六一的部落格


关关难过关关过,前路漫漫亦灿灿。




便签

Unreal Engine C++ Project Setup, From Scratch


说明

-
Cmder 终端模拟器
Sublime

虚幻引擎5.1版本说明 : 依赖.NET 6.0


概览

  • 从零创建Unreal项目
  • 在命令行编译和运行项目, 封装在脚本中
  • 创建Actor派生类
  • 查看引擎代码

Cmder

  1. 显示/隐藏窗口: C-`
  2. 在文件资源管理器打开Cmder当前路径
    1cd /d C:\Dirk
    2explorer .

Sublime

使用以下插件

-
Project Manager
Switch File Deluxe 在源文件和头文件之间切换; Windows Alt-O ; macOS Option-Command-UP
Unreal Snippets UP主提供

从零创建Unreal项目

创建项目文件夹Dirk


创建项目

  1. Sublime > 命令行 > Project Manager: Add New Project
  2. 命名为Dirk

添加文件夹

  1. Sublime > 命令行 > Project: Add Folder
  2. 选择Dirk

创建Unreal项目文件

Dirk/Dirk.uproject

包含项目对应的引擎版本, 以及打开该项目所需的动态库

  1. 插入代码段: uuproj > TAB
  2. 修改 Modules > Name
     1{
     2    "FileVersion": 3,
     3    "EngineAssociation": "4.25",
     4    "Category": "",
     5    "Description": "",
     6    "Modules": [
     7        {
     8            "Name": "DirkCore",
     9            "Type": "Runtime",
    10            "LoadingPhase": "Default"
    11        }
    12    ]
    13}

创建Target文件

  • 指示如何编译Target

    Target Rules Definition
  • 有两个Target, 游戏实例和虚幻编辑器

游戏实例

Dirk/Source/Dirk.Target.cs

  1. 插入代码段: umt > TAB
  2. 给出需要构造的模块
     1using UnrealBuildTool;
     2
     3public class DirkTarget : TargetRules
     4{
     5    public DirkTarget(TargetInfo Target) : base(Target)
     6    {
     7        Type = TargetType.Game;
     8        DefaultBuildSettings = BuildSettingsVersion.V2;
     9        ExtraModuleNames.AddRange( new string[] { "DirkCore" } );
    10    }
    11}

虚幻编辑器

Dirk/Source/DirkEditor.Target.cs

  1. 插入代码段: umt > TAB
  2. 填写Target类型为Editor
  3. 给出需要构造的模块
     1using UnrealBuildTool;
     2
     3public class DirkEditorTarget : TargetRules
     4{
     5    public DirkEditorTarget(TargetInfo Target) : base(Target)
     6    {
     7        Type = TargetType.Editor;
     8        DefaultBuildSettings = BuildSettingsVersion.V2;
     9        ExtraModuleNames.AddRange( new string[] { "DirkCore" } );
    10    }
    11}

创建游戏主模块DirkCore

Primary Game Module

一个项目只有一个游戏主模块; 创建文件夹Dirk/Source/DirkCore


创建源码文件夹

-
Dirk/Source/DirkCore/Public 存放对其他模块可见的头文件
Dirk/Source/DirkCore/Private 存放实现 Implementataion 和模块内部逻辑

模块编译规则

Module Build Rules

Dirk/Source/DirkCore/DirkCore.Build.cs

  1. 插入代码段: umb > TAB
  2. 填写依赖模块: 已填写最少依赖
    -
    Core
    CoreUObject
    Engine
 1using UnrealBuildTool;
 2
 3public class DirkCore : ModuleRules
 4{
 5    public DirkCore(ReadOnlyTargetRules Target) : base(Target)
 6    {
 7        PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
 8        bEnforceIWYU = true;
 9
10        PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine" });
11        PrivateDependencyModuleNames.AddRange(new string[] { });
12    }
13}
  • 虚幻引擎由各个模块组成

    • 查看 Epic Games\UE_5.1\Engine\Source ,组织方式为模块类型
    • Runtime模块:引擎代码,不包含虚幻编辑器和开发工具; 包含各种运行时模块, 如Core、CoreUObject和Engine

      如果想要开发VR游戏, 则需添加依赖模块HeadMountedDisplay

模块实现

模块定义和模块同名

  • DirkCore.h

    Dirk/Source/DirkCore/Public/DirkCore.h

    1. 插入代码段: umh > TAB
    2. 定义了模块入口
    3. 加载模块之后, 调用StartupModule; 卸载模块之前, 调用ShutdownModule
     1#pragma once
     2
     3#include "CoreMinimal.h"
     4#include "Modules/ModuleInterface.h"
     5
     6class FDirkCore : public IModuleInterface
     7{
     8public:
     9    static inline FDirkCore& Get()
    10    {
    11        return FModuleManager::LoadModuleChecked<FDirkCore>("DirkCore");
    12    }
    13
    14    static inline bool IsAvailable()
    15    {
    16        return FModuleManager::Get().IsModuleLoaded("DirkCore");
    17    }
    18
    19    virtual void StartupModule() override;
    20    virtual void ShutdownModule() override;
    21};
  • DirkCore.cpp

    Dirk/Source/DirkCore/Private/DirkCore.cpp

    插入代码段: umcp > TAB

     1#include "DirkCore.h"
     2#include "Modules/ModuleManager.h"
     3
     4#include "Log.h"
     5
     6void FDirkCore::StartupModule()
     7{
     8    UE_LOG(LogDirkCore, Log, TEXT("DirkCore module starting up"));
     9}
    10
    11void FDirkCore::ShutdownModule()
    12{
    13    UE_LOG(LogDirkCore, Log, TEXT("DirkCore module shutting down"));
    14}
    15
    16IMPLEMENT_PRIMARY_GAME_MODULE(FDirkCore, DirkCore, "DirkCore");

创建日志类别

只在DirkCore内部使用, 头文件和源文件均存放在Dirk/Source/DirkCore/Private中

  1. Log.h

    插入代码段: ulh > TAB
    1#pragma once
    2
    3#include "Logging/LogMacros.h"
    4
    5DECLARE_LOG_CATEGORY_EXTERN(LogDirkCore, All, All);
  2. Log.cpp

    插入代码段: ulc > TAB
    1#include "Log.h"
    2
    3DEFINE_LOG_CATEGORY(LogDirkCore);
  3. 插入日志语句: ull > TAB

编译项目

虚幻引擎有自己的交叉编译系统 Cross-Platform , 我们通过C#文件配置Target和模块的编译规则


编译虚幻编辑器使用的动态库

脚本路径
Windows Epic Games\UE_5.1\Engine\Build\BatchFiles\Build.bat
macOS Epic Games\UE_5.1\Engine\Build\BatchFiles\Mac\Build.sh
  • Build脚本包括UnrealBuildTool的调用, 和一些参数配置
  • 运行Build脚本, 指定Target、Platform和Build Configuration, 给出uproject文件路径
  • 最终, 模块被链接成动态库, 供虚幻编辑器加载
-
Target DirkEditor
平台 Mac
编译配置 Development, 介于Debug和Shipping之间

Windows

1"C:\Epic Games\UE_5.1\Engine\Build\BatchFiles\Build.bat" DirkEditor Win64 Development "C:\Dirk\Dirk.uproject" -waitmutex -NoHotReload

macOS

1#!/bin/bash
2
3Project="Dirk/Dirk.uproject"
4BuildScript="UE_5.1/Engine/Build/BatchFiles/Mac/Build.sh"
5Target="DirkEditor"
6
7$BuildScript $Target Mac Development $Project -waitmutex -NoHotReload

虚幻头文件工具

Unreal Header Tool

虚幻引擎源码里使用了很多宏,在编译之前,需要进行解析,在源码文件中进行替换


新增文件夹

-
Binaries
Intermediate 生成文件
-
Dirk/Binaries/Mac/UnrealEditor.modules 元数据 Meta Data , 说明该模块所需的动态库文件, 和引擎版本
打开虚幻编辑器, 会比对引擎版本和项目对应的引擎版本是否一致
Dirk/Binaries/Mac/DirkEditor.target 元数据
  • Windows
    -
    Dirk/Binaries/Win64/UnrealEditor-DirkCore.dll 模块动态库
    Dirk/Binaries/Win64/UnrealEditor-DirkCore.pdb 存放调试信息
  • macOS
    -
    Dirk/Binaries/Mac/UnrealEditor-DirkCore.dylib 模块动态库

使用虚幻编辑器打开项目


Windows

1"C:\Epic Games\UE_5.1\Engine\Binaries\Win64\UnrealEditor.exe" "C:\Dirk\Dirk.uproject" -log

macOS

1#!/bin/bash
2
3Project="Dirk/Dirk.uproject"
4UnrealEditor="UE_5.1/Engine/Binaries/Mac/UnrealEditor.app"
5
6open -a $UnrealEditor $Project

新增文件夹

-
Saved 存放日志和运行时 Runtime 生成
DerivedDataCache 虚幻编辑器导入资产时的缓存
Content 存放各种资产
Config 项目配置

使用虚幻编辑器运行游戏实例, 不加载编辑器本身

使用-game选项


Windows

1"C:\Epic Games\UE_5.1\Engine\Binaries\Win64\UnrealEditor.exe" "C:\Dirk\Dirk.uproject" -game -log -windowed -resx=1280 -resy=720

macOS

1#!/bin/bash
2
3Project="Dirk/Dirk.uproject"
4UnrealEditor="UE_5.1/Engine/Binaries/Mac/UnrealEditor.app/Contents/MacOS/UnrealEditor"
5
6$UnrealEditor $Project -game -log -windowed -resx=1280 -resy=720

编译游戏实例


编译游戏实例

  • 使用游戏实例Target, 得到项目的独立运行版本 Standalone Version
  • 不再把模块链接成动态库, 将项目和引擎源码链接在一起, 生成一个可执行游戏, 不包含虚幻编辑器的特定功能
  • Windows

    1"C:\Epic Games\UE_5.1\Engine\Build\BatchFiles\Build.bat" Dirk Win64 Development "C:\Dirk\Dirk.uproject" -waitmutex -NoHotReload
  • macOS

    1#!/bin/bash
    2
    3Project="Dirk/Dirk.uproject"
    4BuildScript="UE_5.1/Engine/Build/BatchFiles/Mac/Build.sh"
    5Target="Dirk"
    6
    7$BuildScript $Target Mac Development $Project -waitmutex -NoHotReload

烘培资产

Windows

Cook Content

  • 虚幻编辑器使用未烘培资产, 而游戏实例直接将压缩纹理加载到GPU
  • Saved/Cooked存放游戏实例运行时所需资产
  • macOS无UnrealEditor-cmd程序
1"C:\Epic Games\UE_5.1\Engine\Binaries\Win64\UnrealEditor-cmd.exe" "C:\Dirk\Dirk.uproject" -run=cook -targetplatform=Windows

运行游戏实例

Windows

构建时使用了Development参数, 运行时可以使用开发工具

1"C:\Dirk\Binaries\Win64\Dirk.exe" -log -windowed -resx=1280 -resy=720

运行脚本

Windows

和Dirk文件夹同级


变量

vars.bat

 1@echo off 
 2Rem 不打印命令
 3
 4set ROOTDIR=%~dp0
 5Rem ~dp0为脚本所在目录
 6
 7set ROOTDIR=%ROOTDIR:~0,-1% 
 8Rem  ~0,-1% 去除目录最后的/
 9
10set PROJECT=Dirk
11set PROJECT_DIR=%ROOTDIR%\%PROJECT%
12set UPROJECT_PATH=%PROJECT_DIR%\%PROJECT%.uproject
13
14set UE5_DIR=C:\Epic Games\UE_5.1
15set UE5EDITOR_EXE=%UE5_DIR%\Engine\Binaries\Win64\UnrealEditor.exe
16set BUILD_BAT=%UE5_DIR%\Engine\Build\BatchFiles\Build.bat

编译

build.bat

1@echo off
2
3call %~dp0\vars.bat
4
5call "%BUILD_BAT%" %PROJECT%Editor Win64 Development "%UPROJECT_PATH%" -waitmutex -NoHotReload

在虚幻编辑器中打开项目

editor.bat

1@echo off
2
3call %~dp0\vars.bat
4
5start "%UE5EDITOR_EXE%" "%UPROJECT_PATH%" %*

运行脚本

  • 在虚幻编辑器中打开项目
    1editor
    2editor -log
  • 编译成功则在虚幻编辑器中打开
    1build && editor

创建C++类


TestActor.h

Dirk/Source/DirkCore/Public/TestActor.h


插入代码段

  1. 定义Actor派生类: uca > TAB
  2. 添加组件: upc > TAB

    protected
    1class UBillboardComponent;
    2
    3UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Components")
    4class UBillboardComponent* BillboardComponentSprite;	
    
  3. 添加蓝图可编辑属性: upe > TAB

    protected
    1UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Test")
    2int32 Value;
  4. 覆写BeginPlay

    public
    1virtual void BeginPlay() override;
  5. 构造函数: ufc > TAB

    public
    1ATestActor(const FObjectInitializer& ObjectInitializer);

完整代码

 1#pragma once
 2
 3#include "CoreMinimal.h"
 4#include "GameFramework/Actor.h"
 5
 6#include "TestActor.generated.h"
 7
 8class UBillboardComponent;
 9
10UCLASS()
11class ATestActor : public AActor
12{
13    GENERATED_BODY()
14
15public:
16    ATestActor(const FObjectInitializer& ObjectInitializer);
17    virtual void BeginPlay() override;
18
19protected:
20    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Components")
21    class UBillboardComponent* Sprite;	
22
23    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Test")
24    int32 Value;
25};

TestActor.cpp

Dirk/Source/DirkCore/Private/TestActor.cpp

 1#include "TestActor.h"
 2#include "Components/SceneComponent.h"
 3#include "Components/BillboardComponent.h"
 4#include "Log.h"
 5
 6ATestActor::ATestActor(const FObjectInitializer& ObjectInitializer)
 7    : Super(ObjectInitializer)
 8{
 9    Value = 42;
10
11    RootComponent = ObjectInitializer.CreateDefaultSubobject<USceneComponent>(this, TEXT("RootComponent"));
12
13    Sprite = ObjectInitializer.CreateDefaultSubobject<UBillboardComponent>(this, TEXT("Sprite"));
14    Sprite->SetupAttachment(RootComponent);
15}
16
17void ATestActor::BeginPlay()
18{
19    Super::BeginPlay();
20
21    UE_LOG(LogDirkCore, Log, TEXT("%s: on BeginPlay, Value is %d"), *GetName(), Value);
22}

查看引擎代码

  1. 添加引擎源码文件夹

    命令行 > Project: Add Folder > Epic Games\UE_5.1\Engine\Source\Runtime
  2. 项目内查找: 查找派生类
    • Find
      : public FPrimitiveSceneProxy
    • Where
      C:\Epic Games\UE_5.1\Engine\Plugins,*.h,*.cpp,*.inl         
  3. 文件内查找

    支持正则匹配
    • 去到文件Actor.h
    • Set.*Tranform

总结


Visual Studio

MSVC++提供cl.exe和link.exe, 作为编译器 Compiler 和链接器 Linker


Unreal Engine

提供UnrealBuildTool.exe, UnrealHeaderTool.exe和UnrealEditor.exe


虚幻引擎项目

  1. 项目文件: Dirk.uproject
  2. 蓝图项目: 没有模块项
    1{
    2    "FileVersion": 3,
    3    "EngineAssociation": "5.1",
    4    "Category": "",
    5    "Description": ""
    6}
  3. C++项目:
    • 虚幻编辑器需加载指定模块
       1{
       2    "FileVersion": 3,
       3    "EngineAssociation": "5.1",
       4    "Category": "",
       5    "Description": "",
       6    "Modules": [
       7        {
       8            "Name": "DirkCore",
       9            "Type": "Runtime",
      10            "LoadingPhase": "Default"
      11        }
      12    ]
      13
      14}

项目编译

  1. 模块定义在Dirk/Source, 每个模块的构造规则在Build.cs文件中说明
  2. 每个项目有两个Target.cs文件, 说明其依赖的模块
  3. UnrealBuildTool根据Target构造规则编译依赖模块, 模块编译则依据模块编译规则

模块编译

  1. 解析头文件得到生成代码,保存在Intermediate文件夹

    Unreal Header Tool

    DirkCore.init.gen.cpp

    TestActor.gen.cpp

    TestActor.generated.h
  2. 编译解析完的单元, 生成目标文件

    Unreal Build Tool

    DirkCore.cpp.obj

    DirkCore.init.gen.cpp.obj

    TestActor.cpp.obj

    TestActor.gen.cpp.obj
  3. 将代码链接到一起,根据编译规则 Build Rules 提供的依赖名单解决模块见交叉引用

    Unreal Build Tool
  4. 最后, 得到编辑器所需的动态库

    UEEditor-DirkCore.dll

    UEEditor-DirCore.pdb
  5. 给出uproject文件,可以在编辑器中编辑或运行未烘培资产的项目
  6. 也可以使用编辑器为项目烘培资产, 之后, 可以运行独立游戏
标题目录

Windows上使用Sublime进行Unreal开发



便签

Unreal Engine C++ Project Setup, From Scratch


说明

-
Cmder 终端模拟器
Sublime

虚幻引擎5.1版本说明 : 依赖.NET 6.0


概览

  • 从零创建Unreal项目
  • 在命令行编译和运行项目, 封装在脚本中
  • 创建Actor派生类
  • 查看引擎代码

Cmder

  1. 显示/隐藏窗口: C-`
  2. 在文件资源管理器打开Cmder当前路径
    1cd /d C:\Dirk
    2explorer .

