[UE5] PickUpDefense #2 - 위젯 시스템 개념 및 제네릭 함수 활용

ChangJin·2024년 8월 22일
0

Unreal Engine5

목록 보기
100/114
post-thumbnail

2024.08.22

이번 글에서는 PickUpDefense 게임의 UI 위젯 시스템에 대한 개념을 정리하고, 제네릭 함수를 활용하여 코드 중복을 줄이는 과정을 다룹니다. 특히, 언리얼 엔진의 UMG(User Interface) 시스템에서 위젯을 생성하고 배치하는 방법에 대해 설명합니다.

진행상황

  • ✅ 상단 스테이지 UI
    - ✅ UI 위치
    • ⬜ 상단 UI 시간 시스템
    • ⬜ 상단 UI 스테이지 시스템
  • ✅ 하단 차량 상점 UI
    - ✅ UI 위치
    • ⬜ 드래그 앤 드롭으로 카드 옮기기
    • ⬜ 마우스 우클릭으로 구매, 판매하기
  • ⬜ 우측 아이템 UI
    • ⬜ 드래그 앤 드롭 기능을 통한 무기 장착
    • ⬜ 여러 아이템의 마우스 좌클릭 입력 처리
  • ⬜ 호버시 자세히보기 UI

1. UI 위젯의 개념

언리얼 엔진에서 위젯(Widget)은 게임의 사용자 인터페이스(UI)를 구성하는 기본 요소입니다. UMG(User Interface Design) 시스템을 통해 HUD(Heads-Up Display), 메뉴, 버튼, 텍스트, 이미지 등 다양한 UI 요소를 디자인하고 배치할 수 있습니다.

위젯의 주요 구성 요소:

  • UUserWidget: 모든 위젯의 기본 클래스입니다. 이 클래스를 상속받아 고유한 UI 요소를 생성할 수 있습니다.
  • 패널 위젯: 다른 위젯을 자식으로 포함할 수 있는 컨테이너 역할을 합니다. 예를 들어, UCanvasPanel, UHorizontalBox, UVerticalBox 등이 있습니다.
  • 슬롯(Slot): 자식 위젯이 부모 위젯에 어떻게 배치될지를 정의하는 클래스입니다. 슬롯을 통해 위젯의 크기, 정렬, 패딩 등을 설정할 수 있습니다. 예를 들어, UHorizontalBoxSlot, UVerticalBoxSlot 등이 있습니다.
  • 위젯 트리(Widget Tree): 위젯 간의 계층 구조를 관리하며, 특정 부모 위젯 아래에 자식 위젯을 추가하는 구조입니다. WidgetTree는 위젯 트리를 구성하고 관리하는 데 사용됩니다.

2. UI 위젯 시스템 구현

PickUpDefense에서는 다양한 UI 위젯을 사용하여 게임의 인터페이스를 구성하고 있습니다. 이 과정에서 위젯을 효율적으로 생성하고 관리하기 위해 C++을 활용하였습니다.

예시: UI 위젯 생성 및 배치

void UYourWidgetClass::SomeFunction()
{
    // UHorizontalBox 생성
    UHorizontalBox* HorizontalBox = WidgetTree->ConstructWidget<UHorizontalBox>(UHorizontalBox::StaticClass(), TEXT("HorizontalBox"));
    
    // UBorder 생성 및 배치
    UBorder* Border = WidgetTree->ConstructWidget<UBorder>(UBorder::StaticClass(), TEXT("ExampleBorder"));
    Border->SetBrushColor(FLinearColor(0.735351f, 0.35115f, 1.0f, 0.4f));

    // UHorizontalBoxSlot에 UBorder 추가
    if (HorizontalBox)
    {
        UHorizontalBoxSlot* Slot = HorizontalBox->AddChildToHorizontalBox(Border);
        if (Slot)
        {
            FSlateChildSize ChildSize;
            ChildSize.Value = 1.0f;
            Slot->SetSize(ChildSize);
            Slot->SetHorizontalAlignment(EHorizontalAlignment::HAlign_Fill);
            Slot->SetVerticalAlignment(EVerticalAlignment::VAlign_Fill);
            Slot->SetPadding(FMargin(1.0f, 0.0f, 1.0f, 0.0f));
        }
    }
}
  • 위젯 생성: WidgetTree->ConstructWidget 메서드를 사용하여 위젯을 생성합니다.
  • 위젯 배치: 부모 위젯에 자식 위젯을 추가하고, Slot을 통해 레이아웃 속성을 설정합니다.

