본문 바로가기
Engine/Unreal

UMG(Unreal Motion Graph)

by 뇌 속의 통 2024. 11. 19.

UMG란?

Unreal Motion Graph의 약자로 게임 내 HUD, 기타 인터페이스 관련 그래픽 요소로 UI 제작 툴이다.

UMG의 핵심에는 Widget이라는 것이 있는데 이는 미리 만들어진(Button, Textbox 등) 함수 시리즈로

이들을 조립해서 UI를 만들 수 있다.

 

쉽게 UI를 만들기 위한 Module이다.

UMG를 사용하기 위해선 UMG Module을 추가해야한다.

 

Module 추가는 프로젝트명.Build.cs 파일에서 가능하다.

 

using UnrealBuildTool;

public class VampireSurvival : ModuleRules
{
	public VampireSurvival(ReadOnlyTargetRules Target) : base(Target)
	{
		PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;
	
		PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", 
        "Engine", "EnhancedInput", "UMG" });

		PrivateDependencyModuleNames.AddRange(new string[] {  });
	}
}

 

Widget 생성

#pragma once

#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "MainMenuUserWidget.generated.h"

UCLASS()
class THEGENIUSPLAN_API UMainMenuUserWidget : public UUserWidget
{
	GENERATED_BODY()

public:

	virtual void NativeConstruct() override;
	
	UFUNCTION(BlueprintCallable)
	void TestFunction();
	
protected:
	
	UPROPERTY(BlueprintReadWrite, meta = (BindWidget))
	//meta = (BindWidget) 키워드를 넣어 해당 Object가 상속 받아 생성할 Widget과 연결되도록 한다.
	TObjectPtr<class UButton> Button_Login;

	UPROPERTY(BlueprintReadWrite, meta = (BindWidget))
	TObjectPtr<class UButton> Button_SignUp;

	UPROPERTY(BlueprintReadWrite, meta = (BindWidget))
	TObjectPtr<class UButton> Button_Quit;
};

 

사용할 Widget Class를 생성 및 넣은 UI의 Type에 따라 변수를 추가해주어야한다.

 

#include "TheGeniusPlan/Widget/MainMenuUserWidget.h"
#include "Components/Button.h"

void UMainMenuUserWidget::NativeConstruct()
{
	Super::NativeConstruct();

	if(Button_Login)
	{
		Button_Login->OnClicked.AddDynamic(this, &UMainMenuUserWidget::TestFunction);
		//Button의 OnClicked Event함수를 TestFunction으로 Bind해준다.
	}
}

void UMainMenuUserWidget::TestFunction()
{
	UE_LOG(LogTemp, Error, TEXT("User Clicked LoginButton!"));
}

 

이제 앞서 생성한 C++을 상속 받아 새로운 Blue Print Class를 만든다.

우리가 meta = bindwidget으로 설정한 변수와 일치하는 변수가 반드시 해당 Widget에 있어야 Widget 컴파일이 정상적으로 작동한다.

 

 

HUD 정의

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/HUD.h"
#include "MainMenuHUD.generated.h"

UCLASS()
class THEGENIUSPLAN_API AMainMenuHUD : public AHUD
{
	GENERATED_BODY()

public:
	AMainMenuHUD();

protected:

	//widget class를 가져올 변수 선언
	UPROPERTY(EditDefaultsOnly, BlueprintReadWrite, Category = "WidgetClass")
	TSubclassOf<class UMainMenuUserWidget> MainMenuWidgetClass;
	
	//widget을 저장할 변수 선언
	UPROPERTY(BlueprintReadWrite, Category = "WidgetClass")
	TObjectPtr<class UMainMenuUserWidget> MainMenuWidget;

	virtual void BeginPlay() override;

};

 

#include "TheGeniusPlan/GameModes/MainMenuHUD.h"
//Widget Class에 대한 정의가 있는 Header file Include
#include "Blueprint/UserWidget.h"
//우리가 만들 Widget Class의 Header file
#include "TheGeniusPlan/Widget/MainMenuUserWidget.h"

AMainMenuHUD::AMainMenuHUD()
{
	//우리가 만들 Widget의 Class를 가져와 저장한다.
	//Blue Print로 만든 Class이므로 뒤에 _C를 붙여준다.
	static ConstructorHelpers::FClassFinder<UMainMenuUserWidget> WG_MainMenuWidget(TEXT("/Script/UMGEditor.WidgetBlueprint'/Game/Mainmenu/Widget/WG_MainMenu.WG_MainMenu_C'"));
	
	//정상적으로 가져왔다면 변수에 해당 class를 대입한다.
	if (WG_MainMenuWidget.Succeeded())
	{
		MainMenuWidgetClass = WG_MainMenuWidget.Class;
	}
}

void AMainMenuHUD::BeginPlay()
{
	Super::BeginPlay();
	
	//Widget의 Class를 바탕으로 Create Widget을 해준다.
	//반환된 값은 일반 UUserWidget Type이므로 형변환하여 저장한다.
	MainMenuWidget = Cast<UMainMenuUserWidget>(CreateWidget(GetWorld(), MainMenuWidgetClass));

	//정상적으로 저장되었다면 해당 Widget을 Viewport에 띄운다.
	if (MainMenuWidget)
	{
		MainMenuWidget->AddToViewport();
	}
	

}

 

위와 같이 HUD에서 해당 Widget을 생성 및 View port에 띄워주도록 한다.

마지막으로 Game Mode에서 HUD class를 우리가 만든 HUD Static class로 대입하면 정상적으로 Widget이 생성되는 것을 볼 수 있다.

 

우리가 Bind한 함수도 정상적으로 출력되는 것을 볼 수 있다.

 

기타

1. UI는 기본적으로 C++ 생성자로 동작하지 않음.

  • UUserWidget과 같은 Widget Class는 UObject기반 Class와 객체 초기화 방식이 다르기 때문
  • UI는 기본적으로 Blue Print를 통해 생성되기 때문에 설정도 Blue Print를 기반으로 설정된다.
  • 그래서 생성자를 이용할 수 없으며, 생성된 이후 호출되는 NativeConstruct() 함수 또는 Beginplay() 함수를 재정의하여 구현한다.