Sublime

使用以下插件

-
Project Manager
Switch File Deluxe 在源文件和头文件之间切换; Windows Alt-O ; macOS Option-Command-UP
Unreal Snippets UP主提供

从零创建Unreal项目

创建项目文件夹Dirk


创建项目

  1. Sublime > 命令行 > Project Manager: Add New Project
  2. 命名为Dirk

添加文件夹

  1. Sublime > 命令行 > Project: Add Folder
  2. 选择Dirk

创建Unreal项目文件

Dirk/Dirk.uproject

包含项目对应的引擎版本, 以及打开该项目所需的动态库

  1. 插入代码段: uuproj > TAB
  2. 修改 Modules > Name
     1{
     2    "FileVersion": 3,
     3    "EngineAssociation": "4.25",
     4    "Category": "",
     5    "Description": "",
     6    "Modules": [
     7        {
     8            "Name": "DirkCore",
     9            "Type": "Runtime",
    10            "LoadingPhase": "Default"
    11        }
    12    ]
    13}

创建Target文件

  • 指示如何编译Target

    Target Rules Definition
  • 有两个Target, 游戏实例和虚幻编辑器

游戏实例

Dirk/Source/Dirk.Target.cs

  1. 插入代码段: umt > TAB
  2. 给出需要构造的模块
     1using UnrealBuildTool;
     2
     3public class DirkTarget : TargetRules
     4{
     5    public DirkTarget(TargetInfo Target) : base(Target)
     6    {
     7        Type = TargetType.Game;
     8        DefaultBuildSettings = BuildSettingsVersion.V2;
     9        ExtraModuleNames.AddRange( new string[] { "DirkCore" } );
    10    }
    11}

