【UE4】ConstructionScriptでのGetSocketTransformがおかしい？(BP)＋フレームレートの取得(C++)／第13回UE4ぷちコン進捗 - 2020/03/21

[1]:http://historia.co.jp/ue4petitcon13
[2]:https://docs.unrealengine.com/en-US/API/Runtime/Engine/Animation/UAnimSequence/GetNumberOfFrames/index.html
[3]:https://docs.unrealengine.com/en-US/API/Runtime/Engine/Animation/UAnimSequenceBase/GetPlayLength/index.html
[4]:https://docs.unrealengine.com/en-US/API/Runtime/Engine/Animation/UAnimSequence/GetFrameRate/index.html


[株式会社ヒストリアさん主催の第13回UE4ぷちコン][1]の作業進捗。
昨夜ハマったネタの備忘録として。

# ConstructionScript × GetSocketTransform

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/dd7bb0bd-c3cc-2eaf-a602-1b93aa59db5c.png)

上は、コンストラクションスクリプト上で、ドラゴンの Head ボーンの World Transform を取得するノードグラフ。

> Draw Debug Coordinate Cross は、ただ単に座標軸を書くためのもの。
> UE4 標準の Draw Debug Coordinate System もよく使うが、マイナス軸の表示も欲しいときはこういうのを使っている。

この結果、エディタのビューポートに表示される絵はこうなる：

![20200322_1210.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/41f04939-fe77-89e4-e206-4f379ee0cc9a.png)

頭と全然違う位置に座標軸のデバッグ表示が出てしまっている。

> ドラゴンの体を通るピンクのラインは、ビューポート内の Show メニューの Developer > Bones を ON にしたもの。

おおむね昨日一日、この問題で悶絶していた。
もともとは、頭（≒顎）に対する餌の位置を探していたので、逆行列の計算とかがアレコレ入っていて、掛け算の順番を間違ったか？とか、World Spaceじゃなくて、Component Spaceなのか？とか、そっちの方を必死に追いかけてしまっていた。

ふと、思い立って、Tickでもデバッグ表示してみたのがこちら：

![20200322_1211.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/358170/0fbafbbe-29e0-5064-abfe-e3e31d00c100.png)

あってんじゃん！

> ボーン表示はコンソールコマンド `show Bones`

ということで、今のところ、Construction Script で Get Socket Transform をすると、正しくない値が返ってくる可能性があるかもしれません。実行中の Get Socket Transform は正しい値を返します。(UE4.24.3)

例えば、グレイマンでは正しく出るのではないかとか、Get Socket Location ならどうなのか、など、他のシチュエーションでの追加調査をする余裕はないので、このまま放置します。すみません。（…ぷちコン締め切りまで１週間！）

ざっくり何をやったかだけ列挙すると：

- Construction Script での動作
- Skeletal Mesh Component (=ドラゴン) は、Yaw回転が-90度で、２倍のスケール
- Skeletal Mesh Component の Override Animation Data で、エディタ上で表示するアニメーションとフレーム番号を指定。
    - 【追記】IsPlaying = True, PlayRate = 0.0 でも、IsPlaying = False, PlayRate = 1.0 でも、状況は変わらず。
- その後、Get Socket Transform で頭ボーンの Transform を取得

こういう流れでやっています。

# AnimSequenceからフレームレートなどを取得する

Blueprintでは取得できない、アニメーションシーケンスの総フレーム数、フレームレートなどについて。
もう取れないものだとずっと諦めていたのだが、今更ながら、C++でサクっと取得できることに気づいた。

- [UAnimSequence::GetNumberOfFrames()][2]： 総フレーム数の取得
- [UAnimSequenceBase::GetPlayLength()][3]： 総再生時間(秒)の取得（Blueprint 版もある）
- [UAnimSequence::GetFrameRate()][4]： フレームレートの取得

C++ で Blueprint Function Library を作って、一気に便利に取得するようにした例：

```C++:GetAnimFrameInfo()
void UMyBlueprintFunctionLibrary::GetAnimFrameInfo(UAnimSequence* InAnimSequence,
	bool& OutSuccess, int& OutNumFrames, float& OutPlayLength, float& OutFrameRate)
{
	if (!InAnimSequence)
	{
		UE_LOG(LogMyLibrary, Error, TEXT("GetAnimFrameInfo()  InAnimSequence must not be a nullptr."));
		OutSuccess = false;
		return;
	}

	OutSuccess = true;
	OutNumFrames = InAnimSequence->GetNumberOfFrames();
	OutPlayLength = InAnimSequence->GetPlayLength();
	OutFrameRate = InAnimSequence->GetFrameRate();
}
```

【注意】自作関数GetAnimFrameInfo()の第一引数の型が`const UAnimSequence*`ではなく、`UAnimSequence*`なのは、`GetPlayLength()`だけconst関数ではないため。（泣く泣く）


## ついでに便利そうな関数も

> 後日談 (2020/05/01)
> UAnimSequenceBase::GetTimeAtFrame() も UAnimSequence::GetFrameAtTime() も、WITH_EDITOR 関数だった。
> パッケージビルドをするとビルドエラーが出る。
> これらは、Editor 専用モジュールでしか使ってはいけない。

```C++:フレーム番号と時間(秒)の変換

#if WITH_EDITOR

float UMyBlueprintFunctionLibrary::GetAnimTimeAtFrame(const UAnimSequence* InAnimSequence, int InFrame)
{
	if (!InAnimSequence)
	{
		UE_LOG(LogMyLibrary, Error, TEXT("GetAnimTimeAtFrame()  InAnimSequence must not be a nullptr."));
		return 0.0f;
	}

	return InAnimSequence->GetTimeAtFrame(InFrame);
}


int UMyBlueprintFunctionLibrary::GetAnimFrameAtTime(const UAnimSequence* InAnimSequence, float InTime)
{
	if (!InAnimSequence)
	{
		UE_LOG(LogMyLibrary, Error, TEXT("GetAnimFrameAtTime()  InAnimSequence must not be a nullptr."));
		return 0.0f;
	}

	return InAnimSequence->GetFrameAtTime(InTime);
}

#endif // WITH_EDITOR
```

こちらは`const UAnimSequence*`型で行ける。