👬Django框架课—7实现联机对战
2024-5-26
| 2024-6-1
0  |  阅读时长 0 分钟
type
status
date
slug
summary
tags
password
category
Property
Jun 1, 2024 02:10 AM
icon

实现联机对战


✨统一长度单位

由于联机对战的时候,每个用户的客户端长宽不一样,在之前完成的游戏界面里,我们会根据当前客户端的大小,进行渲染
但是在联机对战的时候,应当让所有玩家的游戏界面保持同步才可以,所有,就引入了 统一长度单位 的目标

✨地图渲染

地图 16:9 等比例缩放

实现逻辑:根据当前用户的客户端大小,统一渲染成 16:9的游戏界面,且随着用户调整窗口大小,也动态调整
js/src/playground/zbase.js
js/src/playground/game_map/zbase.js

地图居中

直接把 canvas 元素,用相对位置居中即可
css/game.css

解决地图 resize时,会出现渐变成黑色的情况

原由是因为我们的实现逻辑是:每帧会渲染一层半透明的黑色背景,也就造就了一开始会出现灰屏的情况,解决方法很简单,直接 resize完,强制涂一层不透明的黑色即可
js/src/playground/game_map/zbase.js

✨元素渲染

地图随着尺寸等比例放大缩小的同时,地图内的其他元素也应与背景一同等比例放大缩小,因此,我们只需把元素全部设为相对大小即可,用我们先前设置的playground.scale 值即可

玩家 Player

初始化的时候,转为传递 scale的比例值
js/src/playground/zbase.js
js/src/playground/player/zbase.js

火球 Fireball

js/src/playground/skill/fireball/zbase.js

粒子 particle

js/src/playground/particle/zbase.js

✨增加 “联机对战” 模式

为了区分:用户自己,机器人,联机玩家,需要把 is_me 改成字符串,用以表示不同Player
menu/zbase.js
playground/zbase.js
playground/player/zbase.js

✨配置 django_channels

django_channels 就是基于 wss协议的一种实现。
wssweb-socket (ws)协议的安全模式,支持 C/S 下的双向通信(HTTP协议只支持单向通信)

安装 channels_redis

配置 acapp/asgi.py

固定写法,内容如下:

配置 acapp/settings.py

INSTALLED_APPS 中添加 channels,添加后如下所示:
然后在文件末尾添加:

配置 game/routing.py

这一部分的作用相当于 httpurls
内容如下:

编写 game/consumers

这一部分的作用相当于 httpviews
参考示例:
consumers/multiplayer/index.py

启动 django_channels

~/acapp 目录下执行:

✨建立 WSS 连接

路由 routing

game/routing.py

前端 js

playground/zbase.js
playground/socket/multiplayer/zbase.js

✨编写同步函数

一共需要完成四个通信:
(通信的逻辑基本都是现在本地完成,然后将结果返回给服务器,服务器再分发给其他客户端,达成同步)
  1. create-player :在所有玩家的游戏界面,创建一个新加入的玩家
  1. move-to :在所有玩家的游戏界面,讲一个角色移动到一个位置
  1. shoot-fireball :在所有玩家的游戏界面,让一个角色发射一个火球
  1. attack :在所有玩家的游戏界面,让一个角色被攻击
一场游戏里,所有的元素(玩家,火球等)都需要唯一的标识,来方便同步,为此,我们可以直接修改一下游戏引擎,对于每个元素都创建我们需要的唯一标识
playground/ac-game-object/zbase.js
playground/zbase.js
playground/socket/multiplayer/zbase.js
接着,利用通信的方式,使得每个窗口内,逻辑上相同的元素,其uid 也相同即可
原则是:哪个窗口创建的元素,就用他创建时的 uid作为整个项目运行时的 uid
然后,我们打算用 redis来实现存储每个游戏房间,以及元素,并初始默认设定每个房间上限 3 人

create-player

  • 后端
settings.py
consumers/multiplayer/index.py
  • 前端

✨redis 调试语句

打开 shell 交互
然后用 py3 交互进行 cache 调试
到目前为止,便可以在不同的窗口渲染同一批玩家了

move-to

  • 前端:客户端的通信的发出和接受函数
js/src/playground/
为了让游戏界面中对于要移动的元素做出移动动作,需要对move_to 函数做出一些修改
首先要标识出当前为多人模式,然后模式为多人模式时,每次移动都会触发一次通信
playground/zbase.js
playground/player/zbase.js
  • 后端
consumers/multiplayer/index.py

shoot-fireball

  • 优化一下火球元素
用一个数组来存一个玩家发射的所有火球,以便于子弹消失时,将他们找出并对应删掉
playground/player/zbase.js
playground/skill/fireball/zbase.js
js/src/playground/socket/multiplayer/zbase.js
  • 后端
consumers/multiplayer/index.py

attack

为了只让一个客户端进行攻击命中的判断,因此只有发出方的火球才做碰撞检测
其他客户端对于该火球只有动画效果
又由于碰撞检测是在一台客户端上进行的,因此多端之间可能会存在同步上的延迟
为此的解决方法是:碰撞检测成功时,强制把被击中玩家移动到发起方客户端中的位置,以避免击中延迟上发生的事情
  • 前端
playground/skill/fireball/zbase.js
playground/player/zbase.js
js/src/playground/socket/multiplayer/zbase.js
  • 后端
consumers/multiplayer/index.py

✨游戏的小优化

多人模式下游戏没有开始前,玩家不可以移动

为此我们先引入一个状态机:'waiting' -> 'fighting' -> 'over'来标识当前游戏进行的状态。
然后用一个 notice_board 计分板在前端显示出来,实现的逻辑就是:游戏初始时为 waiting 状态,房间内人数满。 3 人时,才会进入 fighting,角色死亡时为over且发射火球,移动等行为,当且仅当玩家状态为 fighting时,才可以做。
然后设定火球技能的 cd 为 3 秒,且在游戏进入 fighting时,先自动进入 cd 状态。
这样就实现了初始 3 秒内,任何玩家不可攻击。
js/src/playground/notice_board/zbase.js
js/src/playground/zbase.js
js/src/playground/player/zbase.js

技能 CD

给火球技能设置 3s 的 cd,实现逻辑很简单,设定一个 cool_time 变量,每次渲染的时候减去上次渲染的时间间隔
然后 cool_time 为 0 时,技能才可以成功释放
另外修改冷却时间,只用修改自己的即可
js/src/playground/player/zbase.js

用图片来渲染技能 CD

js/src/playground/player/zbase.js

✨添加一个闪现技能

单机部分

js/src/playground/player/zbase.js

联机部分

js/src/playground/socket/multiplayer/zbase.js
consumers/multiplayer/index.py
大功告成 =w=
  • Django
  • Web
  • 算法学习记录SpringBoot 框架课
    Loading...
    目录