UE 插件开发流程

发布于 2022-07-29  701 次阅读


1. 新建个空工程:

进入时因为选择了 C++ 工程,所以会自动打开 Visual Studio,笔者这里使用 Rider,二者开发流程一致,读者可以不必在意。

2. 目录结构

C++ 工程打开后,目录结构如下

Engine 为引擎所在目录,Games为游戏项目目录。

IDE 中并未显示出所有的文件,右键选择在文件管理器中打开,可以看到全部的文件:

有些子目录在引擎和工程的目录中都存在:

  • Binaries - 包含了编译过程中产生的所有可执行文件或其他文件。
  • Build -包含了编译引擎或游戏所需的文件,包括创建针对特定平台的版本所需的文件。
  • Config -包含了用于设置控制引擎行为的值的配置文件。 在游戏项目的Confige目录文件中设置的值将覆盖在Engine\Config目录设置的值。
  • Content - 存放引擎或游戏的内容,包括资源包及地图。
  • DerivedDataCache - 包含了为引用的内容而生成的衍生数据文件。 如果引用内容没有可用的缓存文件,则会极大增加载入时间。
  • Intermediate - 包含了在编译引擎或游戏时生成的临时文件。 在游戏目录中, Shaders 存储在 Intermediate 目录下。
  • Saved - 包含了自动保存内容,配置 (*.ini)文件以及日志文件。 另外, Engine > Saved 目录包含了崩溃日志,硬件信息以及Unreal Swarm的选项及数据。
  • Source - 存放了引擎或游戏的所有源文件,包括引擎源码、工具、游戏性类等。
    • Engine - Engine目录中源码文件分为以下几类:
    • Developer -编辑器和引擎都使用的文件。
      • Editor -仅编辑器使用的文件。
      • Programs -引擎或编辑器使用的外部工具。
      • Runtime - 仅引擎使用的文件。
    • Game -游戏项目中的源码文件按模块分类;一个模块一个目录。 每个模块包含以下信息:
      1. Classes -包含了所有游戏性类的头文件 (.h) 文件。
      2. Private -包含所有 .cpp 文件,包括游戏性类的实现文件及模块的实现文件。
      3. Public - 包含了模块的头文件。
      4. 某些子目录是引擎目录专有的。

某些子目录是引擎目录专有的:

  • Documentation -包含了引擎文档,既包含了源码件也包含了已发布的文件。
    • HTML - 已发布的HTML文件。
    • Source -markdown源码文件。
  • Extras -额外的辅助功能和工具文件。
  • Plugins - 包含了引擎中用到的插件。
  • Programs -包含了UE4根目录中存储的项目配置文件和日志文件以及其它诸如UnrealFrontend和UnrealHeaderTool的虚幻程序。
  • Shaders - 存放了引擎的着色器源码文件 (.usf)。
3. 新建插件

UE 打开后的界面如图,我们选择 Edit -> Plugins

在弹出的窗口中选择 add

此时出现如下界面,这里有一些可供选择的条目,其为 UE 预设好的几种模板

常用的主要有四种:

  1. Blank
    空白模板,最简洁的结构,只有模块类和加载卸载函数,一张白纸最好作画了。
  2. Blueprint Library
    蓝图功能库模板,都是静态函数,提供给蓝图直接调用的,如果只是单一的功能集的话,用此模板最快捷
  3. Editor Toolbar Button
    编辑器工具栏按钮模板,此模板在模块加载时会在UE4编辑器工具栏中注册一个按钮,点击此按钮将触发插件模块中的PluginButtonClicked函数。
  4. Editor Standalone Window
    编辑器独立窗口模板,顾名思义,它将创建出一个窗口,可以在此窗口中自定义界面,像引擎编辑器的各个界面一样的效果。

本文将选择创建一个编辑器独立窗口插件,填写相关属性,点击 Create Plugin 即可。

插件创建完成:

UE5 中的插件默认不会创建菜单栏按钮,我们可以在 Window 中找到插件的入口,点击 MyFirstPlugin 即可打开我们的插件

