引擎体系结构
设置游戏架构的方法多种多样,从将游戏逻辑与引擎融合在一起的多合一解决方案,到一堆单独的模块,每个模块负责功能的一部分。 Unigine处于这种规模的中间位置,它融合了实现游戏或其他3D应用程序所需的一切,除了应用程序逻辑,网络和AI。 Unigine仅包含典型的游戏逻辑,适用于所有类型的应用程序,并且是有意完成的。
这似乎不是一个优势,因为要创建一个游戏,一个人需要做大量的编程工作,并自己实现所需类型的游戏中广泛使用的通用功能。但是,缺乏特定类型的游戏逻辑并没有那么糟糕,因为它使Unigine成为通用库,可以在不同项目中轻松重用。而且,开发人员不受特定类型的束缚,他们可以一次尝试多种类型,如果使用专用引擎,这将非常困难。例如,很难使用仅为第一人称射击游戏创建的引擎来组合射击游戏和赛车游戏。此外,Unigine允许插入外部模块,这些模块可以包含特定于类型的功能,并且也可以重复使用。这一切使Unigine成为了广泛的3D应用程序的相当灵活的基础。
理解Unigine的体系结构对于开发人员和内容创建者都非常重要。前者将知道他们被允许做的事情,他们可以实现的事情以及对Unigine的期望。后者将了解如何处理其内容。因此,本文简要概述了Unigine工作流程。
下图说明了Unigine内部组件与不同外部实体之间的相互关系。
当自定义应用程序逻辑调用Unigine API函数时,一切开始。可以使用 UnigineScript 或直接使用C / C ++进行这些调用。前一种是更可取的方式,因为在这种情况下,程序员不必考虑多线程和内存管理。另外,如果应用程序是用UnigineScript编写的,它将在Unigine支持的每个平台上运行。如果应用程序逻辑要求,API组件会加载模块来扩展Unigine功能。此类模块可能包含例如第三方中间件。
API调用传递给解释器,该解释器初始化所需的资源:注册扩展,加载核心数据,配置文件,脚本和用户界面文件。由于所有这些资源都组织在一个特殊的数据目录中,并且可以进行打包,因此它们通过文件系统组件进行加载。另外,文件系统组件跟踪文件的字节序。请注意,如果在初始化完成后将文件添加到该目录,则需要重新加载文件系统组件。
初始化后,世界经理开始起作用。它加载构建当前场景所需的文件,并确定可见节点集,然后将其发送到 render 组件。世界经理还告诉声音组件,何时以及如何播放环境声音,哪些声音源放置在世界上某个地方并具有空间特性。当然,世界经理与 physics 组件合作,该组件执行物理计算(碰撞检测,关节解算,流体浮力等),并可能更新节点层次结构。简而言之,世界经理不会自己绘制物体,播放声音或执行物理计算。而是将这些任务委托给指定的组件。
渲染和声音组件需要其他资源才能完成其任务:渲染组件需要纹理,网格和动画,声音组件需要声音。因此,他们要求资源管理器提供所需的信息。资源管理器的任务是加载所需的图形和声音,对其进行缓存,并在不再需要它们时将其卸载。资源管理器的存在使游戏开发人员不必考虑应该如何以及何时加载和卸载数据。
如果应用程序逻辑需要,解释器还可以调用 GUI 组件,并使其通过render组件绘制用户界面。在Unigine中,GUI对象不仅可以是独立的,而且可以是显示的虚拟世界的一部分。在后一种情况下,它们由世界经理像其他节点一样进行管理。
当显示可能包含GUI的渲染图像时,用户当然会开始与世界互动。用户可以通过各种输入设备来影响世界。这些设备的输入被发送到GUI组件和 controls 组件。 GUI组件处理输入,检测单击的元素并执行相应的回调函数。控件组件处理与GUI不相关的输入,例如游戏中玩家的动作。请注意,GUI组件始终在控件组件之前获取输入数据,因此具有更高的优先级。
处理后的输入传递到解释器,解释器检测用户动作是否影响渲染或物理设置等。如果是,则解释器要求相应的组件更新图像或计算。如果用户输入改变了世界,世界管理器将更新可见节点集并将新请求发送到指定的组件。
循环重复执行这些操作,直到用户退出应用程序为止。