- C++ 코드카타
- 알고리즘 세션 강의 수강
- Ch3 팀 프로젝트
기존의 전통적인 방식의 문제점을 개선하기 위해 나타난 플러그인이다.
기존의 UMG를 사용하는 방식과의 차이는 다음과 같다.
해당 플러그인은 Lyra 프로젝트에서도 사용되기 때문에 꼭 알아둘 필요가 있다고 생각해서 한 번 사용해보기로 했다.
참고로 CommonUI 플러그인이 켜져있어야 하며, 모듈에 "CommonUI", "CommonInput"을 추가해야 한다.
Common UI의 전반적인 스택 구조는 다음과 같다.

위젯들은 위 4가지의 스택에 삽입되어서 관리되며, 상위 스택의 위젯이 하위 스택의 위젯을 비활성화 시킬 수 있다.
(즉, Modal에 위치한 위젯이 Frontend에 위치한 위젯을 비활성화 시킬 수 있음)
스택을 관리하는 위젯으로, UCommonUserWidget을 상속한 PDPrimaryWidget을 만들어주고
각 스택들은 GameplayTag로 구분해준 뒤, TMap을 통해서 스택과 매핑을 해준다.
// PDFrontendGameplayTags.h
namespace PDFrontendGameplayTags
{
// Frontend WidgetStack
PROJECTD_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Frontend_WidgetStack_Modal);
PROJECTD_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Frontend_WidgetStack_GameMenu);
PROJECTD_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Frontend_WidgetStack_GameHud);
PROJECTD_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Frontend_WidgetStack_Frontend);
}
// PDFrontendGameplayTags.cpp
namespace PDFrontendGameplayTags
{
UE_DEFINE_GAMEPLAY_TAG(Frontend_WidgetStack_Modal, "Frontend.WidgetStack.Modal");
UE_DEFINE_GAMEPLAY_TAG(Frontend_WidgetStack_GameMenu, "Frontend.WidgetStack.GameMenu");
UE_DEFINE_GAMEPLAY_TAG(Frontend_WidgetStack_GameHud, "Frontend.WidgetStack.GameHud");
UE_DEFINE_GAMEPLAY_TAG(Frontend_WidgetStack_Frontend, "Frontend.WidgetStack.Frontend");
}
// PDPrimaryLayout.h
UCLASS(Abstract, BlueprintType, meta = (DisableNativeTick))
class PROJECTD_API UPDPrimaryLayout : public UCommonUserWidget
{
GENERATED_BODY()
public:
/** Subsystem에서 Push 대상 스택을 찾을 때 사용. */
UCommonActivatableWidgetContainerBase* FindStackByTag(const FGameplayTag& StackTag) const;
protected:
/** BP에서 BindWidget으로 묶은 스택을 태그와 함께 등록. */
UFUNCTION(BlueprintCallable, Category = "Layout")
void RegisterStack(UPARAM(meta = (Categories = "Frontend.WidgetStack"))FGameplayTag StackTag, UCommonActivatableWidgetContainerBase* Stack);
private:
UPROPERTY(Transient)
TMap<FGameplayTag, TObjectPtr<UCommonActivatableWidgetContainerBase>> WidgetStackMap;
};
// PDPrimaryLayout.cpp
UCommonActivatableWidgetContainerBase* UPDPrimaryLayout::FindStackByTag(const FGameplayTag& StackTag) const
{
checkf(WidgetStackMap.Contains(StackTag), TEXT("태그에 맞는 스택이 존재하지 않습니다."));
return WidgetStackMap.FindRef(StackTag);
}
void UPDPrimaryLayout::RegisterStack(UPARAM(meta = (Categories = "Frontend.WidgetStack"))FGameplayTag StackTag, UCommonActivatableWidgetContainerBase* Stack)
{
if (!IsDesignTime())
{
if (!WidgetStackMap.Contains(StackTag))
{
WidgetStackMap.Add(StackTag, Stack);
}
}
}
이후 PDPrimaryLayout을 상속하는 위젯 블루프린트를 만들고 Common Activatable Widget Stack을 각각 배치해주고 모든 Alignment를 Fill로 맞춰준다.
(이때, 마지막 위젯이 가장 위에 배치되므로 순서가 중요)

그리고 각 스택을 TMap에 매핑해주기 위해 각각 이벤트 그래프에서 RegisterStack를 호출해주고 태그를 할당해준다.

이후 PlayerController에 Possess 될 때, 해당 위젯만 Add to Viewport를 수행한다. 이 이후로 스택에 위젯을 할당하기 때문에 Add to Viewport를 할 일은 없다.
(참고로 GameInstance의 Init에 먼저 해보았지만, 너무 빨리 호출되서 그런지 해당 작업이 수행이 안되었다.)

현재까지는 기본 틀만 작성하기 때문에 시각적으로 보이는 것은 없다. 다음은 간단한 위젯을 노출하는 작업을 해볼 예정이다.