1.2.2 逻辑与表现分离
在帧同步模式下,客户端的游戏逻辑更新依赖于服务器定期下发的帧命令驱动。对于MOBA类型的游戏,在收到服务器下行帧命令后,客户端立即推进游戏逻辑更新,以保证游戏推进和操作反馈的及时性。而在网络抖动下,客户端接收的帧命令在时间间隔上是不均匀的,游戏逻辑的更新间隔也相应地存在抖动。如果客户端画面完全按照游戏单位的逻辑状态进行渲染,则由于游戏逻辑更新的不均匀,会出现角色位置跳变、抖动、转向和动画卡顿等问题。此外,在这种方式下,客户端提高渲染帧率时也因为受到固定的帧命令广播频率限制,无法有效地提升画面品质。
为此,本节介绍一种适用于帧同步模式的逻辑与表现分离的方案。此方案能够在帧命令更新间隔不均匀的情况下,保证渲染画面的流畅与平滑。
MOBA类游戏需要向玩家呈现视野、阻挡、单位等大量战场信息,通常采用范围较大的第三方鸟瞰视角,画面中的角色模型较小、细节也偏少,玩家对于角色的画面位置、动画、碰撞等信息存在一定的误差容忍度。因此,角色的画面信息展现可以与真实的逻辑状态略有差异,并不影响玩家的战斗打击体验。
因此,此方案下的所有游戏单位均维护两种位置信息—逻辑位置与渲染位置。此处的位置信息不仅包括角色单位的坐标,还包括朝向、动画状态等其他画面展示所需要的信息。
具体而言,逻辑位置由服务器下行帧命令驱动,在接收到服务器下行帧命令时立即由游戏逻辑推进更新;其结果同时也用于游戏逻辑计算,对于所有客户端是完全一致的。渲染位置一般在游戏画面渲染更新时参照渲染的间隔时间及单位的速度、朝向等逻辑运动状态进行计算,计算结果也仅用于本客户端的画面渲染,实质是对逻辑位置的一种插值平滑。
图1.2以角色匀速移动过程为例,展示了单位逻辑位置和渲染位置的更新流程。代表第i次帧逻辑更新后的逻辑位置(),表示固定的逻辑帧更新间隔时间,和分别代表第i次渲染画面更新后的渲染位置和渲染更新间隔()。和分别代表第次逻辑/渲染更新的时刻。圆形和三角形图标则标识了单位各时刻的渲染位置与逻辑位置。
图1.2 逻辑与表现分离的原理
在初始时刻,角色的渲染位置与逻辑位置一致。在第一次画面更新时刻,由于尚未收到服务器的下行帧命令,所以逻辑位置并未发生变化;而渲染位置则按运动公式计算,向前移动了距离。随后,服务器第1帧下行帧命令在时刻送达,客户端立即推进游戏逻辑,使得逻辑位置移动了。在接下来的一段时间,可能由于网络抖动的缘故,客户端未收到帧命令,游戏逻辑未能推进、逻辑位置将保持不变。同时,在时刻,游戏画面正常更新,渲染位置继续前进,两者的差距逐渐拉大。在时刻,客户端收到了第2帧下行帧命令,逻辑位置得以向前推进。到时刻,画面再一次更新,渲染位置和逻辑位置又变得较为接近了。
从客户端渲染更新时间的视角观察单位的位置变化,可以看到,由于网络抖动和渲染更新频率的不匹配,对于较均匀的渲染更新,角色逻辑位置的变化存在明显的抖动和不平滑,但画面呈现的渲染位置则是平滑连续变化的。这样,逻辑位置与表现位置分离的设计极大优化了网络抖动造成的角色位置变化卡顿,也为客户端采用更高的渲染帧率进一步平滑画面表现提供了可能。
除了移动,转向、技能位移等其他位置变化情况,也可用类似的渲染层平滑插值处理来平滑画面显示。此外,为了保证画面显示的准确性,通常需要在渲染位置与逻辑位置偏差过大时,对渲染位置进行额外修正。例如,在渲染位置与逻辑位置间插值得到修正后的渲染位置,降低渲染更新计算使用的移动速度可使渲染位置变动更小,或停止渲染位置的更新甚至直接拉回到角色逻辑位置等。不同类型的游戏应依据自身特性和设计要求合理选取适宜的修正策略。
本方案在实现时进一步分离了表现层和逻辑层的代码。所有画面更新需要的单位额外维护一份自己的表现层对象及相应的计算逻辑,并与逻辑对象对应。表现层仅从逻辑层获取必要的计算数据,而不修改任何逻辑数据和状态。这样,允许表现层考虑网络、玩家操作及其他非逻辑因素实现与逻辑层区别较大的位置计算和修正策略,从而更好地平滑游戏画面表现;同时,也能有效避免游戏不同步的风险。