UE4中类自动生成代码解析


本文章由cartzhang编写,转载请注明出处。 所有权利保留。
文章链接:http://blog.csdn.net/cartzhang/article/details/73189272
作者:cartzhang

一、 UE4 C++ 代码自动生成流程

1. 界面点击生成C++类

这里写图片描述

图1

先调用 SMenuEntryBlock::OnClicked ,然后调用UI_COMMAND(AddCodeToProject) —-> FMainFrameActionCallbacks::AddCodeToProject(),—-> OpenAddCodeToProjectDialog来打开基类选择界面。

2. 点击Create Class按钮

这里写图片描述

图2

OnFinished(this, &SNewClassDialog::FinishClicked)

调用函数SNewClassDialog::FinishClicked()—>AddCodeToProject —>GameProjectUtils::AddCodeToProject_Internal(核心都在这里实现)

3. 头文件生成

拼接文件路径信息,GameProjectUtils::GenerateClassHeaderFile来生成头文件的内容。

FinalOutput = "

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "GameFramework/Pawn.h"
#include "MyPawn.generated.h"

UCLASS()
class HOWTO_VTE_API AMyPawn : public APawn
{
    GENERATED_BODY()

public:
    // Sets default values for this pawn's properties
    AMyPawn();

protected:
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;

public: 
    // Called every frame
    virtual void Tick(float DeltaTime) override;

    // Called to bind functionality to input
    virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;



};
"

4. 生成CPP文件

GenerateClassCPPFile

CPP = // Fill out your copyright notice in the Description page of Project Settings.

#include "HowTo_VTE.h"
#include "MyPawn.h"


// Sets default values
AMyPawn::AMyPawn()
{
    // Set this pawn to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    PrimaryActorTick.bCanEverTick = true;

}

// Called when the game starts or when spawned
void AMyPawn::BeginPlay()
{
    Super::BeginPlay();
    %CURSORFOCUSLOCATION%
}

// Called every frame
void AMyPawn::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);

}

// Called to bind functionality to input
void AMyPawn::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
    Super::SetupPlayerInputComponent(PlayerInputComponent);

}

5. 编译

检测是否可避免全部编译工程,自动热加载,代码首次编译,RecompileModule —>
CheckForFinishedModuleDLLCompile

这里写图片描述

图3

6. 工程重新加载。

代码生成完毕。

二、 一张图

这里写图片描述

图4

一图千言

三、 文件生成模板

UE4 代码写的很精妙!

看模板头文件生成:

FString FinalOutput = Template.Replace(TEXT("%COPYRIGHT_LINE%"), *MakeCopyrightLine(), ESearchCase::CaseSensitive);
    FinalOutput = FinalOutput.Replace(TEXT("%UNPREFIXED_CLASS_NAME%"), *UnPrefixedClassName, ESearchCase::CaseSensitive);
    FinalOutput = FinalOutput.Replace(TEXT("%CLASS_MODULE_API_MACRO%"), *ModuleAPIMacro, ESearchCase::CaseSensitive);
    FinalOutput = FinalOutput.Replace(TEXT("%UCLASS_SPECIFIER_LIST%"), *MakeCommaDelimitedList(ClassSpecifierList, false), ESearchCase::CaseSensitive);
    FinalOutput = FinalOutput.Replace(TEXT("%PREFIXED_CLASS_NAME%"), *PrefixedClassName, ESearchCase::CaseSensitive);
    FinalOutput = FinalOutput.Replace(TEXT("%PREFIXED_BASE_CLASS_NAME%"), *PrefixedBaseClassName, ESearchCase::CaseSensitive);
    FinalOutput = FinalOutput.Replace(TEXT("%EVENTUAL_CONSTRUCTOR_DECLARATION%"), *EventualConstructorDeclaration, ESearchCase::CaseSensitive);
    FinalOutput = FinalOutput.Replace(TEXT("%CLASS_PROPERTIES%"), *ClassProperties, ESearchCase::CaseSensitive);
    FinalOutput = FinalOutput.Replace(TEXT("%CLASS_FUNCTION_DECLARATIONS%"), *ClassFunctionDeclarations, ESearchCase::CaseSensitive);
    FinalOutput = FinalOutput.Replace(TEXT("%BASE_CLASS_INCLUDE_DIRECTIVE%"), *BaseClassIncludeDirective, ESearchCase::CaseSensitive);

CPP文件也类似的。

其中,Tmplate得到是某个继承类的模板字符串,然后通过特定符号来进行替换,生成文件。

模板文件的路径在:UE4_source\UnrealEngine\Engine\Content\Editor\Templates\

比如测试的继承基类为Pawn,他们的模板头文件和CPP文件分别为: PawnClass.h.template 和PawnClass.cpp.template 。
可以自行打开和修改文件。

PawnClass.h.template

%COPYRIGHT_LINE%

#pragma once
%BASE_CLASS_INCLUDE_DIRECTIVE%
#include "%UNPREFIXED_CLASS_NAME%.generated.h"

UCLASS(%UCLASS_SPECIFIER_LIST%)
class %CLASS_MODULE_API_MACRO%%PREFIXED_CLASS_NAME% : public %PREFIXED_BASE_CLASS_NAME%
{
    GENERATED_BODY()

public:
    // Sets default values for this pawn's properties
    %PREFIXED_CLASS_NAME%();

protected:
    // Called when the game starts or when spawned
    virtual void BeginPlay() override;

public: 
    // Called every frame
    virtual void Tick(float DeltaTime) override;

    // Called to bind functionality to input
    virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;

    %CLASS_FUNCTION_DECLARATIONS%
    %CLASS_PROPERTIES%
};

PawnClass.cpp.template

%COPYRIGHT_LINE%

#include "%MODULE_INCLUDE_PATH%"
#include "%UNPREFIXED_CLASS_NAME%.h"
%ADDITIONAL_INCLUDE_DIRECTIVES%

// Sets default values
%PREFIXED_CLASS_NAME%::%PREFIXED_CLASS_NAME%()
{
    // Set this pawn to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
    PrimaryActorTick.bCanEverTick = true;

}

// Called when the game starts or when spawned
void %PREFIXED_CLASS_NAME%::BeginPlay()
{
    Super::BeginPlay();
    %CURSORFOCUSLOCATION%
}

// Called every frame
void %PREFIXED_CLASS_NAME%::Tick(float DeltaTime)
{
    Super::Tick(DeltaTime);

}

// Called to bind functionality to input
void %PREFIXED_CLASS_NAME%::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
    Super::SetupPlayerInputComponent(PlayerInputComponent);

}

%ADDITIONAL_MEMBER_DEFINITIONS%

是不是可以自定义头文件呢,估计可以。暂时没有研究。

UE4 工程量太大了,什么样脑子才能架构这玩意啊,他们都是天才!


paragon

UE4Paragon游戏人物截图!

谢谢浏览,欢迎点赞!!!

猜你喜欢

转载自blog.csdn.net/cartzhang/article/details/73189272