UE4 c++ -- 簡單的UMG

XTG111發表於2024-03-23

說明

學習一下如何將Widget藍圖與C++連線起來,將處理邏輯寫在C++中

基礎

在藍圖中,我們顯示Widget是透過一個Actor或者PlayerController,甚至關卡藍圖,利用Create Widget以及 AddToViewPort使得Widget顯示在螢幕上的
image
所以在C++中也是一樣,一般來說由於Actor的銷燬比如角色死亡,會導致其所有處理邏輯從記憶體中清除掉。所以將這個功能寫在PlayerController類裡。
現在為了演示,直接建立了一個Actor類和一個UserWidget類。

Actor類

其主要作用就是顯示這個UMG介面,在.h檔案中需要一個UserWidget類的指標,用來儲存Create出來的物件。相當於上圖中的那個變數
然後還需要接受一個類,一般透過TSubClassOf宣告,然後在引擎中選擇由UserWidget類建立好的藍圖類。相當於上圖中CreateWidget模組的Class

//.h
public:
	UPROPERTY()
		class UXDebugMenuWidget* XDebugMenu;

	UPROPERTY(EditAnywhere, Category = "Debug")
		TSubclassOf<class UUserWidget> DebugMenuWdgClass;

在.cpp檔案中就主要來實現上圖中的邏輯

//.cpp
//Create Widget
XDebugMenu = CreateWidget<UXDebugMenuWidget>(GetWorld(), DebugMenuWdgClass);
if (XDebugMenu)
{
	XDebugMenu->AddToViewport();
}

CreateWidget函式

在原始碼中其為一個函式模板,

template <typename WidgetT = UUserWidget, typename OwnerT = UObject>
WidgetT* CreateWidget(OwnerT* OwningObject, TSubclassOf<UUserWidget> UserWidgetClass = WidgetT::StaticClass(), FName WidgetName = NAME_None)
{
	static_assert(TIsDerivedFrom<WidgetT, UUserWidget>::IsDerived, "CreateWidget can only be used to create UserWidget instances. If creating a UWidget, use WidgetTree::ConstructWidget.");
	
	static_assert(TIsDerivedFrom<OwnerT, UWidget>::IsDerived
		|| TIsDerivedFrom<OwnerT, UWidgetTree>::IsDerived
		|| TIsDerivedFrom<OwnerT, APlayerController>::IsDerived
		|| TIsDerivedFrom<OwnerT, UGameInstance>::IsDerived
		|| TIsDerivedFrom<OwnerT, UWorld>::IsDerived, "The given OwningObject is not of a supported type for use with CreateWidget.");

	SCOPE_CYCLE_COUNTER(STAT_CreateWidget);

	if (OwningObject)
	{
		return Cast<WidgetT>(UUserWidget::CreateWidgetInstance(*OwningObject, UserWidgetClass, WidgetName));
	}
	return nullptr;
}

可以看到有兩個資訊

  1. 該函式只能建立UserWidget 對於UWidget需要其他函式
  2. OwingObject的型別只能是UWidget UWidgetTree APlayerController UGameInstance UWorld其中的一種,其他的型別無法呼叫該函式
    所以當在Actor呼叫該函式生成Widget的時候,可以利用GetWorld()來得到UWorld類的引數,如果在PlayerController類中直接使用this指標即可

UserWidget類

參考
該類主要是處理UMG在藍圖中的邏輯。需要注意到點就是每個控制元件的宣告是有嚴格的要求的,以Button控制元件為例

UPROPERTY(meta = (BindWidget))
	class UButton* Button_Tab1;
  1. UPROPERTY(meta = (BindWidget))
    BindWidget是一組專門用來繫結Button這些控制元件的列舉值中的一個UE官方文件
  2. 變數名稱:C++中控制元件的名稱必須和藍圖中一樣
  3. 用BindWidget標記過的 widget 在 C++ 建構函式中為空,它們稍後在生命週期中被初始化。如果您需要進行類似建構函式的設定,請使用該NativeConstruct()函式。
  4. 對於按鈕響應,可以呼叫官方設定好的委託函式廣播即可OnClicked.AddDynamic(this,&Func);

使用HUD

使用HUD可以對一個GameMode設定使用一種UMG顯示
image
GameMode是控制整個遊戲的規則,相當於一種最高許可權,可以設定玩家的控制器型別,預設角色型別,HUD型別等等。
當我們將將Widget放在HUD裡面是,我們就可以透過GameMode來控制一些數值的顯示,實際上是透過PlayerController來更改HUD的
可以將HUD理解為多個Widget的集合,我們將在HUD類裡實現在Actor類中的建立Widget的操作。程式碼都是一樣的,只不過OwingObject的型別我們需要修改為PlayerController,因為對於HUD類來說沒有GetWorld物件,但其受到每個玩家控制器的控制,具有GetOwningPlayerController()函式來獲取PlayerController。
然後就可以在PlayerController類裡面使用HUD類物件呼叫HUD中的方法實現UMG的顯示了。

相關文章