现在的服务端框架有支撑数万玩家的能力,且支持横向拓展(即 增加物理机数量),理论上具有无上限的负载能力。下面以《球球大 作战》为例,说明怎样使用这套框架。
1、战斗流程
玩家登录后,玩家可以做些非战斗操作(仿照work示例,可以实现 成就、背包、邮件、好友等功能),如下图所示:
当点击“开始比赛”按钮时,客户端会发生“进入战斗”的协议。战斗流程如下图所示:
服务端会开启很多scene 服务,每个服务处理一场战斗。收到“
进入战斗”
的协议后,
agent
会随机选择一个战斗服务。进入战斗后,agent
会与某个
scene
服关联。注意图中的虚线方框,不同方框里的服务可能位于不同节点,理论上scene服务可以部署在任意节点上,这增加了服务端的扩展能力。
2、游戏玩法
我们简化一下
《球球大作战》的玩法。如下图所示:
战场中包含球和食物这两种对象,每个玩家控制一个球,其中黑 色小圆代表食物。当玩家进入战斗时,场景中会添加一个代表玩家的小球,它出生在随机的位置上,默认是很小尺寸(半径)。玩家可以 控制球移动的速度,比如设置为(1,0)会一直向右走,直到设置为
(
0, 0
)才停下来。场景中会随机生成一些食物,遍布各处,当小球碰 (吃)到食物时,食物消失,球的尺寸增长。
3、战斗协议
《球球大作战》的战斗流程涉及如下几条协议:
(1)进入战场协议
当玩家点击“
开始比赛
”
按钮时,客户端发送
enter
协议(见下图
),服务端会做出能不能进入战斗的判定,并且将
agent
和某个
scene 关联起来。
- 如果成功进入战场,服务端会回应成功信息,且向同战场的其他玩家广播有人进入的消息。广播的消息包含三个参数,分别是刚进入的玩家id、它的坐标和尺寸。
-
如果进入失败,例如玩家已经在战斗中,会回应失败信息,如 “ 您已在战场中,不能重复进入” 。
(2)战场信息协议
进入战场后,客户端需要显示战场中的球和食物。服务端会发送balllist和
foodlist
协议,如下图所示:
以balllist为例,它依次包含了各个球的信息,每个球包含4个参数,分别是玩家id、x坐标、y坐 标和尺寸。 服务端生成食物时,会给每个食物一个唯一id。在食物信息协议 foodlist中每个食物会包含id、x坐标、y坐标这3个参数。
(3)生成食物协议
战场会随机生成一些食物。服务端会广播addfood
协议(如下图所示),此协议包含新生成食物的id、
x
坐标、
y
坐标。
(4)移动协议
当需要改变移动方向时,客户端会发送shift
协议(如下图所示
),设置小球的x
方向速度和
y
方向速度。
所有游戏逻辑由服务端判定。每当小球的位置发生变化时(每隔一小段时间),服务端就会广播move协议(见下图),更新小球的坐标。move协议是发送频率最高的协议,假设服务端每0.2秒更新一次 小球位置,战场上有10个小球,那么每个客户端每秒将收到50条move协议。
说明:每个客户端每秒将收到50条move协议,这个频率非常高,但有不少优化方法,比如可以将多个小球的位置信息合并成一条 协议或使用AOI算法做优化(后面会提到)。
(5)吃食物协议
当小球吞下食物时,服务端会广播eat
协议(见下图
),此协议的参数包含玩家id
、被吃掉的食物
id
和玩家的新尺寸
(6)离开协议
当玩家掉线时(离开战场),服务端会广播leave
协议(如下图
所示),告诉战场中每一位玩家,有人离开了。
完整的《球球大作战》还包含玩家间的碰撞、球分裂、排行榜等 功能。这些功能不算复杂,写法和“
生成食物
”“
吞下小球
”
很相似,大家有时间可以自行实现。