3. 제네릭 함수를 활용한 코드 재사용

여러 부모 위젯에 공통적인 작업을 수행하는 코드를 제네릭 함수로 구현함으로써 코드 중복을 줄이고 유지보수성을 높일 수 있습니다. 예를 들어, UHorizontalBoxUVerticalBox 모두에 UBorder 위젯을 추가하는 작업을 제네릭 함수로 일반화할 수 있습니다.

제네릭 함수 구현

template <typename TParentWidget>
void AddBorderToChild(TParentWidget* ParentWidget, UWidgetTree* WidgetTree, const FName& BorderName)
{
    UBorder* Border = WidgetTree->ConstructWidget<UBorder>(UBorder::StaticClass(), BorderName);
    Border->SetBrushColor(FLinearColor(0.735351f, 0.35115f, 1.0f, 0.4f));

    if (ParentWidget)
    {
        UPanelSlot* PanelSlot = ParentWidget->AddChild(Border);
        if (PanelSlot)
        {
            // 슬롯 타입에 따라 적절한 설정 적용
            if (UHorizontalBoxSlot* HorizontalSlot = Cast<UHorizontalBoxSlot>(PanelSlot))
            {
                HorizontalSlot->SetSize(FSlateChildSize(ESlateSizeRule::Fill));
                HorizontalSlot->SetHorizontalAlignment(EHorizontalAlignment::HAlign_Fill);
                HorizontalSlot->SetVerticalAlignment(EVerticalAlignment::VAlign_Fill);
                HorizontalSlot->SetPadding(FMargin(1.0f, 0.0f, 1.0f, 0.0f));
            }
            else if (UVerticalBoxSlot* VerticalSlot = Cast<UVerticalBoxSlot>(PanelSlot))
            {
                VerticalSlot->SetSize(FSlateChildSize(ESlateSizeRule::Fill));
                VerticalSlot->SetHorizontalAlignment(EHorizontalAlignment::HAlign_Fill);
                VerticalSlot->SetVerticalAlignment(EVerticalAlignment::VAlign_Fill);
                VerticalSlot->SetPadding(FMargin(1.0f, 0.0f, 1.0f, 0.0f));
            }
        }
    }
}

4. FName을 활용한 동적 위젯 이름 생성

FName은 언리얼 엔진에서 고유 식별자로 사용되며, 위젯을 생성할 때 유용합니다. 동적으로 생성되는 위젯에 고유한 이름을 부여하기 위해 FNameFString을 결합하여 새로운 FName을 생성하는 방법을 사용했습니다.

FName CreateDynamicFName(const FName& BaseName, int32 Index)
{
    return FName(*FString::Printf(TEXT("%s_%d"), *BaseName.ToString(), Index));
}
  • CreateDynamicFName: 주어진 기본 이름과 인덱스를 결합하여FName을 생성합니다.

5. 전체 개발 과정 요약

PickUpDefense의 UI 위젯 시스템 구현 과정에서 위젯의 개념을 이해하고, 제네릭 함수와 FName을 활용하여 코드의 효율성을 크게 향상시켰습니다.

  • UI 위젯 개념 이해: 언리얼 엔진의 UMG 시스템에서 위젯의 기본 개념을 이해하고 이를 기반으로 UI를 구성했습니다.
  • 제네릭 함수를 통한 코드 재사용: 다양한 부모 위젯에서 공통적으로 사용할 수 있는 제네릭 함수를 작성하여 코드 중복을 줄였습니다.
  • FName을 활용한 동적 이름 생성: 동적으로 생성되는 위젯에 고유한 이름을 부여하여 코드의 유연성을 높였습니다.

앞으로의 작업에서는 이러한 기반을 바탕으로 PickUpDefense 게임의 UI 시스템을 더욱 발전시키고, 게임의 주요 메커니즘을 구현해 나갈 예정입니다. 다음 단계에서는 게임의 전반적인 인터페이스를 완성하고, 플레이어 경험을 개선할 수 있는 작업들을 진행할 계획입니다.


이 글이 PickUpDefense 게임의 개발 과정을 이해하는 데 도움이 되길 바라며, 앞으로의 개발 과정에서도 이러한 경험이 바탕이 되어 더욱 발전된 기능을 구현할 수 있기를 기대합니다. 피드백이나 질문이 있으면 언제든지 남겨주세요!

profile
게임 프로그래머

0개의 댓글