KoreanFoodie's Study

[언리얼] 위젯(UUserWidget) 과 Native 함수들, UObject Interface 본문

Game Dev/Unreal C++ : Dev Log

[언리얼] 위젯(UUserWidget) 과 Native 함수들, UObject Interface

GoldGiver 2022. 12. 6. 12:26

UUserWidget 의 Native 함수

//native SObjectWidget methods (see the corresponding BlueprintImplementableEvent declarations above for more info on each)
friend class SObjectWidget;

virtual void NativeOnInitialized();
virtual void NativePreConstruct();
virtual void NativeConstruct();
virtual void NativeDestruct();

virtual void NativeTick(const FGeometry& MyGeometry, float InDeltaTime);

UserWidget 에는 위와 같은 함수들이 있다. 각각의 함수들이 언제 호출되는지, 그리고 어떤 역할을 하는지를 한번 살펴보자.

  • NativeOnInitialized : 위젯이 생성될 때 딱 한 번 호출된다. 에디터 편집 시에도 생성될 때 호출된다.
  • NativeConstruct : AddToViewport 시 호출된다. NativeOnInitialized 와 달리, Viewport 에 Add 될 때마다 불린다!
  • NativeDestruct : RemoveFromParent(RemoveFromViewport) 시 호출된다. Viewport 에서 Remove 될 때마다 불린다!

 

UUserWidget 을 상속받아 우리가 위의 함수들을 재정의할 때는, 접근 지정자(protected, public)을 유의하며, virtual 과 override 키워드를 항상 붙여주도록 하자.

또한 재정의할 경우, 함수 내부에서 "Super::" 을 이용해 부모 함수를 호출해 주어야 한다. 실제로 UUserWidget 의 NativeOnInitialized 함수를 보면 다음과 같이 구현이 되어 있는데,

// Native handling for SObjectWidget

void UUserWidget::NativeOnInitialized()
{
	OnInitialized();
}

위의 OnInitialized 함수는 BlueprintImplementableEvent 로, Widget Blueprint 이벤트를 호출해 주고 있다.

/** 
 * Called once only at game time on non-template instances.
 * While Construct/Destruct pertain to the underlying Slate, this is called only once for the UUserWidget.
 * If you have one-time things to establish up-front (like binding callbacks to events on BindWidget properties), do so here.
 */
UFUNCTION(BlueprintImplementableEvent, BlueprintCosmetic, Category="User Interface")
void OnInitialized();

 

 

UObject Interface

UUserWidget 에는 다음과 같은 UObject Interface 가 정의되어 있다.

public:
	UUserWidget(const FObjectInitializer& ObjectInitializer);

	//UObject interface
	virtual class UWorld* GetWorld() const override;
	virtual void PostDuplicate(bool bDuplicateForPIE) override;
	virtual void BeginDestroy() override;
	virtual void PostLoad() override;
	virtual void Serialize(FArchive& Ar) override;
	//~ End UObject Interface

위 함수들의 접근 지정자가 public 이라는 것을 알아두자! 추가로, BeginDestroy 는 다음과 같이 구현되어 있는데,

void UUserWidget::BeginDestroy()
{
	Super::BeginDestroy();

	TearDownAnimations();

	if (AnimationTickManager)
	{
		AnimationTickManager->RemoveWidget(this);
		AnimationTickManager = nullptr;
	}

	//TODO: Investigate why this would ever be called directly, RemoveFromParent isn't safe to call during GC,
	// as the widget structure may be in a partially destroyed state.

	// If anyone ever calls BeginDestroy explicitly on a widget we need to immediately remove it from
	// the the parent as it may be owned currently by a slate widget.  As long as it's the viewport we're
	// fine.
	RemoveFromParent();

	// If it's not owned by the viewport we need to take more extensive measures.  If the GC widget still
	// exists after this point we should just reset the widget, which will forcefully cause the SObjectWidget
	// to lose access to this UObject.
	TSharedPtr<SObjectWidget> SafeGCWidget = MyGCWidget.Pin();
	if ( SafeGCWidget.IsValid() )
	{
		SafeGCWidget->ResetWidget();
	}
}

BeginDestroy 를 Override 할 때는, 'Super::' 를 이용해 부모의 BeginDestroy 를 반드시 호출해 주자. 그래야 GC 이슈와 관련한 크래시를 방지할 수 있다.

Comments