浅谈《守望先锋》中的 ECS 构架(5)
时间:2019-01-08 07:03 来源:百度新闻 作者:巧天工 点击:次
ECS要解决的最复杂,最核心的问题,或许还是网络同步。我认为这也是设计一个状态和行为严格分离的框架的主要动机。因为一个好的网络同步系统必须实现预测、有预测就有预测失败的情况,发生后要解决冲突,回滚状态是必须支持的。而状态回滚还包括了只回滚部分状态,而不能简单回滚整个世界。 我在去年其实在本blog中谈过这个问题。我的观点是,状态的单独保存是非常重要的。在ECS模型中,C是纯数据,所以非常方便做快照和回滚。Entity的组件分离,也适合做关键状态的记录。去年和一个同事一起做了一个射击类的MOBA demo,最终的实现方案就是把游戏对象的位置(移动)状态,和射击状态专门抽出来实现预测同步,效果非常不错。 这个演讲其实并没有谈及预测和同步的具体技术,而是谈ECS怎么帮助降低利用这些技术的实现复杂度。同时也提及了一些有趣的细节。 比如说,ECS规定每个需要根据输入表现的System都提供了一个UpdateFixed函数。守望先锋的同步逻辑是基于60fps的,所以这个UpdateFixed函数会每16ms调用一次,专门用于计算这个逻辑帧的状态。服务器会根据玩家延迟,稍微推迟一点时间,比客户端晚一些调用UpdateFixed。在我去年谈同步的blog中也说过,玩家其实不关心各个客户端和服务器是不是时刻上绝对一致(绝对一致是不可能做到的),而关心的是,不同客户端和服务器是不是展现了相同的过程。就像直播电影,不同的位置早点播放和晚点播放,大家看到的内容是一致的就够了,是不是同时在观看并不重要。 但是,游戏和电影不一样的地方是,玩家自己的操作影响了电影的情节。我们需要在服务器仲裁玩家的输入对世界的影响。玩家需要告知服务器的是,我这个操作是在电影开场的几分几秒下达的,服务器按这个时刻,把操作插入到世界的进程中。如果客户端等待服务器回传操作结果那就实在是太卡了,所以客户端要在操作下达后自己模拟后果。如果操作不被打断,其实客户端模拟的结果和服务器仲裁后的结果是一样的,这样服务器在回传后告之客户端过去某个时间点的对象的状态,其实和当初客户端模拟的其实就是一致的,这种情况下,客户端就开开心心继续往前跑就好了。 (责任编辑:波少) |