虚幻编辑器

Dirk/Source/DirkEditor.Target.cs

  1. 插入代码段: umt > TAB
  2. 填写Target类型为Editor
  3. 给出需要构造的模块
     1using UnrealBuildTool;
     2
     3public class DirkEditorTarget : TargetRules
     4{
     5    public DirkEditorTarget(TargetInfo Target) : base(Target)
     6    {
     7        Type = TargetType.Editor;
     8        DefaultBuildSettings = BuildSettingsVersion.V2;
     9        ExtraModuleNames.AddRange( new string[] { "DirkCore" } );
    10    }
    11}

创建游戏主模块DirkCore

Primary Game Module

一个项目只有一个游戏主模块; 创建文件夹Dirk/Source/DirkCore


创建源码文件夹

-
Dirk/Source/DirkCore/Public 存放对其他模块可见的头文件
Dirk/Source/DirkCore/Private 存放实现 Implementataion 和模块内部逻辑

模块编译规则

Module Build Rules

Dirk/Source/DirkCore/DirkCore.Build.cs

  1. 插入代码段: umb > TAB
  2. 填写依赖模块: 已填写最少依赖
    -
    Core
    CoreUObject
    Engine
 1using UnrealBuildTool;
 2
 3public class DirkCore : ModuleRules
 4{
 5    public DirkCore(ReadOnlyTargetRules Target) : base(Target)
 6    {
 7        PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
 8        bEnforceIWYU = true;
 9
10        PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine" });
11        PrivateDependencyModuleNames.AddRange(new string[] { });
12    }
13}
  • 虚幻引擎由各个模块组成

    • 查看 Epic Games\UE_5.1\Engine\Source ,组织方式为模块类型
    • Runtime模块:引擎代码,不包含虚幻编辑器和开发工具; 包含各种运行时模块, 如Core、CoreUObject和Engine

      如果想要开发VR游戏, 则需添加依赖模块HeadMountedDisplay

