UE4入門學習4:C++編程介紹


- -
文章 UE4入門學習4:C++編程介紹
作者 游藍海( http://blog.csdn.net/you_lan_hai )

UE4直接使用C++作為邏輯層語言,這樣引擎層與邏輯層語言統一,不需要膠水代碼去轉發,消除了邏輯層和引擎層的交互成本。為了便於開發,UE4對C++做了一些包裝,比如反射和垃圾回收,大大減輕C++開發的難度。本文結合UE4官方C++編程指南文檔,對C++相關特性做一些描述和總結。

反射

C++本來是不支持反射的,只有一個基本的RTTI(運行時類型信息)特性,僅能在運行時獲取對象的類型信息,無法得到成員變量和函數列表信息。如果我們要對成員變量進行序列化(存檔/讀檔),需要自己寫很多輔助的讀取和寫入方法,非常麻煩。

UE4在C++編譯開始前,使用工具UnrealHeaderTool,對C++代碼進行預處理,收集出類型和成員等信息,並自動生成相關序列化代碼。然后再調用真正的C++編譯器,將自動生成的代碼與原始代碼一並進行編譯,生成最終的可執行文件。這個過程類似於Qt的qmake預處理機制。

拿出我們之前工程的代碼來分析:

// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "GameFramework/Actor.h"
#include "MyActor.generated.h"

UCLASS()
class HELLOUE4_API AMyActor : public AActor
{
    GENERATED_BODY()
public: 
    // 默認構造函數,初始化一些成員屬性。
    AMyActor();
protected:
    // 游戲開始或者被創建出來后調用。
    virtual void BeginPlay() override;
public: 
    // 每幀都會被調用
    virtual void Tick(float DeltaTime) override;

    // 這個變量會出現在編輯器編輯界面。
    UPROPERTY(EditAnywhere)
    int32   MyID;

private:
    // 這是個內部變量。不會出現在編輯器界面。
    float RunningTime;
};

這個代碼文件包含了一些特殊的頭文件和宏,下面逐一介紹:

名稱 描述
MyActor.generated.h 這個文件是UE4自動生成的,里面存貯了UE4收集的類型信息。
UCLASS 告訴UE4這個類需要收集類型信息
UPROPERTY 告訴UE4這個成員變量的信息需要被收集
GENERATED_BODY 告訴UE4自動生成的代碼注入在這里

以下是MyActor.generated.h中的部分代碼:

#define HelloUE4_Source_HelloUE4_MyActor_h_9_INCLASS_NO_PURE_DECLS \
    private: \
    static void StaticRegisterNativesAMyActor(); \
    friend HELLOUE4_API class UClass* Z_Construct_UClass_AMyActor(); \
    public: \
    DECLARE_CLASS(AMyActor, AActor, COMPILED_IN_FLAGS(0), 0, TEXT("/Script/HelloUE4"), NO_API) \
    DECLARE_SERIALIZER(AMyActor) \
    /** Indicates whether the class is compiled into the engine */ \
    enum {IsIntrinsic=COMPILED_IN_INTRINSIC};

實際上,GENERATED_BODY這個宏最終展開后就對應了宏HelloUE4_Source_HelloUE4_MyActor_h_9_INCLASS_NO_PURE_DECLS,也就是說自動生成的代碼會在C++編譯的時候注入到了類AMyActor中。

注意,如果聲明變量或類型不加上前綴,是不會生成類型信息的。下面是一些基本的類型標記:

  • UCLASS() - 告訴UE4生成類的反射數據。類必須派生自 UObject。
  • USTRUCT() - 告訴UE4生成結構體的反射數據。
  • UENUM() - 告訴UE4生成枚舉的反射數據。
  • GENERATED_BODY() - UE4 使用它替代為類型生成的所有必需樣板文件代碼。
  • UPROPERTY() - 使 UCLASS 或 USTRUCT 的成員變量可用作 UPROPERTY。UPROPERTY 用途廣泛。它允許變量被復制、被序列化,並可從藍圖中進行訪問。垃圾回收器還使用它們來追蹤對 UObject 的引用數。
  • UFUNCTION() - 使 UCLASS 或 USTRUCT 的類方法可用作 UFUNCTION。UFUNCTION 允許類方法從藍圖中被調用,並在其他資源中用作 RPC。

序列化

有了反射功能之后,成員變量的序列化也就更方便了。UE4收集了每個類成員的類型信息,這樣存檔和讀檔時,根據名稱和類型就可以自動完成了,整個過程不需要人工干預。

需要序列化的成員變量,需要在變量聲明的時候在前面加上UPROPERTY()宏,宏參數有很多,分別表示變量的詳細屬性,下面列舉一些常用的:

UPROPERTY參數 說明
EditAnywhere 表示該屬性可從編輯器內的屬性窗口編輯。
Category 定義屬性的分類。使用方法: Category=CategoryName. (分類=分類名稱)
Const 編輯器中不能修改該值
BlueprintReadOnly 在藍圖中只讀,不可修該。
BlueprintReadWrite 在藍圖中可讀寫。
BlueprintCallable 僅能用於Multicast代理。該代理可被藍圖調用。

UPROPERTY對應的還有一個用於修飾函數的宏UFUNCTION,該宏常用於描述如何從藍圖中訪問C++的函數。

UFUNCTION參數 說明
BlueprintCallable 這種類型的函數,只能在C++中實現和重寫。可以理解為藍圖“只讀”函數。
BlueprintImplementableEvent 只能在藍圖中實現的函數。類似於C++的純虛函數
BuleprintNativeEvent C++可以提供默認實現,藍圖可以重寫。

熱重載

在編輯器模式下,UE4將工程代碼編譯成動態鏈接庫,這樣編輯器可以動態的加載和卸載某個動態鏈接庫。UE4為工程自動生成一個cpp文件(本工程為HelloUE4.generated.cpp),cpp文件包含了當前工程中所有需要反射的類信息,以及類成員列表和每個成員的類型信息。在動態鏈接庫被編輯器加載的時候,自動將類信息注冊到編輯器中。反之,卸載的時候,這樣類信息也會被反注冊。

在開發的過程中,當我們編譯完成工程的時候,UE4編輯器會自動檢測動態鏈接庫的變化,然后自動熱重載這些動態鏈接庫中的類信息。

垃圾回收

有了反射機制,UE4也能夠知道哪些類型是指針類型,以及哪些變量需要被垃圾收集系統管理。被垃圾收集系統管理的對象,不需要手動調用delete,只需要正確的維持變量的引用即可。我沒有看過UE4垃圾收集系統實現源碼,姑且將UE4的垃圾收集系統看成是一個使用了“標記-清掃”算法的一個沙盒,當不需要使用某個指針變量的時候,我們只需要把他置為NULL,在下個垃圾回收階段中,系統會自動回收。

使用垃圾回收的時候,需要遵從一定的規范:

  • 所有需要被托管的成員變量需要用宏UPROPERTY()標記
  • 所有從UObject派生的類,才能被系統托管。非UObject派生的類可以考慮從類FGCObject派生,並實現AddReferencedObjects方法,或者使用智能指針
  • 數組TArray的UObject類型指針元素,可以被自動托管
  • Actor類型對象在不用的時候,需要手動調用Destroy。調用Destroy后不會立即消耗,也會等待下個垃圾回收階段

編碼規范

類名前綴

UE4的類名必須遵從命名規范,需要在類名前面加上正確的前綴,與之對應的C++文件名則不加前綴。否則會編譯報錯。

  • 派生自 Actor 的類前綴為 A,如 AController。
  • 派生自 UObject 的類前綴為 U,如 UComponent。
  • 枚舉 的前綴為 E,如 EFortificationType。
  • 接口 類的前綴通常為 I,如 IAbilitySystemInterface。
  • 模板 類的前綴為 T,如 TArray。
  • 派生自 SWidget(Slate UI)的類前綴為 S,如 SButton。
  • 其余類的前綴均為 字母 F ,如 FVector。

其他類型命名

bool類型變量需要加上b前綴,如 bCallable。

參考

  1. UE4 中的 C++ 編程介紹
    https://docs.unrealengine.com/latest/CHN/Programming/Introduction/index.html
  2. UE4 編碼規范
    https://docs.unrealengine.com/latest/CHN/Programming/Development/CodingStandard/index.html


本系列文章會和我的個人公眾號同步更新,感興趣的朋友可以關注下我的公眾號:游戲引擎學習。掃下面的二維碼加關注:

游戲引擎學習


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM