It’s often pretty useful to be able to access UMG-created animations from C++. Especially as you move more and more logic from Blueprints into C++, UMG animations can seem like the last hold-out.
With a custom subclass of
UUserWidget
, we can create a map of FName
to
UWidgetAnimation*
and access the animations by name from C++.
Let’s see how to do this:
CustomUserWidget.h
#pragma once
#include "CustomUserWidget.generated.h"
UCLASS(Abstract)
class UCustomUserWidget : public UUserWidget
{
GENERATED_BODY()
public:
virtual void NativeConstruct() override;
UWidgetAnimation* GetAnimationByName(FName AnimationName) const;
bool PlayAnimationByName(FName AnimationName,
float StartAtTime,
int32 NumLoopsToPlay,
EUMGSequencePlayMode::Type PlayMode,
float PlaybackSpeed);
protected:
TMap<FName, UWidgetAnimation*> AnimationsMap;
void FillAnimationsMap();
};
Notes:
- Our PlayAnimationByName isn’t entirely needed, but it can be a helpful wrapper for the regular PlayAnimation function
CustomUserWidget.cpp
#include "CustomeUserWidget.h"
void UCustomUserWidget::NativeConstruct()
{
FillAnimationsMap();
// Call Blueprint Event Construct node
Super::NativeConstruct();
}
void UCustomUserWidget::FillAnimationsMap()
{
AnimationsMap.Empty();
UProperty* Prop = GetClass()->PropertyLink;
// Run through all properties of this class to find any widget animations
while (Prop != nullptr)
{
// Only interested in object properties
if (Prop->GetClass() == UObjectProperty::StaticClass())
{
UObjectProperty* ObjProp = Cast<UObjectProperty>(Prop);
// Only want the properties that are widget animations
if (ObjProp->PropertyClass == UWidgetAnimation::StaticClass())
{
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;
}