模块实现

模块定义和模块同名

  • DirkCore.h

    Dirk/Source/DirkCore/Public/DirkCore.h

    1. 插入代码段: umh > TAB
    2. 定义了模块入口
    3. 加载模块之后, 调用StartupModule; 卸载模块之前, 调用ShutdownModule
     1#pragma once
     2
     3#include "CoreMinimal.h"
     4#include "Modules/ModuleInterface.h"
     5
     6class FDirkCore : public IModuleInterface
     7{
     8public:
     9    static inline FDirkCore& Get()
    10    {
    11        return FModuleManager::LoadModuleChecked<FDirkCore>("DirkCore");
    12    }
    13
    14    static inline bool IsAvailable()
    15    {
    16        return FModuleManager::Get().IsModuleLoaded("DirkCore");
    17    }
    18
    19    virtual void StartupModule() override;
    20    virtual void ShutdownModule() override;
    21};
  • DirkCore.cpp

    Dirk/Source/DirkCore/Private/DirkCore.cpp

    插入代码段: umcp > TAB

     1#include "DirkCore.h"
     2#include "Modules/ModuleManager.h"
     3
     4#include "Log.h"
     5
     6void FDirkCore::StartupModule()
     7{
     8    UE_LOG(LogDirkCore, Log, TEXT("DirkCore module starting up"));
     9}
    10
    11void FDirkCore::ShutdownModule()
    12{
    13    UE_LOG(LogDirkCore, Log, TEXT("DirkCore module shutting down"));
    14}
    15
    16IMPLEMENT_PRIMARY_GAME_MODULE(FDirkCore, DirkCore, "DirkCore");

