TPS游戏《逃学派对》与《WildTank》开发纪录

先来《WildTank》,吃鸡类射击游戏demo
客户端:Unity
服务器:Python
数据库:MySql

先讲客户端
SFrameworkDemo-TPS
由于还是基于框架开发,所以基本的像 游戏循环,场景状态机,UI框架,日志系统 都是完备的
要做的其实只是 角色Prefab+动画状态机、输入Controller(如地面移动、跳跃、瞄准、射击等),UI、武器、子弹和镜头等
包括第二个控制器(Tank)以及敌人角色(AI)的制作

另外,客户端其实也要放对应的Network处理部分(这里可以参考Unity3D网络游戏编程实战开发)

再讲服务端
PyGameServer
文件结构,主要代码文件在Core和Logic文件夹下
最下面的SocketServer文件夹是一个最简范例(收发注册/登录消息)
Sockets里其实是提供了一些预设服务器,如聊天服、文件传输服等,这些详细可在服务器相关笔记中找到
System封装Utility,Navigation是实现服务端A*寻路,DataMgr与数据库交互,Connection进行连接(基于socketserver),然后协议包用HandleMsg处理

建立连接、心跳检测、粘包分包、事件分发、关闭连接

……好像更详细的资料丢失了,最终版本的源码没有被保存下来,手头只有初版的

再来[2021GameJam]《逃学派对》
战地5

"爷青回"主题游戏
演示视频:好像存在本地?网上只有网易内网有了
游戏源码:GitHub




附:
Python服务器范例 源码剖析
启动Server:
SimpleServer.tick→simpleHost.process→simpleHost.handleNewClient→assign给client(client是netStream,用process处理消息,process被updateClients调用)

收发消息:
netStream的send应该是给client发消息(被sendClient调用)

updateClients中:收消息(源自netStream的recv) -》 read 拿到消息 同时也做心跳检测
read拿到的是一个元组:self.queue.append((conf.NET_CONNECTION_DATA, client.hid, data))
(1,hid,'')是连接断开消息

sendClient:发消息 《- netStream的__trySend……

netStream:
connect还有except错误码处理,很强

消息协议
head为4字节的length信息,使用小端。然后2个字节是sid+cid

消息分发
conf中定义消息类型,msg类存放sid+cid,header类存放反序列化后的对象,service类中存放你要执行的方法,由dispatch找到并执行,然后在方法中将owner找到对应的header将数据解包使用。
因此执行:Server->Host->Dispatcher->Service->Header->Function
如果消息不符合协议,打个log抛弃

装包拆包
server这边,由data经 自定义的对应的Event(SimpleHeader)来unmarshal得到数据。定义head对象 marshal 转为data发送
client这边,用IO.BinaryWritter装包发送,BinaryReader解包 读取数据

Header处理示例
bfmt = 'I%dsI%ds'
for i in xrange(x): # i=0
end = fmt.index('%', begin) #end=1
elen = elen + struct.calcsize(self.BYTES_ORDER + fmt[begin:end]) #elen=4, offset=4
s = struct.unpack(self.BYTES_ORDER + self.lenFormat, raw[elen - self.offset:elen])[0] #
elen = elen + s # s=取得数字(如5),即length, elen=8
lst.append(s) #
begin = end + len('%ds') # begin=1+3=4
之所以要用I%ds的形式,是因为无法直接确定I的值,所以要先确定I的值,来替换掉%d,如获得5s这个format,从而unpack

发送过去的数据:
PyCharm中的显示:
但是,上面的长度在pycharm中是18+4,而c#中是18
找到原因了,两边协议不一样,他的写法是length包括自身4字节的长度信息,我的是不包括。现在统一改成不包括

服务器架构
GameServer,服务器启动
DataMgr,数据库交互部分
Logic,逻辑部分,下分几个文件对应不同逻辑
还可分登录和战斗部分
Gate服务器是用来分发的。客户端往往首先向gate服务器发出请求,gate会给客户端分配具体的connector服务器。具体的分配策略一般是根据客户端的某一个key做hash得到connector的id,这样就可以实现各个connector服务器的负载均衡。

位置同步
本机不需要同步,只需要校验,和上次位置差值是否过大
其他机器,接收到的是本机目前所处的位置,再根据其上一次的位置,以预定的速度移动过去

AI&寻路-可能会遇到的问题,需要想解决方法
有种办法是服务端做大体寻路,客户端做精细寻路
如果是多人联机,服务端发信息交给客户端寻路的话,可能会因为位置的略微差别,或者延迟,导致两个客户端寻路路径不一样
可以选择使用一个客户端的数据,广播到全体。也可以选择服务端做寻路

注意
  1. 看CPU占用率
  2. 网络层接口一定要封装起来,上层看不到
  3. 伤害计算要放服务端,但是攻击判定服务端只做校验,因为不好计算
  4. 消息传输要加密,数据库也要考虑加密
  5. 下线再上,如果还是同一局游戏,要把客户端数据恢复……也就要求服务端存放场景数据,暂时做不了了。下线再上不能再进入游戏



comments powered by Disqus