本文内容
第12章 Gem是什么
第12章 Gem是什么
介绍
本章包括以下主题:
- 什么是 Gem?
- 创建新 Gem
- Gem 的结构
开发 Gem 系统是为了便于在项目之间共享代码。Gem 是模块代码和/或资产的可重用包,可以轻松地添加到 O3DE 项目中或从中删除。
O3DE 引擎是模块化的。这是通过使用 Gem 来实现的。Gem 是代码和资产的集合(或仅是没有任何本机 C++ 代码的资产)。Gem 系统的目的是让开发人员有一个 Gem 集合可供选择,并且能够编写自己的 Gem 以供他们在项目中使用的 Gem。Gem 是包含资产的独立代码段,可以在多个项目中重复使用。
例如,如果要编写一个 Gem 来定位在启动时定位游戏窗口,那么您可以在不同的项目中重复使用此功能,而无需复制粘贴代码。事实上,第 13 章 Gem:设置窗口位置 将编写这样一个 gem!
创建新 Gem
注意:本章的代码可以在 GitHub 上找到,网址为: https://github.com/AMZN-Olex/O3DEBookCode2111/tree/ch12_new_gem
O3DE 有很多宝藏。它们都位于您的 O3DE 安装路径或 GitHub 克隆下。这是我的安装位置:C:\O3DE\21.11.2\Gems。例如,有 EMotionFX、Multiplayer、NvCloth gems 和许多其他 gems。这些是核心 O3DE gem。如果你要编写自己的 gem,我建议把它放在你的项目旁边。到目前为止,我们已经在 C:\git\book\MyProject 创建了一个项目。
一个不错的选择是将我的 Gems 放在 C:\git\book\Gems 下。例如,在本章中,我将创建一个名为 MyGem 的 Gem,并将其放置在 C:\git\book\Gems\MyGem 中。宝石的具体位置完全取决于您。我将向您展示如何配置您的项目,以便从系统上的任何位置查看 gem。
注意:有关创建新 Gem 的官方 O3DE 文档,请访问: https://www.o3de.org/docs/user-guide/programming/gems/
让我们创建一个全新的 gem,看看我们从盒子里得到了什么以及它的整体结构。要创建新的 Gem,我将使用 scripts\o3de.bat 的命令行界面:
C:\O3DE\21.11.2\scripts\o3de.bat create-gem -gp C:\git\book\Gems\MyGem
提示:该脚本足够智能,可以确定游戏的名称应该是 MyGem。但是,您也可以自行指定名称。使用 -h switch 运行命令以查看所有可用选项。
C:\O3DE\21.11.2\scripts\o3de.bat create-gem -h
Gem 名称可以选择使用 -gn 指定。
将 Gem 添加到项目中
您可以使用 O3DE Project Manager 添加和删除 Gem。您可以在 O3DE 安装中找到它,例如:C:\O3DE\21.11.2\bin\Windows\profile\Default\o3de.exe。有关使用 O3DE 用户界面添加和删除 Gem 的官方指南,请访问: https://www.o3de.org/docs/user-guide/project-config/add-remove-gems/
但是,了解幕后发生的事情是有用的。需要修改两个配置文件才能将新 Gem 添加到项目中。
- 第一个文件是位于 C:\git\book\MyProject\project.json 的项目配置文件。
{
"project_name": "MyProject",
"origin": "...",
"license": "...",
"display_name": "MyProject",
"summary": "A short description of MyProject.",
"canonical_tags": [
"Project"
],
"user_tags": [
"MyProject"
],
"icon_path": "preview.png",
"engine": "o3de-sdk",
"external_subdirectories": [
]
}
Property 数组external_subdirectories负责使 Gem 对项目可见。以下示例将 MyGem 的路径添加到项目中。
"external_subdirectories": [
"C:/git/book/Gems/MyGem"
]
现在,如果您在 Visual Studio 中构建ZERO_TARGET,此 Gem 将显示在解决方案中。
注意:这暂时不会启用 gem!现在,项目可以看到 Gem 并将构建,但还剩下一个步骤。
- 第二个文件在项目文件中按其名称启用 Gem: C:\git\book\MyProject\Code\enabled_gems.cmake。
set(ENABLED_GEMS
MyProject
...
MyGem # new
)
MyGem 这个名字从何而来?它来自 Gem 的 json 配置文件“gem_name”属性,位于 C:\git\book\Gems\MyGem\gem.json。
{
"gem_name": "MyGem",
...
}
通过这些更改,新 Gem 将作为项目的一部分进行编译,并将在运行时启用。
提示:您可以通过在 MyGemSystemComponent::Activate 的 C:\git\book\Gems\MyGem\Code\Source\MyGemSystemComponent.cpp 中放置一个断点来确认 Gem 已启用。如果启动 Editor 并命中断点,则表示已成功启用 Gem。
项目在何处列出它使用的 Gem?
我们项目启用的 Gem 的完整列表位于 C:\git\book\MyProject\Code\en abled_gems.cmake 中。
例 12.1.enabled_gems.cmake
set(ENABLED_GEMS
MyProject
Atom
AudioSystem
AWSCore
CameraFramework
DebugDraw
EditorPythonBindings
EMotionFX
GameState
ImGui
LandscapeCanvas
LyShine
Multiplayer
PhysX
PrimitiveAssets
SaveData
ScriptCanvasPhysics
ScriptEvents
StartingPointInput
TextureAtlas
WhiteBox
MyGem # new
)
这些是当您使用默认设置创建项目时启用的默认 Gem。MyProject Gem 是项目 Gem,其中包括位于 C:\git\book\MyProject\Code 中的项目代码。然后是各种核心 O3DE gem 的列表。在本章中,我们只在最后一行添加了 MyGem。
Gem 的文件结构
让我们回顾一下我们在 C:\git\book\Gems\MyGem 中创建的 Gem 的文件结构。
- Assets 文件夹
- Gem 可以为您的项目提供资源。如果有的话,你可以把它们放在这里。这些资源可以是脚本、预制件和其他类型的资源。由于这是一个新的 Gem,因此此文件夹为空。
- Code 文件夹
- 这是 Gem 的 C++ 源代码所在的位置。我们稍后将详细介绍。
- preview.png icon 文件
- 这是 Gem 的默认图标。此图标是 O3DE Project Manager 显示在 Gem 旁边的图标。您可以更改它并根据自己的喜好对其进行自定义。
- CMakeLists.txt 是 Gem 的入口构建文件。我们不需要担心。Gem 的重要构建文件位于 Code 文件夹下的 C:\git\book\Gems\MyGem\Code\CMakeLists.txt。
- gem.json 配置文件。对我们来说,这个文件唯一重要的就是 gem_name 属性下的 gem 名称。
Gem 的 C++ 代码
图 12.1.构建 Gem 的结构
概括地说,Gem 由两个基本构建目标组成:
MyGem.Static 是包含组件的静态库。
MyGem 模块,链接 MyGem.Static 库在 Windows 上创建 C:\git\book\build\bin\profile\MyGem.dll。如果项目启用了此 Gem,则此二进制文件由 Editor、Asset Processor 和游戏启动器加载。
注意:这是 Gem 唯一必需的构建目标。您实际上可以将静态库合并到 gem 模块中,但将组件放入静态库非常有用,因为它也将用于其他一些构建目标。(可选)MyGem.Tests 模块链接到 MyGem.Static,并包含您可能添加的任何单元测试。
(可选)MyGem.Editor.Static、MyGem.Editor.Tests 和 MyGem.Editor 是可选的 如果要构建特定于 Editor 的设计逻辑。本章不会在这里介绍它们,因为它们不是开始使用 O3DE 编写游戏的必要条件。
图 12.2.Gem 代码结构
让我们更深入地研究一下 C:\git\book\Gems\MyGem\Code 中的 scripts/o3de.bat 默认为我们创建的 Gem 的代码结构。
- Include\MyGem 是 Gem 的公共 C++ API 的位置,该 API 应主要由头文件组成,例如事件总线头文件和简单的平面数据结构。
- Platform文件夹包含适用于特定平台 (如 Windows、Linux 等) 的各种构建和源文件。
- Source 文件夹是内部 Gem 代码 (例如自定义组件) 的位置。
- Tests 文件夹包含基本单元测试,供您开始测试 Gem 的代码。
- CMakeLists.txt 是 Gem 的主构建文件。它定义了所有构建目标,例如 Gem 的静态库、Gem 的主模块、单元测试构建目标等。
- mygem_editor_files.cmake、mygem_editor_shared_files.cmake mygem_editor_tests_files.cmake 是特定于 Editor 的构建目标的文件列表,我不会在本章中介绍。
注意:以下是有关 Editor 特定目标的快速摘要。O3DE 允许您将特定于编辑器的逻辑与特定于游戏运行时的代码分开。例如,您可能希望在 Editor 中创建一些设计工具,以保存其输出以供在游戏中使用。在这种情况下,您可能决定将该设计代码与游戏代码分开。然后,设计组件将进入 Editor 构建目标,而最终游戏组件将进入常规组件。但是,这是可选的。首先了解常规非 Editor 构建目标的工作原理非常重要。
- mygem_files.cmake 列出了要进入静态库 MyGem.Static 的文件。
set(FILES
Include/MyGem/MyGemBus.h
Source/MyGemModuleInterface.h
Source/MyGemSystemComponent.cpp
Source/MyGemSystemComponent.h
)
注意:这将列出头文件和源文件。在 Visual Studio 中,它会自动将它们放入不同的过滤器中。
- mygem_shared_files.cmake 列出了特定于构建 MyGem 共享库的文件。
set(FILES
Source/MyGemModule.cpp
)
正如预期的那样,它只包含模块源文件。所有其他组件类将来自静态库 MyGem.Static。
- mygem_tests_files.cmake 是单元测试文件。
set(FILES
Tests/MyGemTest.cpp
)
提示:如果您只添加新组件,则只需担心更新 mygem_files.cmake 以添加新组件文件。其他文件的内容很少会更改
Gem 的公共接口
Project Manager 脚本在 C:\git\book\Gems\MyGem\Code\Include\MyGem\MyGemBus.h 中为我们生成了一个带有 AZ::Interface 的空事件总线。它是 Gem 的公共接口的起点。
注意:AZ::Interface 在第 6 章 什么是 AZ::Interface 中介绍?事件总线是 O3DE 中的唯一系统,有关详细信息,请参阅第 8 章 什么是 AZ::EBus?
您可以在 Gem 中包含任意数量的事件总线。您可以重命名 MyGemBus.h 或将其完全删除。
例 12.2. MyGemBus.h
#pragma once
#include <AzCore/EBus/EBus.h>
#include <AzCore/Interface/Interface.h>
namespace MyGem
{
class MyGemRequests
{
public:
AZ_RTTI(MyGemRequests, "{45ec313a-31a7-41ca-9e19-0f3f9351e328}");
virtual ~MyGemRequests() = default;
// Put your public methods here
};
class MyGemBusTraits
: public AZ::EBusTraits
{
public:
// EBusTraits overrides
static constexpr AZ::EBusHandlerPolicy HandlerPolicy =
AZ::EBusHandlerPolicy::Single;
static constexpr AZ::EBusAddressPolicy AddressPolicy =
AZ::EBusAddressPolicy::Single;
};
using MyGemRequestBus = AZ::EBus<MyGemRequests, MyGemBusTraits>;
using MyGemInterface = AZ::Interface<MyGemRequests>;
} // namespace MyGem
内部 Gem 代码
Gem 的所有内部实现都应该放在 MyGem\Code\Source 下。以下是来自 Gem 模板的文件。
PS C:\git\book\Gems\MyGem\Code\Source> ls -Name
MyGemEditorModule.cpp
MyGemEditorSystemComponent.cpp
MyGemEditorSystemComponent.h
MyGemModule.cpp
MyGemModuleInterface.h
MyGemSystemComponent.cpp
MyGemSystemComponent.h
MyGemEditorModule.cpp、MyGemEditorSystemComponent.cpp 和 MyGemEditorSystemComponent.h 是开始仅为 Editor 模式构建自定义代码的基础知识,出于空间或安全考虑,您不希望将其暴露给游戏运行时。
MyGemModule.cpp 是声明 Gem 的主类。目前,它只注册一个系统组件。
MyGemModuleInterface.h 是 Gem 的 Editor 和 Game 风格的通用基础。它列出了当前向引擎注册的组件。
例 12.3. MyGemModuleInterface
MyGemModuleInterface()
{
m_descriptors.insert(m_descriptors.end(), {
MyGemSystemComponent::CreateDescriptor(),
MyGemSystemComponent 是为您生成的一个空系统组件。Gem 不必具有 system 组件。如果您愿意,您可以删除。
注意:系统组件是在初始化引擎时激活的特殊组件。它不依赖于任何级别,并且会一直持续到游戏启动器或 Editor 退出。它附加到唯一的系统实体。系统组件非常适合处理不依赖于级别的系统范围服务。
如果您重命名其中任何文件或添加新文件,请务必更新 mygem_files.cmake。
图 12.3. mygem_files.cmake
set(FILES
Include/MyGem/MyGemBus.h
Source/MyGemModuleInterface.h
Source/MyGemSystemComponent.cpp
Source/MyGemSystemComponent.h
)
小结
我们已经介绍了 Gem 系统的基础知识,以及当 O3DE Project Manager 脚本为我们创建一个新 Gem 时我们得到什么。在后面的章节中,我们将看一些 gem 的例子。这将使我们能够了解 Gem 的工作原理,以及如何使用它们来帮助您构建游戏代码。
注意:您可以在 GitHub 上找到本章的代码: https://github.com/AMZN-Olex/O3DEBookCode2111/tree/ch12_new_gem