UMG 시스템 소개와 위젯 구조
이전 장에서 우리는 게임 월드 내의 오브젝트들이 서로 어떻게 상호작용하는지(충돌, 물리, 트레이스)에 대해 깊이 있게 알아보았습니다. 이제 게임플레이의 또 다른 핵심 요소인 사용자 인터페이스(UI) 에 대해 다룰 시간입니다. UI는 플레이어에게 정보를 전달하고, 입력을 받으며, 게임 세계와 상호작용할 수 있도록 돕는 시각적 요소들의 집합입니다. 언리얼 엔진은 강력하고 유연한 UI 시스템인 UMG (Unreal Motion Graphics) UI Designer를 제공합니다.
이번 절에서는 UMG 시스템이 무엇인지 소개하고, UMG UI를 구성하는 기본 단위인 위젯(Widget) 의 구조와 계층 관계에 대해 살펴보겠습니다.
UMG (Unreal Motion Graphics)?
UMG는 언리얼 엔진 4부터 도입된 선언적(Declarative) UI 디자인 시스템으로, 개발자가 코드를 직접 작성하는 대신 시각적인 도구(UMG UI Designer)를 사용하여 UI를 직관적으로 제작할 수 있도록 돕습니다. 웹 개발의 HTML/CSS와 유사하게, UMG는 미리 정의된 위젯들을 조합하여 복잡한 UI를 빠르고 효율적으로 만들 수 있게 합니다.
UMG의 주요 특징
- 시각적 디자인 도구: 언리얼 에디터 내에서 드래그 앤 드롭 방식으로 위젯을 배치하고 크기를 조절하며, 실시간으로 UI 레이아웃을 확인할 수 있습니다.
- 데이터 바인딩(Data Binding): 게임 내 변수(C++ 또는 블루프린트)와 UI 위젯의 속성(텍스트, 진행률 바 등)을 쉽게 연결하여 게임 상태가 변하면 UI가 자동으로 업데이트되도록 합니다.
- 애니메이션 시스템 통합: UI 요소에 부드러운 전환 효과나 시각적 피드백을 주기 위한 애니메이션을 내장된 애니메이션 시스템으로 제작할 수 있습니다.
- 블루프린트 지원: UI 로직을 블루프린트 비주얼 스크립팅으로 쉽게 구현할 수 있으며, C++와의 연동도 유연하게 지원합니다.
- 확장성: 새로운 커스텀 위젯을 C++로 생성하고 UMG 시스템에 통합할 수 있습니다.
- 하드웨어 가속: GPU를 활용하여 고성능의 UI 렌더링을 제공합니다.
위젯 (Widget)이란?
위젯은 UMG UI의 가장 기본적인 구성 단위입니다. 버튼, 텍스트 블록, 이미지, 체크박스, 슬라이더 등 UI 화면에 보이는 모든 요소는 위젯입니다. 모든 위젯은 UWidget
클래스를 상속받으며, 이는 UObject
의 자식입니다.
위젯의 계층적 구조
UMG의 UI는 마치 웹 페이지의 HTML DOM(문서 객체 모델)이나 윈도우 운영 체제의 창 구조처럼 계층적인 트리 구조를 가집니다. 즉, 하나의 위젯이 여러 자식 위젯을 포함할 수 있으며, 이 자식 위젯들은 부모 위젯의 영역 내에서 배치됩니다.
- 루트 위젯 (Root Widget): 모든 UI의 최상단에 있는 위젯입니다. 일반적으로
UCanvasPanel
과 같은 레이아웃 위젯이 루트 위젯이 됩니다. - 패널 위젯 (Panel Widget): 자식 위젯들을 특정 규칙에 따라 배치하는 데 사용되는 위젯입니다. (예:
UCanvasPanel
,UHorizontalBox
,UVerticalBox
,UGridPanel
,UScrollBox
등) - 컨트롤 위젯 (Control Widget): 사용자 상호작용을 받거나 정보를 표시하는 개별 UI 요소입니다. (예:
UButton
,UTextBlock
,UImage
,UProgressBar
,USlider
등)
예시 계층 구조
- UMG_HUD (UserWidget)
- CanvasPanel (Root Widget, Panel Widget)
- VerticalBox (Panel Widget)
- TextBlock (PlayerName, Control Widget)
- ProgressBar (HealthBar, Control Widget)
- HorizontalBox (Panel Widget)
- Button (AttackButton, Control Widget)
- TextBlock (Button Text, Control Widget)
- Button (DefendButton, Control Widget)
- TextBlock (Button Text, Control Widget)
- Image (Crosshair, Control Widget)
이러한 계층 구조는 UI의 복잡성을 관리하고, 레이아웃을 유연하게 조정하며, 특정 위젯에만 영향을 미치는 애니메이션이나 상호작용을 구현하는 데 필수적입니다.
위젯 블루프린트 (UUserWidget
)
언리얼 에디터에서 우리가 직접 생성하고 디자인하는 UI는 실제로는 위젯 블루프린트(Widget Blueprint) 에셋입니다. 이 에셋은 C++의 UUserWidget
클래스를 상속받아 구현됩니다. UUserWidget
은 UMG 시스템의 핵심으로, UI를 화면에 표시하고, 상호작용 로직을 처리하며, 내부적으로 C++ 위젯 클래스들을 관리하는 역할을 합니다.
위젯 블루프린트 생성 및 구성
생성: 콘텐츠 브라우저에서 마우스 오른쪽 버튼 클릭 > User Interface
> Widget Blueprint
를 선택합니다. 이름을 지정합니다 (예: WBP_HUD
).
UMG UI Designer: 생성된 위젯 블루프린트를 더블 클릭하여 UMG UI Designer를 엽니다. 이 화면은 크게 다음 세 부분으로 나뉩니다.
- 팔레트(Palette): 사용할 수 있는 모든 기본 위젯 목록입니다. 여기서 원하는 위젯을 드래그 앤 드롭하여 디자인 화면에 추가합니다.
- 계층 구조(Hierarchy): 현재 UI를 구성하는 위젯들의 트리 구조를 보여줍니다. 부모-자식 관계를 시각적으로 파악하고, 위젯을 재정렬할 수 있습니다.
- 디자이너(Designer) 탭: 위젯들을 실제로 배치하고 레이아웃을 조절하는 시각적인 작업 공간입니다.
- 그래프(Graph) 탭: 위젯의 이벤트 처리 로직(클릭 시 동작, 데이터 업데이트 등)을 블루프린트 비주얼 스크립팅으로 구현하는 공간입니다.
위젯의 일반적인 속성 및 이벤트
모든 위젯은 공통적으로 가지는 속성들이 있습니다.
- 포지션(Position) 및 크기(Size): 화면에서의 위치와 크기를 정의합니다.
- 앵커(Anchors): 부모 위젯이나 화면의 특정 지점(코너, 중앙 등)에 위젯을 "고정"시켜 해상도 변화에 따라 자동으로 위치와 크기가 조절되도록 합니다. 반응형 UI 디자인에 필수적입니다.
- 패딩(Padding) 및 마진(Margin): 위젯 내부 콘텐츠와 테두리 간의 간격, 또는 위젯 외부의 다른 위젯과의 간격을 조절합니다.
- 가시성(Visibility): 위젯이 보이는지, 숨겨져 있는지, 아니면 아예 공간을 차지하지 않는지 등을 설정합니다.
- 상호작용 가능 여부(Is Enabled): 위젯이 사용자 입력을 받을 수 있는지 여부입니다.
- 이벤트(Events):
OnClicked
(버튼 클릭),OnHovered
(마우스 오버),OnTextChanged
(텍스트 변경) 등 사용자의 상호작용에 응답하는 다양한 이벤트들이 있습니다. 이러한 이벤트는 그래프 탭에서 블루프린트 노드로 연결하여 로직을 구현합니다.
C++와 UMG의 연동 기본
비록 UMG가 블루프린트 중심의 시각적 디자인을 지향하지만, 복잡한 로직이나 성능이 중요한 부분, 또는 재사용 가능한 기반 위젯은 C++로 구현하는 것이 효율적입니다.
- C++ 클래스 생성:
UUserWidget
을 상속받는 새로운 C++ 클래스를 생성할 수 있습니다 (예:UMyBaseHUDWidget
). - 블루프린트에서 상속: 이 C++ 클래스를 부모로 하는 위젯 블루프린트를 생성하여 디자이너가 시각적 요소를 추가하고 세부 로직을 구현하도록 합니다.
UPROPERTY
/UFUNCTION
: C++ 위젯 클래스 내에서UPROPERTY
와UFUNCTION
매크로를 사용하여 변수와 함수를 블루프린트에 노출함으로써, 블루프린트에서 C++ 로직에 접근하거나 C++ 데이터에 바인딩할 수 있게 합니다. 특히meta=(BindWidget)
지정자는 특정 UMG 위젯을 C++ 코드에서 직접 참조할 때 유용합니다. (다음 절에서 자세히 다룰 예정입니다.)
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "MyUserWidget.generated.h"
// UProgressBar를 사용하기 위해 포함
class UProgressBar;
class UTextBlock;
UCLASS()
class MYPROJECT_API UMyUserWidget : public UUserWidget
{
GENERATED_BODY()
public:
// 생성자나 BeginPlay에서 위젯들을 가져오지 않고,
// meta=(BindWidget)을 사용하여 위젯 블루프린트의 이름과 일치하는 UPROPERTY를 선언하면,
// 자동으로 해당 위젯 인스턴스가 바인딩됩니다.
// **위젯 블루프린트에서 해당 위젯의 IsVariable 체크박스를 반드시 활성화해야 합니다.**
UPROPERTY(meta = (BindWidget))
UProgressBar* HealthBar; // 위젯 블루프린트의 Progress Bar 위젯 이름이 'HealthBar'여야 함
UPROPERTY(meta = (BindWidget))
UTextBlock* PlayerNameText; // 위젯 블루프린트의 Text Block 위젯 이름이 'PlayerNameText'여야 함
// 플레이어의 체력을 업데이트하는 함수
UFUNCTION(BlueprintCallable, Category = "UI")
void UpdateHealth(float CurrentHealth, float MaxHealth);
protected:
virtual void NativeConstruct() override; // BeginPlay와 유사하게 위젯이 생성될 때 호출 (C++에서 초기화 로직)
};
#include "MyUserWidget.h"
#include "Components/ProgressBar.h"
#include "Components/TextBlock.h"
void UMyUserWidget::NativeConstruct()
{
Super::NativeConstruct();
// HealthBar와 PlayerNameText는 이미 meta=(BindWidget)으로 인해 자동으로 바인딩됩니다.
// 여기서 추가적인 초기화나 이벤트 바인딩을 할 수 있습니다.
if (HealthBar)
{
HealthBar->SetPercent(1.0f); // 초기 체력 100%
}
if (PlayerNameText)
{
PlayerNameText->SetText(FText::FromString(TEXT("PlayerOne"))); // 초기 플레이어 이름 설정
}
}
void UMyUserWidget::UpdateHealth(float CurrentHealth, float MaxHealth)
{
if (HealthBar)
{
// 진행률 바 업데이트 (0.0 ~ 1.0 사이의 값)
HealthBar->SetPercent(FMath::Clamp(CurrentHealth / MaxHealth, 0.0f, 1.0f));
}
if (PlayerNameText)
{
// 텍스트 업데이트 (예: 체력 수치도 같이 표시)
PlayerNameText->SetText(FText::Format(FText::FromString(TEXT("{0} ({1}/{2})")),
FText::FromString(TEXT("PlayerOne")),
FText::AsNumber(FMath::FloorToInt(CurrentHealth)),
FText::AsNumber(FMath::FloorToInt(MaxHealth))));
}
}
meta=(BindWidget)
주의사항
- 이 매크로를 사용하려면
UPROPERTY
변수 이름이 위젯 블루프린트 내의 위젯 이름과 정확히 일치해야 합니다. - 해당 위젯 블루프린트 내에서 바인딩하려는 위젯을 선택하고, 디테일 패널의
Is Variable
체크박스를 반드시 활성화해야 합니다. 그렇지 않으면 바인딩되지 않습니다. - 일반적으로
NativeConstruct()
(위젯의BeginPlay()
와 유사)에서 바인딩된 위젯 포인터가 유효한지 확인하고 초기 설정을 수행합니다.
UMG 시스템은 언리얼 엔진에서 사용자 인터페이스를 개발하기 위한 강력하고 직관적인 도구입니다. 위젯의 계층적 구조를 이해하고 UUserWidget
클래스를 기반으로 하는 위젯 블루프린트를 통해 시각적 디자인과 로직을 통합하는 것이 중요합니다. 특히 C++에서 meta=(BindWidget)
을 활용하여 위젯을 참조하고 제어하는 방법은 효율적인 UI 개발의 핵심입니다.