Activatable Widget
CommonUI의 핵심 위젯인 UCommonActivatableWidget의 활성화/비활성화 메커니즘, 위젯 스택, 자동 포커스 관리를 학습합니다.
UCommonActivatableWidget 개념
활성화 가능 위젯의 핵심 역할과 동작 원리
UCommonActivatableWidget은 "활성/비활성" 상태를 가지며, 활성화 시 입력 라우팅 트리에 노드로 등록되는 위젯입니다. 메뉴, 다이얼로그, 팝업 등 입력을 받아야 하는 모든 UI 화면에 사용합니다.
UCLASS()
class USettingsMenu : public UCommonActivatableWidget
{
GENERATED_BODY()
protected:
// 위젯이 활성화될 때 호출
virtual void NativeOnActivated() override;
// 위젯이 비활성화될 때 호출
virtual void NativeOnDeactivated() override;
// 기본 포커스를 받을 위젯 지정
virtual UWidget* NativeGetDesiredFocusTarget() const override;
UPROPERTY(meta = (BindWidget))
UCommonButtonBase* FirstOptionButton;
};
void USettingsMenu::NativeOnActivated()
{
Super::NativeOnActivated();
// 입력 액션 등록, 애니메이션 시작 등
PlayAnimation(FadeInAnimation);
// Back 액션 등록
RegisterUIActionBinding(FBindUIActionArgs(
BackAction, false,
FSimpleDelegate::CreateUObject(this, &USettingsMenu::HandleBack)
));
}
void USettingsMenu::NativeOnDeactivated()
{
// 등록된 액션은 자동 해제됨
Super::NativeOnDeactivated();
}
UWidget* USettingsMenu::NativeGetDesiredFocusTarget() const
{
// 게임패드 사용 시 이 위젯에 포커스 이동
return FirstOptionButton;
}
이 함수는 게임패드 사용 시 자동 포커스 대상을 지정합니다. 구현하지 않으면 CommonUI가 위젯 트리에서 포커스 가능한 첫 번째 위젯을 자동으로 찾지만, 명시적으로 지정하는 것이 의도된 UX를 보장합니다.
위젯 스택과 PushWidget
메뉴 스택 관리 패턴
CommonUI는 위젯 스택(Widget Stack) 개념으로 메뉴 계층을 관리합니다. PushWidget()으로 새 위젯을 스택에 추가하면 이전 위젯은 비활성화되고, DeactivateWidget()으로 현재 위젯을 제거하면 이전 위젯이 다시 활성화됩니다.
// CommonActivatableWidgetContainerBase를 사용하여 스택 관리
UPROPERTY(meta = (BindWidget))
UCommonActivatableWidgetContainerBase* MenuStack;
// 위젯을 스택에 Push
void UGameUI::OpenSettings()
{
// PushWidget은 위젯을 생성하고 스택에 추가
// UE 5.5+: 내부적으로 ActivateWidget() 자동 호출
USettingsMenu* Settings = MenuStack->AddWidget<USettingsMenu>(
SettingsMenuClass);
}
// 현재 최상단 위젯을 Pop (Settings에서 뒤로가기)
void USettingsMenu::HandleBack()
{
// DeactivateWidget()은 스택에서 이 위젯을 제거
// 이전 위젯(Main Menu)이 자동으로 재활성화됨
DeactivateWidget();
}
// 확인 다이얼로그 Push
void USettingsMenu::ShowResetConfirm()
{
UConfirmDialog* Dialog = MenuStack->AddWidget<UConfirmDialog>(
ConfirmDialogClass);
Dialog->OnConfirmed.AddDynamic(
this, &USettingsMenu::OnResetConfirmed);
}
UE 5.5부터 AddWidget() / PushWidget()이 위젯 활성화를 내부적으로 처리합니다. Push 후 수동으로 ActivateWidget()을 호출하면 초기화 로직이 중복 실행되어 버그가 발생할 수 있습니다. 이전 버전 코드를 마이그레이션할 때 주의하세요.
활성화 설정 옵션
입력 모드, 마우스 캡처, 가시성 설정
UCLASS()
class UPauseMenu : public UCommonActivatableWidget
{
GENERATED_BODY()
public:
UPauseMenu()
{
// 활성화 시 입력 설정
// Menu 모드: 게임 입력 차단, UI만 입력 받음
SetInputMode(ECommonInputMode::Menu);
// 마우스 잠금 해제 (메뉴에서 자유 이동)
SetMouseCaptureMode(EMouseCaptureMode::NoCapture);
// 비활성화 시 표시 상태
// Collapsed: 비활성 시 완전히 숨김
// HitTestInvisible: 표시는 하되 입력 안 받음
SetAutoActivate(false);
}
};
// 다른 예: 인게임 오버레이 (게임 입력도 허용)
UCLASS()
class UIngameOverlay : public UCommonActivatableWidget
{
GENERATED_BODY()
public:
UIngameOverlay()
{
// Game+UI 모드: 게임 입력도 통과시킴
SetInputMode(ECommonInputMode::All);
}
};
| 입력 모드 | 게임 입력 | UI 입력 | 사용 예 |
|---|---|---|---|
ECommonInputMode::Menu |
차단 | 허용 | 일시정지 메뉴, 인벤토리, 설정 |
ECommonInputMode::Game |
허용 | 차단 | 게임플레이 전용 (UI 비활성) |
ECommonInputMode::All |
허용 | 허용 | HUD, 인게임 오버레이, 빠른 슬롯 |
실전 패턴: 메뉴 시스템 구축
CommonUI로 완전한 메뉴 시스템을 구현하는 예제
// 루트 UI 레이아웃 위젯
UCLASS()
class UGameUILayout : public UCommonUserWidget
{
GENERATED_BODY()
protected:
// 게임플레이 HUD 레이어
UPROPERTY(meta = (BindWidget))
UCommonActivatableWidgetContainerBase* GameLayer;
// 메뉴 스택 레이어
UPROPERTY(meta = (BindWidget))
UCommonActivatableWidgetContainerBase* MenuLayer;
// 팝업/다이얼로그 레이어 (최상위)
UPROPERTY(meta = (BindWidget))
UCommonActivatableWidgetContainerBase* ModalLayer;
public:
// 레이어별 위젯 추가 함수
template<typename T>
T* PushToGameLayer(TSubclassOf<T> WidgetClass)
{
return GameLayer->AddWidget<T>(WidgetClass);
}
template<typename T>
T* PushToMenuLayer(TSubclassOf<T> WidgetClass)
{
return MenuLayer->AddWidget<T>(WidgetClass);
}
template<typename T>
T* PushToModalLayer(TSubclassOf<T> WidgetClass)
{
return ModalLayer->AddWidget<T>(WidgetClass);
}
};
UI를 Game / Menu / Modal 레이어로 분리하면 입력 우선순위가 자연스럽게 관리됩니다. Modal 레이어에 다이얼로그가 있으면 Menu 레이어의 입력이 차단되고, Menu 레이어에 메뉴가 있으면 Game 레이어의 입력이 차단됩니다. 이 패턴은 Lyra 프로젝트에서도 사용됩니다.
핵심 요약
UCommonActivatableWidget은 활성/비활성 상태를 가지며, 활성화 시 입력 라우팅 트리에 노드로 등록됩니다NativeOnActivated()에서 입력 액션 등록,NativeGetDesiredFocusTarget()에서 자동 포커스 대상을 지정합니다- 위젯 스택으로 메뉴 계층을 관리하며,
AddWidget()으로 Push,DeactivateWidget()으로 Pop합니다 - ECommonInputMode로 Menu(UI 전용), Game(게임 전용), All(둘 다) 입력 모드를 설정합니다
- Game/Menu/Modal 레이어 분리 패턴으로 입력 우선순위를 자연스럽게 관리할 수 있습니다
도전 과제
배운 내용을 직접 실습해보세요
UCommonActivatableWidgetContainerBase(Stack)를 사용하여 메인메뉴 -> 설정 -> 그래픽 상세설정 순으로 Push/Pop되는 메뉴 스택을 구현하세요. 뒤로가기 시 자동으로 이전 화면이 활성화되는 것을 확인합니다.
GetDesiredFocusTarget()을 오버라이드하여 각 메뉴 화면이 활성화될 때 적절한 버튼에 자동 포커스가 이동하도록 구현하세요. 게임패드로 메뉴를 탐색하며 포커스 흐름이 자연스러운지 확인합니다.
UCommonActivatableWidgetSwitcher와 CommonUI Tab 시스템을 조합하여 '인벤토리/장비/스킬/퀘스트' 탭으로 구성된 RPG 스타일 메뉴를 구현하세요. 각 탭은 독립적인 입력 컨텍스트를 가져야 합니다.