本篇主要是提供帧同步主体框架的实现方法以及源码。还有一些坑点的分析。如果对帧同步理论感兴趣的话可以看看这里《帧同步理论篇》。
ps:我的同步框架是在lua里面写的,已经经过了测试没有什么问题即使网络很卡也可以通过调节同步参数保证游戏的流畅。原来的代码里包含了一些项目内部的信息所以就不直接贴出来了。这里只给出核心代码具体的细节大家可以根据项目需求自己扩充。另外我个人这边是用lua写的同步框架,所以贴的也是lua代码哦。
目录
主体架构
如上图所示,整体的架构为:
1.战斗类管理着同步类和其他模块类。
2.各模块使用的数学计算和随机数等使用自定义的浮点数学类。
3.各模块必须实现两个接口即逻辑执行接口和渲染执行接口。
4.lockstep会接管各模块的逻辑接口和渲染接口保证整个战斗在同步下进行。
LockStep
lockstep主要的功能是控制整个游戏的流程,替代unity的update,让游戏所有逻辑和渲染通在lockstep的控制下在规定的时间点执行。
这里采用了几个关键逻辑来划分lockstep流程周期。
操作发送 => 用户操作时立即上报给服务器。
事件帧 => 到达事件帧时向服务器请求缓存的用户操作,并立即执行。[1个事件帧=N个逻辑帧]
逻辑帧 => 每个逻辑帧执行战斗各个模块的逻辑运算接口,如位移伤害等等。[1个逻辑帧=M个渲染帧]
渲染帧 => 每个渲染帧根据上一次逻辑帧时自身缓存的信息和当前逻辑帧的数据做插值后得到渲染帧的数据并执行渲染,如位移旋转的修改。[1个渲染帧=unity自身的最小update间隔]
--累计经过的时间
local accumilateTime
--下一次事件帧时间
local nextKeyTime
--事件帧间隔
local keyLen
--下一次逻辑帧时间
local nextLogicTime
--当前逻辑帧数
local logicNum
-逻辑帧间隔
local logicLen
--dt即为渲染帧间隔(可以和unity保持一致即60帧/s)
function lockStep.Update(dt)
--计算累计经过的时间
accumilateTime = accumilateTime + dt
--累积时间大于关键帧的时候
if accumilateTime >= nextKeyTime then
--*2*.取得缓存的用户操作并处理
--如果缓存没数据了则锁定客户端
if noData then
return
end
--更新下一个事件帧时间
nextKeyTime = nextKeyTime + keyLen
end
--处理逻辑帧(这里while循环是防止某一帧间隔过大跨度了多个逻辑帧的情况)
while(accumilateTime > nextLogicTim