Posted at

UE4 アニメ―ションBPをC++クラス継承にしてアクセスする


概要

UnrealEngine のアニメーションブループリントをC++クラス継承する形にして処理を移譲できるようにしてみます。

アニムグラフのステートマシン遷移ルールでの呼び出しもテストしてみます。


環境

Windows10

Visual Studio 2017

UnrealEngine 4.22


参考

以下を参考にさせて頂きました。

https://wiki.unrealengine.com/Animation_Blueprint,_Set_Custom_Variables_Via_C%2B%2B

UE4ドキュメント-遷移ルール


実装


アニメーションBPの作成

対象のスケルトンを右クリック -> [作成する] -> [Animブループリント]

例:ThirdPersion_AnimBP.uasset

animBP.png


C++クラスの作成

UAnimInstanceを継承したC++クラスを作成をします。

コンテンツブラウザにて、[新規追加] -> [新規C++クラス...]

例:MyAnimInstance.h, MyAnimInstance.cpp

ParentClass_AnimInstance.png

オーバーライド可能なメソッドをいくつか実装しています。


MyAnimInstance.h

#include "CoreMinimal.h"

#include "Animation/AnimInstance.h"
#include "MyAnimInstance.generated.h"

/**
*
*/

UCLASS()
class TEST_API UMyAnimInstance : public UAnimInstance
{
GENERATED_BODY()

public:
// コンストラクタ
UMyAnimInstance(const FObjectInitializer& ObjectInitializer);

// アニメーションの初期化時
virtual void NativeInitializeAnimation() override;
// アニメーションの更新時
virtual void NativeUpdateAnimation(float DeltaTime) override;
// アニメーション評価後
virtual void NativePostEvaluateAnimation() override;
// アニメーションの終了化時
virtual void NativeUninitializeAnimation() override;

// イベント開始時
virtual void NativeBeginPlay() override;
};


cpp側です。メソッドの中身はとりあえずUE_LOG出力にしておきます。


MyAnimInstance.cpp

#include "MyAnimInstance.h"

