1. 程式人生 > >UE4反射機制UCLASS() USTRUCT() GENERATED_BODY() UPROPERTY() UFUNCTION()

UE4反射機制UCLASS() USTRUCT() GENERATED_BODY() UPROPERTY() UFUNCTION()

遊戲性類使用特殊的標記。因此在開始瞭解它們之前,我們有必要了解虛幻屬性系統的一些基礎知識。UE4 使用其自身的反射實現,可啟用動態功能,如垃圾回收、序列化、網路複製和藍圖/C++ 通訊。這些功能為選擇加入,意味著您需要為型別新增正確的標記,否則引擎將無視型別,不生成反射資料。以下是基礎標記的快速總覽:

  • UCLASS() - 告知虛幻引擎生成類的反射資料。類必須派生自 UObject。

  • USTRUCT() - 告知虛幻引擎生成結構體的反射資料。

  • GENERATED_BODY() - UE4 使用它替代為型別生成的所有必需樣板檔案程式碼。

  • UPROPERTY() - 使 UCLASS 或 USTRUCT 的成員變數可用作 UPROPERTY。UPROPERTY 用途廣泛。它允許變數被複制、被序列化,並可從藍圖中進行訪問。垃圾回收器還使用它們來追蹤對 UObject 的引用數。

  • UFUNCTION() - 使 UCLASS 或 USTRUCT 的類方法可用作 UFUNCTION。UFUNCTION 允許類方法從藍圖中被呼叫,並在其他資源中用作 RPC。

以下是 UCLASS 的聲明範例:

#include"MyObject.generated.h"

UCLASS(Blueprintable)classUMyObject:publicUObject{
    GENERATED_BODY()public:MyUObject();

    UPROPERTY(BlueprintReadOnly,EditAnywhere)floatExampleProperty
; UFUNCTION(BlueprintCallable)voidExampleFunction();};

首先注意 - “MyClass.generated.h”檔案已包含。虛幻引擎將生成所有反射資料並將放入此檔案。必須在宣告型別的標頭檔案中將此檔案作為最後的 include 包含。

您還會注意到,可以在標記上新增額外的說明符。此處已新增部分常用說明符用於展示。通過說明符可對型別擁有的特定行為進行說明。

  • Blueprintable - 此類可由藍圖延展。

  • BlueprintReadOnly - 此屬性只可從藍圖讀取,不可寫入。

  • Category - 定義此屬性出現在編輯器 Details 檢視下的部分。用於組織。

  • BlueprintCallable - 可從藍圖呼叫此函式。

    使屬性出現在編輯器中

    類建立好之後,現在即可建立一些屬性(設計師可在虛幻編輯器中設定這些屬性)。使用特殊巨集 UPROPERTY() 即可輕鬆將屬性公開到編輯器。只需在屬性宣告之前使用UPROPERTY(EditAnywhere) 巨集即可,如以下類所示。

    UCLASS()classAMyActor:publicAActor{
        GENERATED_BODY()
    
        UPROPERTY(EditAnywhere)
        int32 TotalDamage;...};

    執行這些操作後,即可在編輯器中對數值進行編輯。有多種方式控制其編輯方法和位置。為 UPROPERTY() 巨集傳入更多資訊可完成此操作。例如:如需 TotalDamage 屬性和相關屬性出現在一個部分中,可使用分類功能。以下屬性宣告對此進行演示。

    UPROPERTY(EditAnywhere,Category="Damage")
    int32 TotalDamage;

    使用者需要編輯此屬性時,它將和其他屬性(這些屬性已以此型別命名標記)一同出現在 Damage 標題之下。這可將常用設定放置在一起,便於設計師進行編輯。

    現在讓我們將相同屬性對藍圖公開。

    UPROPERTY(EditAnywhere,BlueprintReadWrite,Category="Damage")
    int32 TotalDamage;

    如您所見,存在一個藍圖特有的引數。正是此引數使屬性為可讀取和可編寫狀態。還存在一個單獨選項 - BlueprintReadOnly。可通過此選項使屬性在藍圖中被識別為常量。此外還有多個選項可控制屬性對引擎公開的方式

    跨 C++ 和藍圖邊界呼叫函式

    我們已經談到如何對藍圖公開屬性,在深入探索引擎之前還有最後一個需要介紹的要點。在遊戲性系統的建立中,設計師需要呼叫 C++ 程式設計師建立的函式,而遊戲性程式設計師需要從 C++ 程式碼呼叫藍圖中實現的函式。首先,我們先實現從藍圖中呼叫 CalculateValues() 函式。對藍圖公開函式和公開屬性同樣簡單。在函式宣告前放置一個巨集即可!以下程式碼片段顯示了所需內容。

    UFUNCTION(BlueprintCallable,Category="Damage")voidCalculateValues();

    UFUNCTION() 巨集把 C++ 函式對反射系統公開。BlueprintCallable 選項將其對藍圖虛擬機器公開。每個對藍圖公開的函式都需要與其相關的型別,右鍵單擊快捷選單才能正常使用。下圖顯示了型別對快捷選單的影響。

    image alt text

    如您所見,可從 Damage 型別選擇函式。以下藍圖程式碼顯示 TotalDamage 數值發生變化後將進行呼叫,重新計算依賴資料。

    image alt text

    計算依賴屬性使用的函式與之前新增的函式相同。引擎的大部分通過 UFUNCTION() 巨集對藍圖公開,開發者無需編寫 C++ 程式碼即可構建遊戲。然而,最佳方法是使用 C++ 構建基礎遊戲性系統和與效能關係密切的程式碼,而藍圖則用於自定義行為或從 C++ 構建塊建立合成行為。

    實現設計師呼叫 C++ 程式碼的操作後,我們來尋找一個越過 C++/藍圖邊界的好方法。此方法允許 C++ 程式碼呼叫藍圖中定義的函式。通常使用此方法告知設計師在適當時可進行反饋的事件。通常這包括特效生成或其他視覺效果,如 actor 的隱藏和現身。以下程式碼片段顯示藍圖實現的函式。

    UFUNCTION(BlueprintImplementableEvent,Category="Damage")voidCalledFromCpp();

    此函式的呼叫方式和其他 C++ 函式相同。虛幻引擎在後臺生成一個基礎 C++ 函式實現;它理解如何調入藍圖 VM。這通常被稱作 Thunk(形實轉換程式)。如討論中的藍圖不為此方法提供函式主體,函式的行為則與不含主體行為的 C++ 函式一樣:不執行任何操作。如果希望提供 C++ 預設實現,同時仍允許藍圖覆寫此方法,結果會怎樣?UFUNCTION() 巨集也擁有針對此情況的選項。以下程式碼片段顯示達成此效果需要在頭中進行的的變更。

    UFUNCTION(BlueprintNativeEvent,Category="Damage")voidCalledFromCpp();

    此版本仍然生成 thunking 法,以調入藍圖 VM。那麼如何提供預設實現呢?工具還將生成外觀與 _Implementation() 相似的新函式實現。您必須提供函式的這個版本,否則專案將無法連結。以下是上方宣告的實現程式碼。

    voidAMyActor::CalledFromCpp_Implementation(){// 玩點花活}

    現在,討論中的藍圖不覆寫方法時將呼叫函式的這個版本。需要注意:在編譯工具的舊版本中,_Implementation() 宣告為自動生成。在 4.8 或更高版本中,這會被顯式新增到頭中。