创建日志类别

只在DirkCore内部使用, 头文件和源文件均存放在Dirk/Source/DirkCore/Private中

  1. Log.h

    插入代码段: ulh > TAB
    1#pragma once
    2
    3#include "Logging/LogMacros.h"
    4
    5DECLARE_LOG_CATEGORY_EXTERN(LogDirkCore, All, All);
  2. Log.cpp

    插入代码段: ulc > TAB
    1#include "Log.h"
    2
    3DEFINE_LOG_CATEGORY(LogDirkCore);
  3. 插入日志语句: ull > TAB

编译项目

虚幻引擎有自己的交叉编译系统 Cross-Platform , 我们通过C#文件配置Target和模块的编译规则


编译虚幻编辑器使用的动态库

脚本路径
Windows Epic Games\UE_5.1\Engine\Build\BatchFiles\Build.bat
macOS Epic Games\UE_5.1\Engine\Build\BatchFiles\Mac\Build.sh
  • Build脚本包括UnrealBuildTool的调用, 和一些参数配置
  • 运行Build脚本, 指定Target、Platform和Build Configuration, 给出uproject文件路径
  • 最终, 模块被链接成动态库, 供虚幻编辑器加载
-
Target DirkEditor
平台 Mac
编译配置 Development, 介于Debug和Shipping之间

