0. Slate

Slate는 Unreal Engine의 C++ 기반 저수준 UI 프레임워크다. 모든 Slate 위젯은 SWidget 클래스를 부모로 갖는다.

항목 설명
목적 고성능, 저수준 UI 렌더링
기반 구조 SWidget 기반(Non-UObject, 경량 구조)
제작 방법 순수 C++ 코드로 구성
사용 예 커스텀 위젯, 에디터 UI, 성능이 중요한 UI 등
관리 방식 직접 메모리 관리(SharedPtr 기반)
이벤트 Slate Event(OnClicked, OnMouseDown) 등
성능 UMG에 비해 가볍고 빠름

0-1. Slate의 기본 구조

Slate는 아래처럼 C++에서 직접 위젯을 생성 및 구성한다.

TSharedRef<SVerticalBox> MySlateUI =
	SNew(SVerticalBox)
	+ SVerticalBox::Slot()
	.AutoHeight()
	[
		SNew(STextBlock)
		.Text(FText::FromString("Hello, Slate!"))
	]
	+ SVerticalBox::Slot()
	.AutoHeight()
	[
		SNew(SButton)
		.Text(FText::FromString("Click Me"))
		.OnClicked(this, &MyClass::OnClickButton)
	];

SNew, Slot(), [] 등의 구문은 Slate 고유 문법이다.

0-2. Slate 특징

항목 설명
SWidget 모든 Slate 위젯의 부모 클래스(텍스트, 버튼 등 전부 상속)
TSharedRef, TSharedPtr 메모리 관리용 스마트 포인터 사용(GC 아님)
SNew 매크로 Slate 위젯을 선언적으로 생성
이벤트 바인딩 OnClicked, OnMouseEnter 등 함수 포인터 방식
스타일 FSlateStyleSet, FSlateBrush, FSlateFontInfo 등을 통한 커스터마이징

1. UMG(Unreal Motion Graphics)

Slate를 Blueprint-friendly하게 감싼 고수준 UI 시스템이다. UUserWidget은 내부적으로 SWidget들이 실제 렌더링을 처리한다.

항목 설명
목적 사용자 친화적인 UI 제작(디자이너, BP)
기반 구조 UObject 기반(UUserWidget)
제작 방법 에디터 + 블루프린트 + 일부 C++
사용 예 인벤토리, HUD, 메뉴 등 대부분 UI
관리 방식 GC 대상(UObject)
이벤트 BindWidget, BP Event, UFUNCTION 등
성능 Slate에 비해 무거움

1-1. 구성 요소

구성 설명
UUserWidget UI 화면을 표현하는 가장 기본 단위 클래스
CanvasPanel, VerticalBox 레이아웃 위젯
Button, TextBlock, Image 시각적 위젯
Blueprint Widget UUserWidget을 상속한 에디터 기반 블루프린트 UI

1-2. 동작 방식

  1. C++로 UUserWidget을 상속받은 클래스를 만든다.
  2. 에디터에서 그걸 상속받은 위젯 블루프린트를 만들어 UI를 구성한다.
  3. C++ 또는 블루프린트에서 이 위젯을 CreateWidget()이나 UWidgetComponent로 생성 또는 GetWidgetFromName() 함수를 통해 위젯을 찾아 화면에 표시한다.

UUserWidget 클래스를 상속받아 블루프린트로 만든 UI를 어떻게 다시 C++ 코드에서 GetWidgetFromName()함수를 통해 얻어올 수 있을까? 이를 이해하려면 Widget Tree를 알아야 한다.

1-3. Widget Tree

UUserWidget 내부에 자동 생성되는 트리 구조의 위젯 계층이다. 모든 자식 위젯(Button, TextBlock 등)은 Widget Tree에 등록된다. GetWidgetFromName()은 이 WidgetTree 안에서 위젯을 찾는다.

에디터에서 구성한 UI 요소들은 부모 C++ 클래스가 아닌 해당 블루프린트 인스턴스의 WidgetTree에 들어가며, C++ 코드에서 GetWidgetFromName()으로 접근할 수 있는 이유가 바로 이것이다.

에디터에서 위젯 블루프린트(BP)를 만들 때, 이 위젯 BP는 어떤 C++ 부모 클래스(ex. UMyUserWidget)를 상속받고 있다. BP 내부에서 Button, TextBlock 등 여러 위젯을 Designer탭에서 배치하면 이 UI 구성 정보는 BP 내부에 저장된다. 이후 런타임에서 CreateWidget()이나 WidgetComponent로 인스턴스화할 때, 이 구조가 부모 C++ 클래스의 인스턴스(ex. UMyUserWidget)의 WidgetTree에 담기게 된다. 따라서 GetWidgetFromName()은 반드시 실제 인스턴스가 생성된 뒤에 호출해야 한다.

구조 예시

UUserWidget (MyWidget)

  • CanvasPanel
    • TextBlock (TitleText)
    • Button (StartButton)
      • TextBlock (ButtonLabel)

이 모든 구조는 MyWidget->WidgetTree에 저장되어 있고, GetWidgetFromName(TEXT("StartButton"))으로 StartButton을 찾을 수 있다.

1-4. Panel

여러 자식 위젯을 담는 컨테이너 위젯이다(ex. CanvasPanel, VerticalBox, Overlay). Panel은 자식 위젯을 여러 개 가질 수 있는 부모 위젯이며, 레이아웃을 결정한다.

대표적인 Panel의 종류로는,

  1. CanvasPanel : 절대 좌표 배치(픽셀 단위 위치)
  2. VerticalBox : 위에서 아래로 차례대로 배치
  3. HorizontalBox : 왼쪽에서 오른쪽으로 배치
  4. Overlay : 자식 위젯을 겹쳐서 배치
  5. GridPanel : 행/열 격자 배치

등이 있다.

1-5. Slot

Slot은 패널이 각 자식 위젯에 대해 가지는 부가 정보이다(ex. UCanvasPanelSlot, UVerticalBoxSlot). 위치, 정렬, Padding 등 UI 배치를 제어하며, 패널 종류마다 대응되는 Slot 클래스가 다르다.

UButton* Button = WidgetTree->ConstructWidget<UButton>();

//패널에 추가 -> 해당 패널 전용 Slot이 반환됨
UCanvasPanelSlot* Slot = Cast<UCanvasPanelSlot>(Canvas->AddChild(Button));
if (Slot)
{
	Slot->SetPosition(FVector2D(100, 100));
	Slot->SetSize(FVector2D(200, 50));
}

Leave a comment