技术概述 - scutrobotlab/RM2021_simulation GitHub Wiki

模拟器开发使用的技术栈主要包括游戏引擎、网络同步方案、实时通讯方案和支持软件的技术方案。

游戏引擎

当下,游戏引擎的选择有很多。主流引擎选择包括 Unity、Unreal、Godot、Cocos 等。引擎可选用的开发方式也各不相同,典型的有 C#、C++、Typescript、自研脚本等语言的程序化开发,和以 Bolt、蓝图为代表的图形化开发两种。各引擎在素材处理、图形渲染、配置要求、跨平台支持等方面各有特色。经过综合考量,我们最终选用了 Unity 引擎进行 2021 赛季模拟器开发,下面会对几种主流引擎做简单介绍,以供后续选型参考。

Unity引擎,最初只是一个用于支持网页 3D 的小插件。后来由于其较低的入门门槛,良好的跨平台支持受到移动端开发者青睐,逐渐发展成为完整的三维创作工具。Unity 引擎的主要开发方式是 C# 脚本编程,同时提供了 Bolt 图形化编程支持(对标 Unreal 蓝图)。Unity 能很好的兼容各种格式导入数据,模型、图像、音频等资源基本不会遇到导入问题。Unity 采用开源的 PhysX 物理引擎进行物理模拟,有很快的模拟速度和可以接受的物理精度。图形渲染方面,Unity 引擎提供了多种渲染管线供选择:内置渲染管线速度快、可定制性低、效果一般。通用渲染管线有一定可定制性、渲染效果在各平台都可圈可点。HDRP 渲染管线面向高端设备,提供最好的图形效果,但对美工、技术美工的要求都高一个档次。

Unreal 引擎,目前已经迭代到第五代试用版,向来以极高的写实渲染水平著称。Unreal 引擎的主要开发方式是 C++ 脚本编程,同时提供了非常强大的图形化编程方式:蓝图。Unreal 的学习和使用门槛都比较高。物理模拟方面,Unreal 有自己的 Chaos 物理系统,可以模拟包括破碎在内的逼真物理效果。Unreal V 版本中更是引入了新的网格和光照系统,适应极高面数模型导入,和实时(免烘培)全局光照效果,非常惊艳。图形渲染独孤求败水平,但是对开发人员、美工、技术美工、以及开发电脑配置都有较高的要求。

Godot 引擎,近几年出现的开源游戏引擎,曾经被一个 RM 战队用于 RMUL 模拟器的制作。使用自创的脚本进行逻辑编写,非常轻量级,图形效果、跨平台特性等还可以接受。具体实践经验较少,不予评价。但由于是新生项目,在生态方面无法与上述两个老大相匹敌。

Cocos 引擎,被许多厂商用于手机游戏开发,近年也推出了面向三维作品开发的功能,但在设计上和体量上都不够合适。

网络同步

技术选项的第二点,是网络同步方案选型,主要以 Unity 引擎举例。网络同步,是联机游戏的重要部分。目前主流的同步方案可以根据底层协议分为两种:基于 TCP 的方案和基于 UDP 的方案。基于 TCP 的同步方案依赖于长连接特性,可以与服务端做长时间、数据保证一致的通信。此类方案主要用于 MMORPG 类网游,可以承载很高的连接数量,但在更新帧率上会收到校验重传的限制,为数据一致性牺牲了同步效率。

基于 UDP 的方案主要应用于高实时性游戏,比如 MOBA、FPS 类游戏。这种游戏要求极低的同步延迟(主要是操作同步延迟),0.5 秒的滞后都可能对游戏进程造成很大影响。基于 UDP 的协议可以保持稳定的同步帧率。利用预测插值、打包同步等技术,此类协议可以保证在有丢包的网络环境下维持可以接受的一致性。

在以上的分类中,网络同步又可以细分为操作同步(经常称为帧同步)和状态同步。操作同步,顾名思义,同步的内容是玩家的操作,比如按下键盘,点击鼠标等。操作数据被发送到服务端,再转发到其他客户端。只要时间轴上的操作一致,就可以保证所有客户端模拟的最终结果一直。操作同步的优点在于同步数据量小,记录数据量小,其缺点在于一致性较难保证,需要额外的技术加持。状态同步,其同步内容是全局的游戏状态,即每一帧都向每一个玩家同步所有物体的位置、旋转、物理模拟等数据。此类同步的优点是强数据一致性,但也带来了数据流量大的问题。状态同步往往需要与预测插值、变速重放等技术共同使用。