Windows

1"C:\Epic Games\UE_5.1\Engine\Build\BatchFiles\Build.bat" DirkEditor Win64 Development "C:\Dirk\Dirk.uproject" -waitmutex -NoHotReload

macOS

1#!/bin/bash
2
3Project="Dirk/Dirk.uproject"
4BuildScript="UE_5.1/Engine/Build/BatchFiles/Mac/Build.sh"
5Target="DirkEditor"
6
7$BuildScript $Target Mac Development $Project -waitmutex -NoHotReload

虚幻头文件工具

Unreal Header Tool

虚幻引擎源码里使用了很多宏,在编译之前,需要进行解析,在源码文件中进行替换


新增文件夹

-
Binaries
Intermediate 生成文件
-
Dirk/Binaries/Mac/UnrealEditor.modules 元数据 Meta Data , 说明该模块所需的动态库文件, 和引擎版本
打开虚幻编辑器, 会比对引擎版本和项目对应的引擎版本是否一致
Dirk/Binaries/Mac/DirkEditor.target 元数据
  • Windows
    -
    Dirk/Binaries/Win64/UnrealEditor-DirkCore.dll 模块动态库
    Dirk/Binaries/Win64/UnrealEditor-DirkCore.pdb 存放调试信息
  • macOS
    -
    Dirk/Binaries/Mac/UnrealEditor-DirkCore.dylib 模块动态库

使用虚幻编辑器打开项目


Windows

1"C:\Epic Games\UE_5.1\Engine\Binaries\Win64\UnrealEditor.exe" "C:\Dirk\Dirk.uproject" -log

macOS

