Class GameDev* SheepAdult

[Unreal Engine 4.27] Widget Animation Delegate C++ 본문

Unreal Project

[Unreal Engine 4.27] Widget Animation Delegate C++

SheepAdult 2022. 5. 14. 16:05

 스켈레탈 메쉬에 대한 몽타주가 끝나거나 블렌드 아웃될 때, 혹은 노티파이가 시작될 때 등 스켈레탈 애니메이션에 대한 Delegate를 활용하여 코드를 더 안전하고 효율성 있게 짤 수 있다. 언리얼은 위젯 애니메이션에도 이러한 Delegate를 지원한다.

 

 아래는 전체적인 코드이다.

// Widget.h

#pragma once

#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "Components/Image.h"

#include "FirstPersonDefaultWidget.generated.h"

/**
 * 
 */
UCLASS()
class CAP2_API UFirstPersonDefaultWidget : public UUserWidget
{
	GENERATED_BODY()
	
protected:
	virtual void NativeConstruct() override;
    
private:
    UPROPERTY()
		class AMainCharacter* MainCharacter;

	UPROPERTY(meta = (BindWidgetAnim), Transient)
		class UWidgetAnimation* FadeIn;
	UPROPERTY(meta = (BindWidgetAnim), Transient)
		class UWidgetAnimation* FadeOut;

	FWidgetAnimationDynamicEvent StartDelegate;
	FWidgetAnimationDynamicEvent EndDelegate;

	UFUNCTION()
		void AnimationStarted();
	UFUNCTION()
		void AnimationFinished();

};
// Widget.cpp

#include "FirstPersonDefaultWidget.h"
#include "MainCharacter.h"
#include "Kismet/GameplayStatics.h"

void UDefaultWidget::NativeConstruct()
{
	StartDelegate.BindDynamic(this, &UFirstPersonDefaultWidget::AnimationStarted);
	EndDelegate.BindDynamic(this, &UFirstPersonDefaultWidget::AnimationFinished);

	BindToAnimationStarted(FadeIn, StartDelegate);
	BindToAnimationFinished(FadeIn, EndDelegate);

	BindToAnimationStarted(FadeOut, StartDelegate);
	//BindToAnimationFinished(FadeOut, EndDelegate);

	MainCharacter = Cast<AMainCharacter>(UGameplayStatics::GetPlayerCharacter(GetWorld(), 0));
}

void UDefaultWidget::AnimationStarted()
{
	if (MainCharacter != nullptr)
		MainCharacter->SetControllable(false);
}

void UFirstPersonDefaultWidget::AnimationFinished()
{
	if (MainCharacter != nullptr)	
		MainCharacter->SetControllable(true);
}

 먼저 나는 레벨을 시작할때, 플레이어가 죽었을 때, 플레이어가 부활할 때 일정 시간 동안 움직일 수 없게 만들어 줄 것이다. 위의 세 가지 경우에 FadeIn, FadeOut애니메이션을 적절하게 재생할 것이고, 이 동안엔 메인 캐릭터를 움직일 수 없게 할 것이다. 헤더 파일에 애니메이션을 선언한다. 이는 위젯에서 만든 애니메이션의 이름과 똑같아야 한다. 이때, Transient라는 인자를 UPROPERTY()에 넣어줬는데, 이는 직렬화를 해제하는 역할을 하며 이를 작성하지 않으면 Transient가 아니라는 문구의 에러가 난다(서칭 해봤는데 정확한 이유는 알지 못했다...). 그리고 FWidgetAnimationBindWidget으로 Delegate를 선언해준다. 시작과 끝 Delegate를 만들 것이므로 두 개를 선언했다. 그리고 바인딩시켜줄 함수 void AnimationStarted(), void AnimationFinished() 두 가지도 선언했다.

 이제 NativeConstruct에서 Delegate에 선언해준 함수를 BindDynamic으로 바인딩 시켜준다. 그리고 UUserWidget에서 제공하는 BindToAnimationStarted()와 BindToAnimationFinished()에 애니메이션과 바인딩한 Delegate를 인자로 넣어서 완성해주면 된다. 나는 게임 시작과 리스폰에 바인딩된 GameInstance의 LoadData()에서(Save & Load 글에서 설명돼 있음) Widget Animaion을 실행시켜 Delegate를 콜 한다.

 

해당 프로젝트 13iew 다운로드 링크 : https://store.steampowered.com/app/2362150/13iew/