UMG (Unreal Motion Graphics)는 언리얼 엔진의 강력한 UI 시스템으로, 게임 내 사용자 인터페이스를 쉽고 효율적으로 제작할 수 있게 해줍니다.
이 절에서는 UMG의 기본 개념과 C++에서의 활용 방법을 살펴보겠습니다.
UMG의 주요 컴포넌트
위젯 (Widget) : UI의 기본 구성 요소
캔버스 패널 (Canvas Panel) : 위젯을 자유롭게 배치할 수 있는 컨테이너
앵커 (Anchor) : 위젯의 위치와 크기를 상대적으로 지정하는 기준점
C++에서 기본적인 UI 요소 생성 및 조작
위젯 생성
UCLASS ()
class MYPROJECT_API UMyUserWidget : public UUserWidget
{
GENERATED_BODY ()
public:
virtual void NativeConstruct () override ;
private:
UPROPERTY ( meta = (BindWidget))
class UButton * MyButton ;
UPROPERTY ( meta = (BindWidget))
class UTextBlock * MyTextBlock ;
UFUNCTION ()
void OnButtonClicked ();
};
void UMyUserWidget :: NativeConstruct ()
{
Super :: NativeConstruct ();
if (MyButton)
{
MyButton -> OnClicked . AddDynamic ( this , & UMyUserWidget ::OnButtonClicked);
}
}
void UMyUserWidget :: OnButtonClicked ()
{
if (MyTextBlock)
{
MyTextBlock -> SetText ( FText :: FromString ( "Button Clicked!" ));
}
}
Copy
위젯 생성 및 화면에 추가
UCLASS ()
class MYPROJECT_API AMyHUD : public AHUD
{
GENERATED_BODY ()
public:
void ShowMyWidget ();
private:
UPROPERTY ()
UMyUserWidget* MyWidget;
};
void AMyHUD :: ShowMyWidget ()
{
if (MyWidget == nullptr )
{
MyWidget = CreateWidget < UMyUserWidget >( GetOwningPlayerController (), UMyUserWidget :: StaticClass ());
}
if (MyWidget)
{
MyWidget -> AddToViewport ();
}
}
Copy
위젯 블루프린트와 C++ 코드 연동
위젯 블루프린트에서 C++ 함수를 호출하거나, C++에서 위젯 블루프린트의 속성에 접근할 수 있습니다.
UCLASS ()
class MYPROJECT_API UMyWidgetBlueprintBase : public UUserWidget
{
GENERATED_BODY ()
public:
UFUNCTION (BlueprintCallable, Category = "UI" )
void UpdateHealthBar ( float Health );
UPROPERTY ( EditAnywhere , BlueprintReadWrite , Category = "UI" )
float MaxHealth = 100.0f ;
};
void UMyWidgetBlueprintBase :: UpdateHealthBar ( float Health )
{
// 헬스바 업데이트 로직
}
Copy
동적 UI 생성 및 관리
동적으로 UI 요소를 생성하고 관리하는 방법
UCLASS ()
class MYPROJECT_API UDynamicUIManager : public UObject
{
GENERATED_BODY ()
public:
void CreateDynamicUI ( TSubclassOf < UUserWidget > WidgetClass );
void RemoveDynamicUI ( UUserWidget * WidgetToRemove );
private:
UPROPERTY ()
TArray<UUserWidget*> ActiveWidgets;
};
void UDynamicUIManager :: CreateDynamicUI ( TSubclassOf < UUserWidget > WidgetClass )
{
APlayerController* PlayerController = UGameplayStatics :: GetPlayerController ( GetWorld (), 0 );
if (PlayerController)
{
UUserWidget* NewWidget = CreateWidget < UUserWidget >(PlayerController, WidgetClass);
if (NewWidget)
{
NewWidget -> AddToViewport ();
ActiveWidgets . Add (NewWidget);
}
}
}
void UDynamicUIManager :: RemoveDynamicUI ( UUserWidget * WidgetToRemove )
{
if (WidgetToRemove)
{
WidgetToRemove -> RemoveFromParent ();
ActiveWidgets . Remove (WidgetToRemove);
}
}
Copy
UI 애니메이션 구현
UMG에서 C++를 통해 UI 애니메이션을 구현하는 방법
UCLASS ()
class MYPROJECT_API UAnimatedWidget : public UUserWidget
{
GENERATED_BODY ()
public:
virtual void NativeConstruct () override ;
void PlayFadeAnimation ();
private:
UPROPERTY ( Transient , meta = (BindWidgetAnim))
UWidgetAnimation* FadeAnimation;
};
void UAnimatedWidget :: NativeConstruct ()
{
Super :: NativeConstruct ();
if (FadeAnimation)
{
PlayAnimation (FadeAnimation);
}
}
void UAnimatedWidget :: PlayFadeAnimation ()
{
PlayAnimation (FadeAnimation);
}
Copy
UMG 성능 최적화 전략
위젯 풀링
UCLASS ()
class MYPROJECT_API UWidgetPool : public UObject
{
GENERATED_BODY ()
public:
UUserWidget * GetWidget ( TSubclassOf < UUserWidget > WidgetClass );
void ReturnWidget ( UUserWidget * Widget );
private:
TMap<TSubclassOf<UUserWidget>, TArray<UUserWidget*>> PooledWidgets;
};
UUserWidget * UWidgetPool :: GetWidget ( TSubclassOf < UUserWidget > WidgetClass )
{
if ( PooledWidgets . Contains (WidgetClass) && PooledWidgets [WidgetClass]. Num () > 0 )
{
return PooledWidgets [WidgetClass]. Pop ();
}
else
{
return CreateWidget < UUserWidget >( GetWorld (), WidgetClass);
}
}
void UWidgetPool :: ReturnWidget ( UUserWidget * Widget )
{
if (Widget)
{
Widget -> RemoveFromParent ();
PooledWidgets . FindOrAdd ( Widget -> GetClass ()). Add (Widget);
}
}
Copy
레이아웃 캐싱
UCLASS ()
class MYPROJECT_API UOptimizedUserWidget : public UUserWidget
{
GENERATED_BODY ()
public:
virtual void NativeConstruct () override ;
protected:
virtual void NativePreConstruct () override ;
private:
UPROPERTY ()
FGeometry CachedGeometry;
void UpdateCachedGeometry ();
};
void UOptimizedUserWidget :: NativePreConstruct ()
{
Super :: NativePreConstruct ();
UpdateCachedGeometry ();
}
void UOptimizedUserWidget :: UpdateCachedGeometry ()
{
// 레이아웃 계산 및 CachedGeometry 업데이트
}
Copy
반응형 UI 디자인 구현
다양한 해상도와 화면 비율에 대응하는 반응형 UI 설계
UCLASS ()
class MYPROJECT_API UResponsiveWidget : public UUserWidget
{
GENERATED_BODY ()
public:
virtual void NativeConstruct () override ;
protected:
virtual void NativeTick ( const FGeometry & MyGeometry , float InDeltaTime ) override ;
private:
void UpdateLayout ();
};
void UResponsiveWidget :: NativeConstruct ()
{
Super :: NativeConstruct ();
UpdateLayout ();
}
void UResponsiveWidget :: NativeTick ( const FGeometry & MyGeometry , float InDeltaTime )
{
Super :: NativeTick (MyGeometry, InDeltaTime);
if ( MyGeometry . GetLocalSize () != LastSize)
{
LastSize = MyGeometry . GetLocalSize ();
UpdateLayout ();
}
}
void UResponsiveWidget :: UpdateLayout ()
{
// 화면 크기에 따라 위젯 레이아웃 조정
}
Copy
고급 UI 기능 구현
인벤토리 시스템
UCLASS ()
class MYPROJECT_API UInventoryWidget : public UUserWidget
{
GENERATED_BODY ()
public:
void UpdateInventory ( const TArray < FItemData > & Items );
private:
UPROPERTY ( meta = (BindWidget))
class UUniformGridPanel * ItemGrid ;
UPROPERTY ( EditDefaultsOnly , Category = "UI" )
TSubclassOf<UUserWidget> ItemWidgetClass;
};
void UInventoryWidget :: UpdateInventory ( const TArray < FItemData > & Items )
{
ItemGrid -> ClearChildren ();
for ( const FItemData& Item : Items)
{
UUserWidget* ItemWidget = CreateWidget < UUserWidget >( this , ItemWidgetClass);
// ItemWidget 설정
ItemGrid -> AddChildToUniformGrid (ItemWidget);
}
}
Copy
미니맵
UCLASS ()
class MYPROJECT_API UMinimapWidget : public UUserWidget
{
GENERATED_BODY ()
public:
virtual void NativeTick ( const FGeometry & MyGeometry , float InDeltaTime ) override ;
private:
UPROPERTY ( meta = (BindWidget))
class UImage * MinimapImage ;
void UpdateMinimapPosition ();
};
void UMinimapWidget :: NativeTick ( const FGeometry & MyGeometry , float InDeltaTime )
{
Super :: NativeTick (MyGeometry, InDeltaTime);
UpdateMinimapPosition ();
}
void UMinimapWidget :: UpdateMinimapPosition ()
{
// 플레이어 위치에 따라 미니맵 이미지 업데이트
}
Copy
대화 시스템
UCLASS ()
class MYPROJECT_API UDialogueWidget : public UUserWidget
{
GENERATED_BODY ()
public:
void StartDialogue ( const TArray < FString > & DialogueLines );
private:
UPROPERTY ( meta = (BindWidget))
class UTextBlock * DialogueText ;
UPROPERTY ( meta = (BindWidget))
class UButton * NextButton ;
UFUNCTION ()
void OnNextButtonClicked ();
TArray<FString> CurrentDialogue;
int32 CurrentLineIndex;
};
void UDialogueWidget :: StartDialogue ( const TArray < FString > & DialogueLines )
{
CurrentDialogue = DialogueLines;
CurrentLineIndex = 0 ;
if (DialogueText && CurrentDialogue . Num () > 0 )
{
DialogueText -> SetText ( FText :: FromString ( CurrentDialogue [CurrentLineIndex]));
}
}
void UDialogueWidget :: OnNextButtonClicked ()
{
CurrentLineIndex++;
if (CurrentLineIndex < CurrentDialogue . Num ())
{
DialogueText -> SetText ( FText :: FromString ( CurrentDialogue [CurrentLineIndex]));
}
else
{
RemoveFromParent ();
}
}
Copy
UMG는 언리얼 엔진에서 강력하고 유연한 UI 시스템을 구축할 수 있게 해주는 도구입니다. C++를 사용하여 UMG의 기능을 확장하고 커스터마이즈함으로써, 게임의 요구사항에 맞는 복잡하고 인터랙티브한 UI를 구현할 수 있습니다.
위젯 블루프린트와 C++ 코드를 효과적으로 연동하여 사용하면, 디자이너와 프로그래머 간의 협업을 원활히 하고 개발 효율성을 높일 수 있습니다. 동적 UI 생성 및 관리 기법을 통해 게임 상황에 따라 유동적으로 변화하는 UI를 구현할 수 있으며, UI 애니메이션을 활용하여 더욱 생동감 있는 인터페이스를 만들 수 있습니다.
성능 최적화를 위해서는 위젯 풀링, 레이아웃 캐싱 등의 기법을 활용해야 하며, 반응형 UI 디자인을 통해 다양한 디바이스와 해상도에 대응할 수 있습니다.
마지막으로, UMG를 활용하여 인벤토리 시스템, 미니맵, 대화 시스템 등의 고급 UI 기능을 구현할 수 있습니다. 이러한 기능들을 효과적으로 설계하고 구현함으로써, 사용자 경험을 크게 향상시킬 수 있습니다.