1#!/bin/bash
2
3Project="Dirk/Dirk.uproject"
4UnrealEditor="UE_5.1/Engine/Binaries/Mac/UnrealEditor.app"
5
6open -a $UnrealEditor $Project

新增文件夹

-
Saved 存放日志和运行时 Runtime 生成
DerivedDataCache 虚幻编辑器导入资产时的缓存
Content 存放各种资产
Config 项目配置

使用虚幻编辑器运行游戏实例, 不加载编辑器本身

使用-game选项


Windows

1"C:\Epic Games\UE_5.1\Engine\Binaries\Win64\UnrealEditor.exe" "C:\Dirk\Dirk.uproject" -game -log -windowed -resx=1280 -resy=720

macOS

1#!/bin/bash
2
3Project="Dirk/Dirk.uproject"
4UnrealEditor="UE_5.1/Engine/Binaries/Mac/UnrealEditor.app/Contents/MacOS/UnrealEditor"
5
6$UnrealEditor $Project -game -log -windowed -resx=1280 -resy=720

编译游戏实例


编译游戏实例

  • 使用游戏实例Target, 得到项目的独立运行版本 Standalone Version
  • 不再把模块链接成动态库, 将项目和引擎源码链接在一起, 生成一个可执行游戏, 不包含虚幻编辑器的特定功能
  • Windows

    1"C:\Epic Games\UE_5.1\Engine\Build\BatchFiles\Build.bat" Dirk Win64 Development "C:\Dirk\Dirk.uproject" -waitmutex -NoHotReload
  • macOS

    1#!/bin/bash
    2
    3Project="Dirk/Dirk.uproject"
    4BuildScript="UE_5.1/Engine/Build/BatchFiles/Mac/Build.sh"
    5Target="Dirk"
    6
    7$BuildScript $Target Mac Development $Project -waitmutex -NoHotReload

烘培资产

Windows

Cook Content

  • 虚幻编辑器使用未烘培资产, 而游戏实例直接将压缩纹理加载到GPU
  • Saved/Cooked存放游戏实例运行时所需资产
  • macOS无UnrealEditor-cmd程序
1"C:\Epic Games\UE_5.1\Engine\Binaries\Win64\UnrealEditor-cmd.exe" "C:\Dirk\Dirk.uproject" -run=cook -targetplatform=Windows

运行游戏实例

Windows

构建时使用了Development参数, 运行时可以使用开发工具

1"C:\Dirk\Binaries\Win64\Dirk.exe" -log -windowed -resx=1280 -resy=720

运行脚本

Windows

和Dirk文件夹同级


变量

vars.bat

 1@echo off 
 2Rem 不打印命令
 3
 4set ROOTDIR=%~dp0
 5Rem ~dp0为脚本所在目录
 6
 7set ROOTDIR=%ROOTDIR:~0,-1% 
 8Rem  ~0,-1% 去除目录最后的/
 9
10set PROJECT=Dirk
11set PROJECT_DIR=%ROOTDIR%\%PROJECT%
12set UPROJECT_PATH=%PROJECT_DIR%\%PROJECT%.uproject
13
14set UE5_DIR=C:\Epic Games\UE_5.1
15set UE5EDITOR_EXE=%UE5_DIR%\Engine\Binaries\Win64\UnrealEditor.exe
16set BUILD_BAT=%UE5_DIR%\Engine\Build\BatchFiles\Build.bat

编译

build.bat

1@echo off
2
3call %~dp0\vars.bat
4
5call "%BUILD_BAT%" %PROJECT%Editor Win64 Development "%UPROJECT_PATH%" -waitmutex -NoHotReload

在虚幻编辑器中打开项目

editor.bat

1@echo off
2
3call %~dp0\vars.bat
4
5start "%UE5EDITOR_EXE%" "%UPROJECT_PATH%" %*

运行脚本

  • 在虚幻编辑器中打开项目
    1editor
    2editor -log
  • 编译成功则在虚幻编辑器中打开
    1build && editor

创建C++类


TestActor.h

Dirk/Source/DirkCore/Public/TestActor.h


插入代码段

  1. 定义Actor派生类: uca > TAB
  2. 添加组件: upc > TAB

    protected
    1class UBillboardComponent;
    2
    3UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Components")
    4class UBillboardComponent* BillboardComponentSprite;	
    
  3. 添加蓝图可编辑属性: upe > TAB

    protected
    1UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Test")
    2int32 Value;
  4. 覆写BeginPlay

    public
    1virtual void BeginPlay() override;
  5. 构造函数: ufc > TAB

    public
    1ATestActor(const FObjectInitializer& ObjectInitializer);

