Unreal Engine 4 프로그래밍 c++/UMG

c++ WidgetAnimation 실행

코닥쿠 2022. 1. 5. 02:10
반응형

WidgetAnimation같은 경우에는 예전버전같은경우에는 UUserWidget_BP에서 애니메이션을 만들고 블루프린트안에서 Property->ObjectProperty->WidgetAnimation 이런식으로 애니메이션으로 찾아 들어갔어야했다.

Old Method

CustomUserWidget.h

UCLASS()
class PROJECT_API CustomUserWidget : public UUserWidget
{
	GENERATED_BODY()
	
public:
	virtual void NativeConstruct() override;

	void FillAnimationsMap();
    
	//UWidgetAnimation : 위젯 애니메이션 레퍼런스//
	//AnimationName : 애니메이션 이름//
	UFUNCTION(BlueprintCallable)
	UWidgetAnimation* GetAnimationByName(FName AnimationName) const;

	//bool : 재생//
	//AnimationName : 애니메이션 이름//
	//StartAtTime : 시작 시간//
	//NumLoopsToPlay : 루프 횟수//
	//PlayMode : 재생 모드//
	//PlaybackSpeed : 재생 속도//
	UFUNCTION(BlueprintCallable)
	bool PlayAnimationByName(FName AnimationName,
		float StartAtTime = 0.f,
		int32 NumLoopsToPlay = 1,
		EUMGSequencePlayMode::Type PlayMode = EUMGSequencePlayMode::Forward,
		float PlaybackSpeed = 1.f);

CustomUserWidget.cpp

#include "CustomeUserWidget.h"

void UCustomUserWidget::NativeConstruct()
{
	//애니메이션 스택//
	FillAnimationsMap();

	Super::NativeConstruct();
}

//!애니메이션 스택Func//
void UCustomUserWidget::FillAnimationsMap()
{
	//애니메이션맵 비우기//
	AnimationsMap.Empty();
	
    //클래스 프로퍼티들를 가져옴//
	UProperty* Prop = GetClass()->PropertyLink;
	while (Prop != nullptr)
	{
		//객체들만 가져옴//
		if (Prop->GetClass() == UObjectProperty::StaticClass())
		{
        	//!Cast//
			UObjectProperty* ObjProp = Cast<UObjectProperty>(Prop);
			
            //객체들중에서 애니메이션객체만 가져옴//
			if (ObjProp->PropertyClass == UWidgetAnimation::StaticClass())
			{
            	//가져온 애니메이션객체를 WidgetAnimation으로 Cast함//
				UObject* Obj = ObjProp->GetObjectPropertyValue_InContainer(this);
				UWidgetAnimation* WidgetAnim = Cast<UWidgetAnimation>(Obj);

				if (WidgetAnim != nullptr && WidgetAnim->MovieScene != nullptr)
				{
                	//맵에 애니메이션 이름과 애니메이션을 쌓음//
					FName AnimName = WidgetAnim->MovieScene->GetFName();
					AnimationsMap.Add(AnimName, WidgetAnim);
				}
			}
		}
		//다음 링크로 이동//
		Prop = Prop->PropertyLinkNext;
	}

//맵에 있는 애니메이션을 이름과 같은 애니메이션을 찾아 반환시켜줌//
UWidgetAnimation* UCustomUserWidget::GetAnimationByName(FName AnimationName) const
{
	UWidgetAnimation* const* WidgetAnim = AnimationsMap.Find(AnimationName);
	if (WidgetAnim)
	{
		return *WidgetAnim;
	}
	return nullptr;
}

//실제 호출하는 함수로 입력값에 따라 실행이 됨//
bool UCustomUserWidget::PlayAnimationByName(FName AnimationName,
	float StartAtTime,
	int32 NumLoopsToPlay,
	EUMGSequencePlayMode::Type PlayMode,
	float PlaybackSpeed)
{
	UWidgetAnimation* WidgetAnim = GetAnimationByName(AnimationName);
	if (WidgetAnim)
	{
		PlayAnimation(WidgetAnim, StartAtTime, NumLoopsToPlay, PlayMode, PlaybackSpeed);
		return true;
	}
	return false;
}

근데 지금은 이 메소드가 자체가 UUserWidget안에 들어간듯하다.

/*원본 주소*/

https://benui.ca/unreal/ui-animations-from-cpp/

 

Controlling UMG Animations from C++

How to call UMG animations defined in Blueprints from C++.

benui.ca


New Method

Player_Crosshair_Widget.h

//call the Func From Player//
void PlayAnimationByName();

UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (BindWidgetAnim), Transient)
class UWidgetAnimation* Zoom_Fire;
UPROPERTY(EditAnywhere, BlueprintReadWrite, meta = (BindWidgetAnim), Transient)
class UWidgetAnimation* Fire;

이제는 UWidgetAnimation 다른객체들과 같이 똑같지만 다른것은

meta = (BindWidgetAnim), Transient이다. 

BindWidgetAnim은 애니메이션과 바인딩하기 위해 필수요소이다.

 하지만 Transient를 적용을 안할경우에 이런 오류가 뜨는데 직렬화가 안돼서 그런거같다.

Player_Crosshair_Widget.cpp

void UPlayer_Crosshair_Widget::PlayAnimationByName()
{
	//!줌인 상태면 Zoom_Fire를 실행, 아닐경우 Fire를 실행함//
	if (Player->bZoomIn) PlayAnimation(Zoom_Fire);
	else PlayAnimation(Fire);
}

에디터로 돌아와서 위젯으로 돌아가 애니메이션 생성하면 잘 바인딩 되는것을 볼수 있다.

애니메이션 트랙은 자신이 원하는 위젯을 추가하여 만들며 +트랙버튼을 누르면 여러가지로 만들수 있으면 Visibility, Transform, Padding 등 여러가지 방법이 있으면 지금은 크로스헤어 애니메이션을 사용하기 Transform으로 위치포인트를 찍어 주었다.

이런식으로 만든다음에 애니메이션을 사용하기위해 플레이어클래스에서 호출을 작성해줍니다.

void AThirdPersonCharacter::Fire()
{
	Player_HUD->PlayAnimationByName();
}

이렇게 애니메이션을 실행되는걸 볼수 있다.

반응형