icon안동민 개발노트

슬레이트 UI 시스템 기초


 슬레이트(Slate)는 언리얼 엔진의 저수준 UI 프레임워크로, C++에서 직접 UI를 구현할 때 사용됩니다. UMG가 디자이너와 프로그래머 모두를 위한 고수준 UI 도구라면, 슬레이트는 프로그래머를 위한 강력하고 유연한 UI 시스템입니다.

슬레이트 위젯의 구조

 슬레이트 위젯은 기본적으로 SWidget을 상속받아 구현됩니다. 가장 일반적으로 사용되는 기본 클래스는 SCompoundWidget입니다.

class MYPROJECT_API SMyWidget : public SCompoundWidget
{
    SLATE_BEGIN_ARGS(SMyWidget)
        : _SomeAttribute()
    {}
        SLATE_ARGUMENT(FString, SomeAttribute)
    SLATE_END_ARGS()
 
    void Construct(const FArguments& InArgs);
};
 
void SMyWidget::Construct(const FArguments& InArgs)
{
    ChildSlot
    [
        SNew(STextBlock)
        .Text(FText::FromString(InArgs._SomeAttribute))
    ];
}

 이 예제에서 SLATE_BEGIN_ARGSSLATE_END_ARGS 매크로는 위젯의 속성을 정의합니다. Construct 함수에서는 위젯의 실제 구조를 정의합니다.

주요 슬레이트 클래스

  1. SWidget : 모든 슬레이트 위젯의 기본 클래스
  2. SCompoundWidget : 단일 자식을 가질 수 있는 복합 위젯
  3. SPanel : 여러 자식을 가질 수 있는 패널 위젯
  4. SLeafWidget : 자식을 가질 수 없는 리프 위젯

커스텀 슬레이트 위젯 생성

 커스텀 슬레이트 위젯을 생성할 때는 주로 SCompoundWidget을 상속받아 구현합니다.

class SCustomButton : public SCompoundWidget
{
public:
    SLATE_BEGIN_ARGS(SCustomButton)
        : _ButtonText()
        , _OnClicked()
    {}
        SLATE_ATTRIBUTE(FText, ButtonText)
        SLATE_EVENT(FOnClicked, OnClicked)
    SLATE_END_ARGS()
 
    void Construct(const FArguments& InArgs)
    {
        ChildSlot
        [
            SNew(SButton)
            .Text(InArgs._ButtonText)
            .OnClicked(InArgs._OnClicked)
        ];
    }
};

 이 예제에서는 SButton을 래핑하는 커스텀 버튼 위젯을 생성합니다.

슬레이트 스타일 설정

 슬레이트는 강력한 스타일링 시스템을 제공합니다. 스타일은 주로 FSlateStyleSet을 통해 정의됩니다.

FSlateStyleSet* StyleSet = new FSlateStyleSet("CustomStyle");
StyleSet->Set("CustomButton", FButtonStyle()
    .SetNormal(FSlateBoxBrush(FPaths::ProjectContentDir() / TEXT("UI/ButtonNormal.png"), FMargin(10.0f/32.0f)))
    .SetHovered(FSlateBoxBrush(FPaths::ProjectContentDir() / TEXT("UI/ButtonHovered.png"), FMargin(10.0f/32.0f)))
    .SetPressed(FSlateBoxBrush(FPaths::ProjectContentDir() / TEXT("UI/ButtonPressed.png"), FMargin(10.0f/32.0f)))
);
FSlateStyleRegistry::RegisterSlateStyle(*StyleSet);

이벤트 처리 구현

 슬레이트에서 이벤트 처리는 주로 델리게이트를 통해 이루어집니다.

SNew(SButton)
.OnClicked(FOnClicked::CreateLambda([this]()
{
    // 클릭 이벤트 처리
    return FReply::Handled();
}))

레이아웃 및 정렬

 슬레이트는 다양한 레이아웃 위젯을 제공합니다.

 예를 들어, SVerticalBoxSHorizontalBox는 가장 기본적인 레이아웃 위젯입니다.

SNew(SVerticalBox)
+SVerticalBox::Slot()
.HAlign(HAlign_Center)
.VAlign(VAlign_Center)
[
    SNew(STextBlock)
    .Text(FText::FromString("Centered Text"))
]
+SVerticalBox::Slot()
.HAlign(HAlign_Right)
[
    SNew(STextBlock)
    .Text(FText::FromString("Right-aligned Text"))
]

UMG와 슬레이트의 차이점

  1. 사용 난이도 : UMG는 비주얼 디자이너를 제공하여 더 쉽게 UI를 만들 수 있습니다.
  2. 성능 : 슬레이트는 더 낮은 수준에서 동작하므로 일반적으로 더 높은 성능을 제공합니다.
  3. 유연성 : 슬레이트는 더 많은 커스터마이징 옵션을 제공합니다.

고성능 UI 구현 전략

  1. 위젯 재사용 : 가능한 한 위젯을 재사용하여 생성 비용을 줄입니다.
  2. 레이아웃 최적화 : 복잡한 레이아웃 계산을 최소화합니다.
  3. 드로우 콜 최소화 : 가능한 한 드로우 콜을 줄이도록 UI를 설계합니다.

에디터 UI 확장

 슬레이트는 언리얼 에디터의 UI를 확장하는 데 주로 사용됩니다.

FLevelEditorModule& LevelEditorModule = FModuleManager::LoadModuleChecked<FLevelEditorModule>("LevelEditor");
TSharedPtr<FTabManager> LevelEditorTabManager = LevelEditorModule.GetLevelEditorTabManager();
LevelEditorTabManager->RegisterTabSpawner("CustomTab", FOnSpawnTab::CreateLambda([](const FSpawnTabArgs& Args)
{
    return SNew(SDockTab)
    .TabRole(ETabRole::NomadTab)
    [
        SNew(SCustomWidget)
    ];
}));

성능 최적화 기법

  1. 캐싱 : 자주 변경되지 않는 위젯 부분을 캐싱합니다.
  2. 가시성 최적화 : 화면에 보이지 않는 위젯의 업데이트를 최소화합니다.
  3. 지연 생성 : 필요할 때만 위젯을 생성합니다.

디버깅 방법

  1. 슬레이트 위젯 리플렉터 : 에디터에서 제공하는 도구로 위젯 계층 구조를 분석할 수 있습니다.
  2. 로깅 : UE_LOG 매크로를 사용하여 위젯의 상태와 이벤트를 로깅합니다.
  3. 시각적 디버깅 : DrawDebugLine과 같은 함수를 사용하여 위젯의 경계를 시각화합니다.

 슬레이트 UI 시스템은 강력하고 유연하지만, 학습 곡선이 가파르다는 단점이 있습니다. 그러나 한번 익숙해지면, 고성능의 커스텀 UI를 구현하는 데 매우 유용한 도구가 됩니다. 특히 에디터 확장이나 고도로 최적화된 게임 내 UI가 필요한 경우에 슬레이트의 강점이 두드러집니다.