【UE4】Character Movement Componentを使わずにルートモーションをする

[link-1]:https://docs.unrealengine.com/4.27/en-US/API/Runtime/Engine/Animation/UAnimInstance/ConsumeExtractedRootMotion/
[link-2]:https://docs.unrealengine.com/4.27/en-US/API/Runtime/Engine/Components/USkeletalMeshComponent/ConvertLocalRoot-/
[link-3]:https://www.unrealengine.com/ja/blog/featured-free-marketplace-content-september-2021
[link-4]:https://www.unrealengine.com/marketplace/en-US/product/close-combat-animset

:::note warn
よりよい方法が見つかったため、この記事ではなく、[【UE5】【修正版】Character Movement Componentを使わずにルートモーションする](https://qiita.com/Rinderon/items/5d7c838d5d2cc1206c1d)、をご参照ください。
:::

# やりたいこと

- ルートモーションを使いたい。
- だが、Character Actorクラス＋Character Movement Componentで作るほど大げさにはしたくない。
- 普通のActor (またはPawn)＋Skeletal Mesh Componentでサクっとやりたい。
- Blueprint で使えるノードが欲しい。

…をやるときに使える便利関数のメモ。

# 参考サイト

[UE4ルートモーションについてのメモ](https://qiita.com/unknown_ds/items/d3d802415c16101d47f1) を参考にさせていただきました。

# UAnimInstance::ConsumeExtractedRootMotion() について

上記の参考サイトの通り、Character Movement Componentを使用しないとルートモーションは適用されず、[UAnimInstance::ConsumeExtractedRootMotion()][link-1]を使って得られたTransformを、自前でアクタのTransformに作用させなくてはならない。
ところが、[UAnimInstance::ConsumeExtractedRootMotion()][link-1]から返ってくるのは、Component SpaceでのDelta Transformであり、アクタのTransformに直接作用させるにはひと手間必要となる。

Character Movement Componentのエンジンソースを辿って、便利関数を見つけたのでメモとして残しておく。

## USkeletalMeshComponent::ConvertLocalRootMotionToWorld()

[USkeletalMeshComponent::ConvertLocalRootMotionToWorld()][link-2]がその便利関数である。
この関数は、[UAnimInstance::ConsumeExtractedRootMotion()][link-1]の結果(Component SpaceでのDelta Transform)を与えると、World SpaceでのDelta Transformに変換してくれる。

# C++ソース例

UAnimInstanceを継承したクラスを用意する。
例）URootMotionAnimInstance

## RootMotionAnimInstance.h

以下のヘッダファイルを見ての通り、`ConsumeExtractedRootMotion()`をBlueprintに公開するのが目的である。

```C++:RootMotionAnimInstance.h
#pragma once

#include "CoreMinimal.h"
#include "Animation/AnimInstance.h"
#include "RootMotionAnimInstance.generated.h"

// Custom UAnimInstance class which have an utility to extract its root motion.
UCLASS(transient)
class ROOTMOTIONTEST_API URootMotionAnimInstance : public UAnimInstance
{
	GENERATED_BODY()
	
public:

	// Get current accumulated root motion, removing it from the AnimInstance in the process.
	// This function is only for exposing UAnimInstance::ConsumeExtractedRootMotion() to the Blueprint.
	UFUNCTION(BlueprintCallable, Category = "Root Motion Anim Instance",
		meta = (InAlpha = "1"))
		void ConsumeExtractedRootMotion(float InAlpha, bool& OutSuccess, FTransform& OutDeltaTransformInWorld);
};
```

## RootMotionAnimInstance.cpp

ここでは、[UAnimInstance::ConsumeExtractedRootMotion()][link-1]で取得したDelta Transformを、[USkeletalMeshComponent::ConvertLocalRootMotionToWorld()][link-2]でWorld系に変換して返している。

```C++:RootMotionAnimInstance.cpp
#include "RootMotionAnimInstance.h"

void URootMotionAnimInstance::ConsumeExtractedRootMotion(float InAlpha, 
	bool& OutSuccess, FTransform& OutDeltaTransformInWorld)
{
	USkeletalMeshComponent* SkelComp = GetOwningComponent();
	FRootMotionMovementParams Params = UAnimInstance::ConsumeExtractedRootMotion(InAlpha);
	if (SkelComp != nullptr && Params.bHasRootMotion)
	{
		OutSuccess = true;
		OutDeltaTransformInWorld =
			SkelComp->ConvertLocalRootMotionToWorld(Params.GetRootMotionTransform());
	}
	else
	{
		OutSuccess = false;
		OutDeltaTransformInWorld.SetIdentity();
	}
}
```

# Blueprintでの使用例

Pawnを継承したクラスBP_RootMotion_Pawnを作成。
試していないが、素のActorを継承したクラスでも大丈夫なはず。

## Componentsタブ

Characterクラスに比べて非常にシンプルに組める。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/a8dea237-da4e-c1d1-c4e6-86e9191d2bc4.png)

## Event Tick

C++側でWorld系のDelta Transformに変換済みなので、シンプルに`AddActorWorldTransform`に渡すだけ。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/041c842d-b9b0-4787-f87a-d4546baba379.png)

## 実行例

![20210917_01_RootMotionInPawn.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/7631aafe-5099-9507-511c-7262369ec4f3.gif)

一応、ワールド原点から外した位置・角度で動作をさせている。

なお、使用したアニメーションは[2021年9月の無料マーケットプレイスコンテンツ][link-3]の[Close Combat Animset][link-4]のもの。