除了这些大分类,实践中的网络同步又延伸出了各种不同版本。在开发过程中,可以融合不同方式的优势,来设计最合适的网络同步方式。

代码组织

参照上面不同的网络同步方式,已经有很多成熟的网络框架可供使用。不同的框架有不同的代码组织方式,以下对常见的两种做简要介绍。

客户端——服务器模式。此模式比较符合人们对传统网络应用的认识。应用分为客户端和服务器两部分。首先由客户端发起连接,服务器新建线程进行响应。响应结束后,客户端断开连接。在此模型中,客户端与服务器有清晰的任务划分,两部分逻辑合起来组成完整的游戏逻辑。客户端与服务器分别拥有自己的代码库,并视情况抽取一部分核心逻辑,作为公用代码库。

混合模式。这种模式主要在游戏编程中出现,其特点是游戏服务端与客户端共用一套代码,在代码中使用注解等特性区分客户端与服务端逻辑。这种模式的优点是开发迅速,不用重复编写逻辑,调用直观。在复杂数据同步方面,借助框架特性,节省了大量胶水代码,开发者可以专注于逻辑编写。2021 赛季模拟器采用的 Mirror 框架即采用此种模式。

更多技术

上述内容之外,还有一些可供参考的选型方向。

实时通讯方案,模拟器中可能用到的实时通讯主要有两种:文字通讯和语音通讯。利用网络框架的基本功能,实现一个简单的文字实时通讯系统并不难。但更好的思路是采用完整的实时通讯解决方案。以 Vivox 为例,其为小规模应用开发者提供绰绰有余的通讯套餐,其中功能包括基于频道的通讯、禁言、登录登出等,并涵盖了文本与语音通讯。此类方案一般会提供与主流引擎快速集成的方式,直接调库即可。

支持软件,除了模拟器本体,模拟器的实际使用还需要支持软件的配合。一个很好的例子是服务器网页控制台,让队员无需启动模拟器就可以了解到服务器目前的运行情况,有哪些队员在训练,分别选择什么角色等。其他支持软件还包括外挂的决策系统,服务启动器等。模拟器本体与支持软件间的 IPC 往往需要使用 protobuf、grpc 等协议,可能基于 websocket 等协议。具体技术选型视用例而定。

ECS,对象组件系统,是近年兴起的一种游戏架构模式,通过对游戏内所有元素进行合理抽象,使数据在内存中规则排列,统一处理,以最大化利用硬件资源。这种模式非常适用于有大量实体并行模拟需求的项目。但由于需要在硬件角度对数据进行抽象,采用 ECS 需要对系统有完整的设计,对于需要中途更改需求的模拟器项目是否合适有待研究。Unity 引擎针对 ECS 模式推出了一套新的软件栈 DOTS,包括 ECS 系统实现,新的网络同步框架等。

单元测试,在模拟器开发过程中,经常需要验证实现是否正确。如果每次调试都从头启动模拟器,设置联机环境,复现特定的情况,会非常浪费时间。最规范的验证方式应该是在开发时就划分单元,并设计单元测试。每个游戏引擎都有许多可选的单元测试方案,编写测试应该在设计阶段就纳入考虑范畴。

音频渲染,虽然模拟器在视觉上比在听觉上有更高的效果要求,但考虑到后续功能设计的多样性,更好的音频渲染依然应该纳入考虑。Unity 引擎内置的声音系统可以渲染立体音频,模拟声音混合等,但依然不够写实。现实中的声音存在穿透、反射、混响等现象。要更进一步模拟声音的真实传播,一种可能的技术选项是 Steam Audio SDK,其包含高级的音频渲染核心与各大引擎的接入方案。

构建系统,如果采用混合模式网络编程,就会经常需要同时构建两个版本的程序:构建模拟器本体,在构建设置中勾选 Server Build 再构建服务器程序。由于能跑 Windows Server 的服务器更贵,如果想用 Linux 跑服务端,可能还需要改变服务端构建平台。这样的流程非常耗费时间,是可以采用自动化方案替代的。在后续模拟器设计中,如果有更多功能设计,可能还需要构建移动端版本模拟器,对多版本同时构建的需求就更加强烈。一种可能的技术选择是 Super unity build,在设置构建选项之后,可以同时对多个构建目标进行打包。

构建系统拓展:还可以利用 Drone 等方案实现 CI,Nightly build。