c++ WidgetAnimation 실행
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();
}
이렇게 애니메이션을 실행되는걸 볼수 있다.