本节内容是通过 Django Channels 框架使用 WebSocket 协议实现多人模式中的同步移动,攻击以及被击中判定函数。
此外实现房间内玩家数提示板、技能冷却时间以及闪现技能。
1. 编写移动同步函数move_to
与上一章中的 create_player 同步函数相似,移动函数的同步也需要在前端实现 send_move_to 和 receive_move_to 函数。我们修改 MultiPlayerSocket 类(在目录 ~/djangoapp/game/static/js/src/playground/socket/multiplayer 中):
1 | class MultiPlayerSocket { |
然后修改一下后端通信代码(~/djangoapp/game/consumers/multiplayer 目录中的 index.py 文件):
1 | from channels.generic.websocket import AsyncWebsocketConsumer |
最后我们还需要调用函数,首先我们需要在 AcGamePlayground 类中记录下游戏模式 mode:
1 | class AcGamePlayground { |
然后在 Player 类中进行修改,当为多人模式时,需要广播发送 move_to 信号:
1 | class Player extends AcGameObject { |
现在即可实现多名玩家的同步移动。当 A 窗口中的玩家移动时,首先该窗口(Player 类)的监听函数会控制该玩家自身进行移动,接着判定为多人模式,因此再调用 MultiPlayerSocket 类中的 send_move_to 函数向服务器发送信息(通过 WebSocket 向服务器发送一个事件),接着服务器端(~/djangoapp/game/consumers/multiplayer/index.py 文件中)的 receive 函数会接收到信息,发现事件 event 为 move_to,就会调用 move_to 函数,该函数会向这个房间中的其他所有玩家群发消息,每个窗口都会在前端(MultiPlayerSocket 类中)的 receive 函数接收到信息,通过事件路由到 receive_move_to 函数,该函数就会通过 uuid 调用每名玩家的 move_to 函数。
2. 编写攻击同步函数shoot_fireball
由于发射的火球是会消失的,因此需要先将每名玩家发射的火球存下来,此外我们实现一个根据火球的 uuid 删除火球的函数,在 Player 类中进行修改:
1 | class Player extends AcGameObject { |
由于火球在 Player 中存了一份,因此我们在删除火球前需要将它从 Player 的 fire_balls 中删掉。且由于 FireBall 类中的 update 函数过于臃肿,可以先将其分成 update_move 以及 update_attack,我们修改 FireBall 类:
1 | class FireBall extends AcGameObject { |
然后我们在 MultiPlayerSocket 类中实现 send_shoot_fireball 和 receive_shoot_fireball 函数:
1 | class MultiPlayerSocket { |
现在我们需要实现后端函数:
1 | import json |
最后是在 Player 类中调用函数:
1 | class Player extends AcGameObject { |
3. 编写击中判定同步函数attack
我们需要统一攻击这个动作,由一个窗口来唯一判断是否击中,若击中则广播给其他窗口,因此窗口中看到其他玩家发射的火球仅为动画,不应该有击中判定。我们先在 FireBall 类中进行修改:
1 | class FireBall extends AcGameObject { |
每名玩家还需要有一个函数 receive_attack 表示接收到被攻击的信息:
1 | class Player extends AcGameObject { |
我们假设发射火球的玩家为 attacker,被击中的玩家为 attackee,被击中者的位置也是由攻击者的窗口决定的,且火球在击中其他玩家后在其他玩家的窗口也应该消失,因此还需要传火球的 uuid。我们在 MultiPlayerSocket 类中实现 send_attack 与 receive_attack 函数:
1 | class MultiPlayerSocket { |
然后实现后端函数如下:
1 | import json |
最后需要在火球 FireBall 类中调用攻击判定的同步函数:
1 | class FireBall extends AcGameObject { |
4. 优化改进(玩家提示板、技能CD)
我们限制在房间人数还没到3个时玩家不能移动,需要在 AcGamePlayground 类中添加一个状态机 state,一共有三种状态:waiting、fighting、over,且每个窗口的状态是独立的,提示板会在之后进行实现:
1 | class AcGamePlayground { |
接下来我们实现一个提示板,显示当前房间有多少名玩家在等待,在 ~/djangoapp/game/static/js/src/playground 目录下新建 notice_board 目录,然后进入该目录创建 zbase.js 文件如下:
1 | class NoticeBoard extends AcGameObject { |
每次有玩家创建时就将 player_count 的数量加一,当玩家数量大于等于3时将游戏状态转换成 Fighting,且设置除了在 Fighting 状态下点击鼠标或按下按键才有效果,否则无效。在 Player 类中进行修改:
1 | class Player extends AcGameObject { |
现在对局一开始就能攻击,显然不太合适,因此还需要设定在游戏刚开始的前若干秒无法攻击,即技能冷却。每个窗口只有自己才有技能冷却,也就是只能看到自己的冷却时间。现在我们给火球技能设置一秒的冷却时间,在 Player 类中进行修改:
1 | class Player extends AcGameObject { |
我们还不知道技能什么时候冷却好,因此还需要加上一个技能图标与 CD 提示,可以模仿其他 MOBA 类游戏,在技能图标上添加一层 CD 涂层即可。假设我们的技能图标资源存放在 ~/djangoapp/game/static/image/playground 目录下,那么我们在 Player 类中渲染技能图标:
1 | class Player extends AcGameObject { |
5. 闪现技能
闪现技能的实现很简单,整体参考之前的火球技能即可,我们先实现单机模式下的闪现技能,在 Player 类中实现:
1 | class Player extends AcGameObject { |
然后我们还需要将闪现技能在多人模式中进行同步,原理和移动的同步是一样的,先在 MultiPlayerSocket 类中实现前端函数:
1 | class MultiPlayerSocket { |
然后实现一下后端,在 ~/djangoapp/game/consumers/multiplayer/index.py 文件中实现:
1 | import json |
最后在 Player 类中调用一下广播闪现技能的函数即可:
1 | class Player extends AcGameObject { |
上一章:Django学习笔记-实现联机对战(上)。
下一章:Django学习笔记-实现聊天系统。