默认状态的插件如图:

此时让我们回到 Visual Studio 中来,可以发现,工程目录发生了改变,新增了 Plugin 文件夹。

展开后如图:

  • Resources:一般为图片图标的存放位置(UE 中有大量的图标,笔者感觉小 icon 足够用)
  • Source:代码存放位置
  • .uplugin文件:插件项目配置文件,JSON格式
  • .Build.cs文件:每个 .build.cs 文件声明派生自 ModuleRules 基类的类,并设置属性控制器从构造函数进行编译的方式。由虚幻编译工具编译,并被构造来确定整体编译环境。使用C#语法
4. 配置文件说明
  1. uplugin 文件
  • Category:类目名即在插件浏览器中所属的类目。
  • Installed:默认启用或禁用状态,在插件浏览器中可以控制加载卸载插件模块。
  • Modules:描述模块名、运行类型、加载时机、支持平台等信息。
  • Type:Runtime,RuntimeNoCommandlet,Developer,Editor,EditorNoCommandlet,Program。
  • LoadingPhase:Default,PreDefault,PostConfigInit,PostConfigInit。
  • WhitelistPlatforms:支持的平台
  • BlacklistPlatforms:不支持的平台
// Copyright Epic Games, Inc. All Rights Reserved.

using UnrealBuildTool;

public class MyFirstPlugin : ModuleRules
{
    public MyFirstPlugin(ReadOnlyTargetRules Target) : base(Target)
    {
        PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs;

        PublicIncludePaths.AddRange(
            new string[] {
                // ... add public include paths required here ...
            }
            );

        PrivateIncludePaths.AddRange(
            new string[] {
                // ... add other private include paths required here ...
            }
            );

        PublicDependencyModuleNames.AddRange(
            new string[]
            {
                "Core",
                // ... add other public dependencies that you statically link with here ...
            }
            );

        PrivateDependencyModuleNames.AddRange(
            new string[]
            {
                "Projects",
                "InputCore",
                "EditorFramework",
                "UnrealEd",
                "ToolMenus",
                "CoreUObject",
                "Engine",
                "Slate",
                "SlateCore",
                // ... add private dependencies that you statically link with here ...  
            }
            );

        DynamicallyLoadedModuleNames.AddRange(
            new string[]
            {
                // ... add any modules that your module loads dynamically here ...
            }
            );
    }
}
  1. public class PanoCam : ModuleRules 中的PanoCame为模块名,代码引用中认准这个名字
  2. PCHUsage = ModuleRules.PCHUsageMode.UseExplicitOrSharedPCHs
    预编译标头使用显示或共享标头。
  3. PublicIncludePathModuleNames (List)
    带有标头文件的模块名称列表(无需路径),需要由模块的公共标头访问,但不需要再“导入”或链接。
  4. PublicDependencyModuleNames (List)
    公共依赖性模块名称列表(不需要路径)(自动包含私有/公共)。这些是公共源文件所需的模块。
  5. PrivateIncludePathModuleNames (List)
    带有标头文件的模块名称列表(无需路径),需要由模块的私有代码文件访问,但不需要再“导入”或链接。
  6. PrivateDependencyModuleNames (List)
    私有依赖性模块名称列表。这些是私有代码所依赖的模块,但公共include文件中没有任何依赖。
  7. DynamicallyLoadedModuleNames (List)
    此模块在运行时可能需要的附加模块。
  8. PublicSystemIncludePaths (List)
    系统/库include路径列表,通常用于外部(第三方)模块。在解析标头依赖项时未检查的公共稳定标头文件目录。
  9. PublicIncludePaths (List)
    (当前不需要此设置,因为可以从“Public”文件夹中搜索所有文件)公开给其他模块的include文件的所有路径列表。
  10. PrivateIncludePaths (List)
    此模块内部include文件的所有路径的列表,未公开给其他模块(至少有一个包含在“私有”路径中,如果要避免相对路径,可以添加更多)
  11. PublicLibraryPaths (List)
    系统/库路径列表(.lib文件的目录),通常用于外部(第三方)模块。
  12. PublicAdditionalLibraries (List)
    其他库的列表(包括扩展名的.lib文件的名称),通常用于外部(第三方)模块。