UMyAnimInstance::UMyAnimInstance(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{}

void UMyAnimInstance::NativeBeginPlay()
{
Super::NativeBeginPlay();

UE_LOG(LogTemp, Log, TEXT("UMyAnimInstance::NativeBeginPlay()"));
}

void UMyAnimInstance::NativeInitializeAnimation()
{
Super::NativeInitializeAnimation();

UE_LOG(LogTemp, Log, TEXT("UMyAnimInstance::NativeInitializeAnimation()"));
}

void UMyAnimInstance::NativeUpdateAnimation(float DeltaTime)
{
Super::NativeUpdateAnimation(DeltaTime);

UE_LOG(LogTemp, Log, TEXT("UMyAnimInstance::NativeUpdateAnimation()"));
}

void UMyAnimInstance::NativePostEvaluateAnimation()
{
Super::NativePostEvaluateAnimation();

UE_LOG(LogTemp, Log, TEXT("UMyAnimInstance::NativePostEvaluateAnimation()"));
}

void UMyAnimInstance::NativeUninitializeAnimation()
{
Super::NativeUninitializeAnimation();

UE_LOG(LogTemp, Log, TEXT("UMyAnimInstance::NativeUninitializeAnimation()"));
}



追記1:UAnimInstance の アニメーション関連系のC++メソッドについて

アニメーションブループリントにて使用される以下4つのメソッド

BlueprintInitializeAnimation

BlueprintUpdateAnimation

BlueprintPostEvaluateAnimation

BlueprintBeginPlay

これらはオーバーライドできませんので、ブループリント専用です。

オーバーライド可能なメソッドは以下のようです。


AnimInstance.h

virtual void NativeBeginPlay();

virtual void NativeInitializeAnimation();
virtual void NativeUpdateAnimation(float DeltaSeconds);
virtual void NativePostEvaluateAnimation();
virtual void NativeUninitializeAnimation();

NativeInitializeAnimationはアニメ―ション開始時、NativeUninitializeAnimationはアニメ―ション終了時、NativeUpdateAnimationとNativePostEvaluateAnimationは更新されるフレームのようです。

また、上のテストコードでは継承元のメソッドを実行していますが(Super::Native***())、継承元クラスUAnimInstanceの該当メソッドの処理は空なのでなくても(今のところは)問題はありません。ただ将来のバージョンではどうなるかわからないので呼んでおくほうが無難ではあります。


追記2:UAnimInstance のステートマシン関連系のC++メソッドについて

ステートマシンへのステートや遷移ルールの追加削除は以下のメソッドで行うことができるようです。


AnimInstance.h

void AddNativeTransitionBinding(const FName& MachineName, const FName& PrevStateName, const FName& NextStateName, const FCanTakeTransition& NativeTransitionDelegate, const FName& TransitionName = NAME_None);

bool HasNativeTransitionBinding(const FName& MachineName, const FName& PrevStateName, const FName& NextStateName, FName& OutBindingName);
void AddNativeStateEntryBinding(const FName& MachineName, const FName& StateName, const FOnGraphStateChanged& NativeEnteredDelegate);
bool HasNativeStateEntryBinding(const FName& MachineName, const FName& StateName, FName& OutBindingName);
void AddNativeStateExitBinding(const FName& MachineName, const FName& StateName, const FOnGraphStateChanged& NativeExitedDelegate);
bool HasNativeStateExitBinding(const FName& MachineName, const FName& StateName, FName& OutBindingName);

ステートマシン自体の追加はUAnimInstanceクラスには見当たりません。


親クラスの差し替え

アニメーションブループリントの親クラスを差し替えます。

[ファイル] -> [ブループリントの親を変更]

superclass.png

親クラス選択ウィンドウにて選ぶと、アニメーションBPウィンドウ右側の表示が変わり、親クラスが切り替わっていることがわかります。

super_class_name.png

これで準備はできました。


実行テスト


C++メソッド呼び出し確認

アニメ―ションを再生するとアウトプットログに各NativeメソッドのUE_LOGが出力されており、C++メソッドが呼び出されていることが確認できます。

OutputLog.png

1か所だけUpdateが呼ばれて、Evaluateが呼ばれない箇所がありますが、処理落ちでしょうか?


ステートマシンからの呼び出し確認

ステートマシンの遷移ルール(トランジッション)から呼び出せるかテストしてみます。

以下のようなメソッドを追加します。


MyAnimInstance.h

UFUNCTION(BlueprintPure)

bool TestRule();

コンポーネントから情報を取得して結果を遷移ルールとしています。


MyAnimInstance.cpp

bool UMyAnimInstance::TestRule()

{
UE_LOG(LogTemp, Log, TEXT("MyTestRule!"));

auto _Pawn = TryGetPawnOwner();
if (_Pawn == nullptr)return(false);

bool _IsFall = _Pawn->GetMovementComponent()->IsFalling();

return(_IsFall);
}


ステートマシンです。

テストには[Idle/Run] から [JumpStart] への遷移部分を使います。

StateMachine.png

[Idle/Run] から [JumpStart] へのトランジッションに上で追加した TestRuleメソッドを呼び出してみます。

Transision.png

以下のようなワーニングがでました。


コンパイル結果

Node  Result  uses potentially thread-unsafe call  Test Rule . Disable threaded update or use a thread-safe call. Function may need BlueprintThreadSafe metadata adding. 


どうやらアニムグラフでのメソッドは明示的にスレッドセーフを宣言しないとメインスレッドで処理されるようです。

回避するにはスレッドセーフを宣言するか、イベントグラフにてメソッドを実行し(メインスレッドで実行し)結果を変数経由で受け取るしかないようです。

今回は特にメインスレッドと競合するような処理ではないので、スレッドセーフを宣言するようにメタ情報を修正してワーニングを回避します。


MyAminInstance.h

UFUNCTION(BlueprintPure, meta = (BlueprintThreadSafe))

bool TestRule();

コンパイル&ホットリロード後、アニムグラフを確認するとワーニングがなくなりました。

Transision2.png

実行すると、UE_LOGが大量にアウトプットログに表示されており、TestRuleメソッドが呼び出されていることが確認できます。

TestRule_OutputLog.png


まとめ

アニメーションブループリントをC++クラスを継承する形にすると、複雑な処理をC++側に持って行ってメソッド化できるためアニメ―ションBPコードが少なくなると思います。(自分は特にBPがごちゃごちゃになりやすいので)

特に複雑なステートマシンなどを作る場合などは有用な手段ではないかと思います。(ただしクラス継承は深くなってしまいますが)