引擎体系结构
设置游戏架构的方法多种多样,从将游戏逻辑与引擎融合在一起的多合一解决方案,到一堆单独的模块,每个模块负责功能的一部分。 Unigine处于这种规模的中间位置,它融合了实现游戏或其他3D应用程序所需的一切,除了应用程序逻辑,网络和AI。 Unigine仅包含典型的游戏逻辑,适用于所有类型的应用程序,并且是有意完成的。
这似乎不是一个优势,因为要创建一个游戏,一个人需要做大量的编程工作,并自己实现所需类型的游戏中广泛使用的通用功能。但是,缺乏特定类型的游戏逻辑并没有那么糟糕,因为它使Unigine成为通用库,可以在不同项目中轻松重用。而且,开发人员不受特定类型的束缚,他们可以一次尝试多种类型,如果使用专用引擎,这将非常困难。例如,很难使用仅为第一人称射击游戏创建的引擎来组合射击游戏和赛车游戏。此外,Unigine允许插入外部模块,这些模块可以包含特定于类型的功能,并且也可以重复使用。这一切使Unigine成为了广泛的3D应用程序的相当灵活的基础。
理解Unigine的体系结构对于开发人员和内容创建者都非常重要。前者将知道他们被允许做的事情,他们可以实现的事情以及对Unigine的期望。后者将了解如何处理其内容。因此,本文简要概述了Unigine工作流程。
下图说明了Unigine内部组件与不同外部实体之间的相互关系。
当自定义 应用程序 调用 UNIGINE C++ API 函数时,一切都开始了。 这些调用是使用 C++/C# 完成的。 C++ 应用程序 直接调用API 的函数。 C# 应用程序 使用 C# Wrapper (UnigineSharp.dll),而后者又使用 C Wrapper (UnigineWrapper.dll, UnigineWrapper.so) 与 UNIGINE API 交互。
应用程序逻辑可以直接在 AppWorldLogic, AppSystemLogic 和 AppEditorLogic 类或通过一组组件 使用 API 中包含的 组件系统。
应用程序功能可以通过引擎插件进行扩展。 UNIGINE 提供了一组即用型插件,但是,您可以实现自定义插件。 您还可以实现自定义 Editor Plugins,以扩展 UNIGINE Editor 的功能。
API 调用被传递给 Engine,它初始化所需的资源:注册扩展、加载核心数据、配置文件、用户界面文件、插件目录。 由于所有这些资源都组织在一个特殊的数据目录中,而且可以打包,它们是通过文件系统加载的。 此外,文件系统跟踪文件的字节顺序。 注意,如果在初始化完成后向该目录添加文件,则需要重新加载文件系统组件。
- App 管理 主循环 并控制图形上下文(管理控件的事件,更新窗口参数)。
- Render 渲染场景。 它需要额外的资源来完成其任务:纹理、网格和动画。 所需的图形资源从文件系统传递给渲染器。
- World 加载构建当前场景所需的文件,并确定可见节点集,稍后将其发送到 Render。 World 还告诉 Sound,何时以及如何播放环境声音,哪些源放置在世界某处并具有空间属性。 World 与 Physics 合作,后者执行物理计算(碰撞检测、关节求解、流体浮力等)。 简而言之,世界不会自行绘制对象、播放声音或执行物理计算。 相反,它将这些任务委托给相应的子系统。
- Game 将完成最后一帧所用的时间(以秒为单位)传递给 World(按需)。 World 根据接收到的值进行更新。
- Physics控制World中的物理模拟。
- Input (Controls)处理来自Input Devices的输入并传递反馈。如果需要,应用程序可以读取并以某种方式处理获得的输入。
- Materials和Properties管理材料和属性。它们是从File System加载的。
- Sounds从File System接收声音,并将它们传递给Sound Card播放。
- GUI绘制用户界面。在UNIGINE中,GUI对象既可以是独立的,也可以是显示的虚拟世界的一部分。在后一种情况下,它们像其他节点一样由 World管理。当呈现的图像(可能包含GUI)显示出来时,用户开始与世界进行交互。用户可以通过各种输入设备来影响世界。来自这些设备的输入被发送到GUI和Controls。GUI处理输入,检测单击的元素,并执行相应的回调函数。Controls子系统处理与GUI无关的输入,例如玩家在游戏中的操作。注意,GUI总是在Controls之前获得输入数据,因此具有更高的优先级。