完整代码

 1#pragma once
 2
 3#include "CoreMinimal.h"
 4#include "GameFramework/Actor.h"
 5
 6#include "TestActor.generated.h"
 7
 8class UBillboardComponent;
 9
10UCLASS()
11class ATestActor : public AActor
12{
13    GENERATED_BODY()
14
15public:
16    ATestActor(const FObjectInitializer& ObjectInitializer);
17    virtual void BeginPlay() override;
18
19protected:
20    UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category="Components")
21    class UBillboardComponent* Sprite;	
22
23    UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Test")
24    int32 Value;
25};

TestActor.cpp

Dirk/Source/DirkCore/Private/TestActor.cpp

 1#include "TestActor.h"
 2#include "Components/SceneComponent.h"
 3#include "Components/BillboardComponent.h"
 4#include "Log.h"
 5
 6ATestActor::ATestActor(const FObjectInitializer& ObjectInitializer)
 7    : Super(ObjectInitializer)
 8{
 9    Value = 42;
10
11    RootComponent = ObjectInitializer.CreateDefaultSubobject<USceneComponent>(this, TEXT("RootComponent"));
12
13    Sprite = ObjectInitializer.CreateDefaultSubobject<UBillboardComponent>(this, TEXT("Sprite"));
14    Sprite->SetupAttachment(RootComponent);
15}
16
17void ATestActor::BeginPlay()
18{
19    Super::BeginPlay();
20
21    UE_LOG(LogDirkCore, Log, TEXT("%s: on BeginPlay, Value is %d"), *GetName(), Value);
22}

查看引擎代码

  1. 添加引擎源码文件夹

    命令行 > Project: Add Folder > Epic Games\UE_5.1\Engine\Source\Runtime
  2. 项目内查找: 查找派生类
    • Find
      : public FPrimitiveSceneProxy
    • Where
      C:\Epic Games\UE_5.1\Engine\Plugins,*.h,*.cpp,*.inl         
  3. 文件内查找

    支持正则匹配
    • 去到文件Actor.h
    • Set.*Tranform

总结


Visual Studio

MSVC++提供cl.exe和link.exe, 作为编译器 Compiler 和链接器 Linker


Unreal Engine

提供UnrealBuildTool.exe, UnrealHeaderTool.exe和UnrealEditor.exe


虚幻引擎项目

  1. 项目文件: Dirk.uproject
  2. 蓝图项目: 没有模块项
    1{
    2    "FileVersion": 3,
    3    "EngineAssociation": "5.1",
    4    "Category": "",
    5    "Description": ""
    6}
  3. C++项目:
    • 虚幻编辑器需加载指定模块
       1{
       2    "FileVersion": 3,
       3    "EngineAssociation": "5.1",
       4    "Category": "",
       5    "Description": "",
       6    "Modules": [
       7        {
       8            "Name": "DirkCore",
       9            "Type": "Runtime",
      10            "LoadingPhase": "Default"
      11        }
      12    ]
      13
      14}

项目编译

  1. 模块定义在Dirk/Source, 每个模块的构造规则在Build.cs文件中说明
  2. 每个项目有两个Target.cs文件, 说明其依赖的模块
  3. UnrealBuildTool根据Target构造规则编译依赖模块, 模块编译则依据模块编译规则

模块编译

  1. 解析头文件得到生成代码,保存在Intermediate文件夹

    Unreal Header Tool

    DirkCore.init.gen.cpp

    TestActor.gen.cpp

    TestActor.generated.h
  2. 编译解析完的单元, 生成目标文件

    Unreal Build Tool

    DirkCore.cpp.obj

    DirkCore.init.gen.cpp.obj

    TestActor.cpp.obj

    TestActor.gen.cpp.obj
  3. 将代码链接到一起,根据编译规则 Build Rules 提供的依赖名单解决模块见交叉引用

    Unreal Build Tool
  4. 最后, 得到编辑器所需的动态库

    UEEditor-DirkCore.dll

    UEEditor-DirCore.pdb
  5. 给出uproject文件,可以在编辑器中编辑或运行未烘培资产的项目
  6. 也可以使用编辑器为项目烘培资产, 之后, 可以运行独立游戏