网络游戏的同步能够作的很简单,也能够作的很复杂。简单来讲就是经过Http或者Socket来跟服务器同步数据。而若是往复杂了说,能够有p2p、帧同步、航位预测等等高级课题能够研究。php
由于咱们的项目需求----几百个独立单位的实时同步(带pvp的rts),因此研究了下帧同步。不事后来发现它其实有不少问题,因此具体如何还要看其余同事的研究成果。以我我的来讲,修改游戏方案反而是最合理的解决方案。html
首先从需求上来讲,几百个独立单位的做战,自己结果和士兵强弱从策划的角度来看就是不可控制的。玩家更加不可控制。好比士兵的攻击力增长10%或者弓箭手的射程增长50%,带来的影响多是几倍于预想值。这样一个不可控制的游戏对玩家而言,即使再独特,其吸引力也不如卡牌游戏。 从这点上来讲,项目的需求自己就是值得商榷的。spring
帧同步的原理和实现能够参考这些文章:服务器
http://clintonbrennan.com/2013/12/lockstep-implementation-in-unity3d/网络
http://blog.sina.com.cn/s/blog_674f1bd20101omv7.html数据结构
大意是,游戏运行时以10fps(100毫秒间隔,具体数值可根据实际状况调整)运行一个逻辑帧,逻辑帧负责物理、ai、攻击断定等等。而动画和实际位移由渲染帧负责。这样动画表现是流畅的。而客户端每逻辑帧都会与服务器进行通讯同步客户端的操做,当操做同步完成客户端的逻辑帧能够继续向后模拟。好比运行第3帧要确保第一帧的数据是完整的。双方客户端接收的操做内容是一致的,初始状态是一致的,因此运行的结果也应该是一致的。随机数可使用肯定随机种子的伪随机数来解决。函数
因此关键问题就是要确保客户端以一样的输入能够得到一样的运行结果。 这个是理论上可行的,不少rts游戏也都是基于此原理。好比魔兽争霸3 最高指挥官2 全面战争 星际争霸 帝国时代 等等。 以最高指挥官(Super Commander)为例,其所有单位有上千个,若是要实时同步他们的状态以如今的网络条件都是很困难的,因此这些rts同步的仅仅是操做,即点击了什么位置,点击了什么按钮,选择了什么目标,按了什么按键。客户端接收到对应的操做,进行一样的模拟,达到一样的输出。从而完成网络同步。测试
魔兽争霸的录像机制也是基于此原理,记录操做,而不记录状态。因此几十分钟的游戏,其战报只有几百k。一样由于这个原理,因此在出bug的时候(几率不高,可是玩家多了,仍是很容易碰到的)会形成录像与实际玩的时候不一致。好比玩的时候剑圣暴击杀死了对手,从而翻盘取得了经典的胜利,可是战报播放的时候却没有发生暴击,直接被对方给推了。 全面战争也是如此,因此也会出现战报跟实际游戏不一致的状况,不过几率确实不大,只有发生极限状况才可能出现这样的问题。动画
可是,若是拿Unity实现一个RTS手游,要实现肯定性的模拟就很是困难了。由于Unity中的Start Awake Update等函数的调用是不受控制的,协程、SendMessage、Invoke也是不受控制的,动画事件更加不受控制,物理使用Physic也是不保证肯定性模拟的,即OnTriggerEnter这些函数的调用或者RigidBody的运动均可能存在偏差。一开始只是很是小能够忽略的偏差,而偏差可能逐渐积累最终的蝴蝶效应就是战斗结果彻底不一致。好比一开始只是一个单位的坐标误差了0.1米,可是可能影响到一个箭有没有射中它,进而影响到它究竟死没死,若是单位的死亡产生不一致了,那么后续的战斗就彻底错乱掉了。.net
这个就是帧同步的过程当中的“不一样步”现象。帝国时代和最高指挥官会在每逻辑帧计算当前全部单位的属性的crc值,几个客户端之间比较这个crc值,若是发现不一致,那么就是不一样步现象。此时能够把不一样步的客户端踢出游戏,也能够强制同步某个单位或者是全部单位的状态。产生不一样步现象的缘由可能不少,好比机器卡了一下,网络卡了一下。不管什么缘由,可是确实是出Bug了,悲剧的是,这个Bug是很是难查的。多是使用某个特殊技能形成一个特殊效果的时候,刚好杀死了对方,这种状况下会出Bug。也多是错误的使用了被内存池回收的数据,若是此时此数据已被从新分配出去,那么就会出现Bug,若是没有被从新分配出去,那么能够“正常”的运行。 当游戏越复杂,这种Bug可能越多,而且几乎不可查,由于只有当大量玩家玩的时候才会暴露出这样的问题,QA根本没法重现这个Bug。 即使不是帧同步,“肯定性”模拟,这类Bug都是最让人头疼的,可能会“没法重现”几年,更况且对精确度要求很是高的时候。
实现一个“肯定性”模拟的客户端,其难度很高,而且维护成本很是大。每一个添加的技能都要深思熟虑,而且要花大量的时间去测试。每一个新添加的代码均可能形成不一样步现象,除非战斗部分写好后一百年不动,不然不管是重构仍是添加新功能都会战战兢兢,如履薄冰。
不光是Unity自己的问题,底层和上层都须要作相应的处理。
底层要保证浮点数的“肯定性”,这个自己就是一个高级课题,保证后还要考虑修改后的效率问题,毕竟手游上单位多了,简单ai也会成为大问题,若是浮点数计算的效率低了,极可能会大大的下降运行效率。数据结构如List也可能会有不稳定排序的问题。
上层的ai逻辑也要精心设计,以尽量“准确”的描述来执行行为,好比a单位移动到b点,攻击c,这样的ai执行起来相对可靠。而若是是a追踪b单位,直到x单位进入攻击范围则开始攻击,这个就埋下了很大的隐患,除非全部的计算和调用都是肯定性的。
以手游来讲,以帧同步来实现战斗同步还有一些反作用。好比要保证客户端彻底匹配,不管是配置仍是版本,差一点儿都没有办法一同游戏。因此不管是安装包仍是配置,只要有修改就必需要让玩家更新,不然不能进入战斗。 而不一样设备、不一样cpu,是否会形成不一样的结果,这个不能百分百的确定,也就是说,游戏的兼容性有很大的隐患。
总结一下就是,如今手游上使用帧同步来处理rts并不现实,迄今为止我并无看到成功的例子。 而早期的rts游戏,可能由于游戏相对简单,自研引擎相对可控,再加上大量人力物力的投入,这些跟咱们手游使用Unity快速开发游戏的模式并不相同。 而除开rts,我并不认为其余的游戏形式如ARPG、横版格斗等等须要使用帧同步,正常的行为和状态同步足够了。注意,帧同步的肯定性模拟这个需求是个大难题,并非帧同步自己有多难。也并非说不使用帧同步,客户端就不能本身运行逻辑,进行动做先行或者是预测。
参考资料(这些资料都至关经典,强烈推荐阅读):
1500 Archers on a 28.8: Network Programming in Age of Empires and Beyond
http://www.gamasutra.com/view/feature/3094/1500_archers_on_a_288_network_.php
Syncing System of TA Spring
https://springrts.com/wiki/Syncing_System
Opinion: Synchronous RTS Engines And A Tale of Desyncs
http://www.gamasutra.com/view/news/126022/Opinion_Synchronous_RTS_Engines_And_A_Tale_of_Desyncs.php
SYNCHRONOUS RTS ENGINES 2: SYNC HARDER
http://forrestthewoods.com/synchronous-rts-engines-2-sync-harder/
Cross platform RTS synchronization and floating point indeterminism
http://gamasutra.com/blogs/MaksymHryniv/20150107/233596/Cross_platform_RTS_synchronization_and_floating_point_indeterminism.php
原文:http://blog.csdn.net/langresser_king/article/details/46756393