本节内容是通过 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学习笔记-实现聊天系统。