5. 插件框架

在我们选择创建了编辑器独立窗口插件后,工程中自动生成了相关的框架代码

插件可含有任意数量的模块源目录。多数插件仅有一个模块(但可创建多个模块,例如插件包含纯编辑器功能时),及游戏期间要运行的其他代码。

插件源文件的大部分布局与引擎中其他C++模块相同。

在模块的 Source 目录(或其子目录)内,插件可在标头文件中声明新反映的类型(UCLASSUSTRUCT 等)。引擎的构建系统将检测此类文件,并按需要生成代码支持新类型。需遵守C++模块中使用 Uobjects 时的一般规则,例如在模块的源文件中包含生成的标头文件和模块 generated.inl 文件。

UE4支持共生模块和插件。通过在自身.uproject文件中启用插件,项目模块可依赖插件。类似地,通过在自身.uplugin文件中启用其他插件,插件可表明依赖性。但其中有一项重要限制:插件和模块将拆分为若干层级,仅能依赖同一级或更高级的其他插件或模块。例如,项目模块可依赖引擎模块,但引擎模块无法依赖项目模块。这是因为引擎(及其所有插件和模块)的级别高于项目,须能在无项目的情况下编译。以下图表展示了项目和模块间的依赖性层级:

PluginAndModuleDependency.png
箭头表明可能的依赖性。各插件或模块类型可依赖同级别或更高级别的其他插件或模块类型。

MyFirstPlugin.h 内容如下

// Copyright Epic Games, Inc. All Rights Reserved.

#pragma once

#include "CoreMinimal.h"
#include "Modules/ModuleManager.h"

class FToolBarBuilder;
class FMenuBuilder;

class FMyFirstPluginModule : public IModuleInterface
{
public:

    /** IModuleInterface implementation */
    virtual void StartupModule() override;
    virtual void ShutdownModule() override;

    /** This function will be bound to Command (by default it will bring up plugin window) */
    void PluginButtonClicked();

private:

    void RegisterMenus();

    TSharedRef<class SDockTab> OnSpawnPluginTab(const class FSpawnTabArgs& SpawnTabArgs);

private:
    TSharedPtr<class FUICommandList> PluginCommands;
};

每个独立模块都有一个这样的类且继承于 IModuleInterface,重写了插件加载卸载的方法。
.uplugin 文件中 Modules 下的 LoadingPhase 字段说明了模块加载的时机,当满足这个时机时此模块StartupModule 函数将被调用。
此插件的功能入口就是从这里开始。
当程序关闭或主动调用 ShutdownModule 函数时,模块将被卸载。

6. Slate

Slate 是完全自定义、与平台无关的用户界面框架,旨在让工具和应用程序(比如虚幻编辑器)的用户界面或游戏中用户界面的构建过程变得有趣、高效。它将声明性语法与轻松设计、布局和风格组件的功能相结合,允许在UI上轻松实现创建和迭代。

Slate UI解决方案使得为工具和应用程序组合图形用户界面和快速迭代这些界面变得极其简单。

Slate概述 | 虚幻引擎文档 (unrealengine.com)

笔者此处不再添加 UI 控件相关用法,新开文章后链接于此。

https://santa.wang/ue-slate-upropety

参考链接:

(117条消息) UE4插件开发_顺杭的博客-CSDN博客_ue4 插件开发

(117条消息) UE4项目工程的目录结构_游戏鸟的博客-CSDN博客

(117条消息) UE4中的Slate&UMG类图_桃溪小小生的博客-CSDN博客_ue4 umg和slate

比较大佬的文章:

Unreal插件开发入门 - 简书 (jianshu.com)

如堕五里雾中
最后更新于 2023-03-08