Common UI 기반 Progress Button 구현

Woogle·2024년 11월 9일
0

언리얼 엔진 5

목록 보기
60/60
post-thumbnail

📄 개요

Common UI Plugin을 기반으로 Hold Progress를 표시하는 버튼을 만들면서 알게된 점과 방법을 기록한다.


📄 UButton과 UCommonButtonBase의 차이점

🚨 UButton

  • UMG에서 기본적으로 제공하는 버튼 클래스
  • UMG의 상호작용을 통해 입력 이벤트를 처리한다.

🔌 UCommonButtonBase

  • Common UI Plugin에서 제공하는 버튼 클래스
  • Common UI Plugin의 UCommonUserWidget을 상속받아 다중 입력 시스템(키보드/마우스, 터치, 게임패드 등)을 지원한다.
  • UMG의 UButton을 직접 상속받지 않는다. (착각하기 쉬운 부분)
  • WidgetTree에서 RootWidget을 버튼화해서 사용한다.

🚀 CommonUserWidget.h

/**
* The actual UButton that we wrap this user widget into. 
* Allows us to get user widget customization and built-in button functionality. 
*/
TWeakObjectPtr<class UCommonButtonInternalBase> RootButton;

🚀 CommonUserWidget.cpp

bool UCommonButtonBase::Initialize()
{
	const bool bInitializedThisCall = Super::Initialize();

	if (bInitializedThisCall)
	{
		UCommonButtonInternalBase* RootButtonRaw = ConstructInternalButton();

		RootButtonRaw->SetClickMethod(ClickMethod);
		RootButtonRaw->SetTouchMethod(TouchMethod);
		RootButtonRaw->SetPressMethod(PressMethod);
		RootButtonRaw->SetButtonFocusable(IsFocusable());
		RootButtonRaw->SetButtonEnabled(bButtonEnabled);
		RootButtonRaw->SetInteractionEnabled(bInteractionEnabled);
		RootButton = RootButtonRaw;

		if (WidgetTree->RootWidget)
		{
			UButtonSlot* NewSlot = Cast<UButtonSlot>(RootButtonRaw->AddChild(WidgetTree->RootWidget));
			NewSlot->SetPadding(FMargin());
			NewSlot->SetHorizontalAlignment(EHorizontalAlignment::HAlign_Fill);
			NewSlot->SetVerticalAlignment(EVerticalAlignment::VAlign_Fill);
			WidgetTree->RootWidget = RootButtonRaw;

			RootButton->OnClicked.AddUniqueDynamic(this, &UCommonButtonBase::HandleButtonClicked);
			RootButton->HandleDoubleClicked.BindUObject(this, &UCommonButtonBase::HandleButtonDoubleClicked);
			RootButton->OnReceivedFocus.BindUObject(this, &UCommonButtonBase::HandleFocusReceived);
			RootButton->OnLostFocus.BindUObject(this, &UCommonButtonBase::HandleFocusLost);
			RootButton->OnPressed.AddUniqueDynamic(this, &UCommonButtonBase::HandleButtonPressed);
			RootButton->OnReleased.AddUniqueDynamic(this, &UCommonButtonBase::HandleButtonReleased);
		}
	}

	return bInitializedThisCall;
}

📄 Press, Release, Click 이벤트의 차이점

이벤트발생 시점사용 목적
Pressed버튼을 누르는 순간즉각적인 피드백, 충전 시작
Released버튼을 놓는 순간누르고 있는 동작의 종료, 충전 해제
Clicked버튼을 누르고 떼는 동작이 완료된 후명시적인 명령 수행, 버튼의 기능 동작

📄 Progress Button의 구현

✏️ 구현 설계

  • CommonButton Base를 상속받아 커스텀 버튼 클래스를 만들었다.
    • 기본 Common Button Base는 WBP에 OnPressed, OnReleased 이벤트가 노출되지 않음
    • WBP에서 CurrentHoldProgress를 접근할 수 있는 함수가 필요함

🚀 Progress Button 코드

UCLASS()
class HOLDBUTTONTEST_API UProgressButton : public UCommonButtonBase
{
	GENERATED_BODY()

public:
    // Hold 시작 딜리게이트
	UPROPERTY(BlueprintAssignable, Category = "Events", meta = (AllowPrivateAccess = true, DisplayName = "On Pressed"))
	FCommonButtonBaseClicked OnButtonBasePressed;

	virtual void NativeOnPressed() override;
	{
		Super::NativeOnPressed();
		OnButtonBasePressed.Broadcast(this);
	}

    // Hold 중단 딜리게이트
	UPROPERTY(BlueprintAssignable, Category = "Events", meta = (AllowPrivateAccess = true, DisplayName = "On Released"))
	FCommonButtonBaseClicked OnButtonBaseReleased;

	virtual void NativeOnReleased() override;
	{
		Super::NativeOnReleased();
		OnButtonBaseReleased.Broadcast(this);
	}

    // Progress Bar에 Percent를 전달하기 위함
	UFUNCTION(BlueprintCallable)
	float GetCurrentHoldProgress() const { return CurrentHoldProgress; }
};
  • WBP에서 이벤트를 연결한다.

  • Hold Time 데이터는 Common UI Plugin에서 제공되는 UCommonUIHoldData을 그대로 사용한다.

✏️ 구현 결과

  • Hold 시작 시 UI가 보이고, Hold 중단 또는 Progress가 100% 되면 UI가 숨겨진다.

📄 참고 자료

profile
노력하는 게임 개발자

0개의 댓글