1. はじめに
UnityのAnimatorControllerは,ステートの状態が多くなると管理しづらくなる(矢印だらけになる)という問題がある.
そこでUnity公式のサンプルではどのようにアニメーションを実装しているのか知るためソースを読んだ.
2. 前知識
まずソースを読む前に公式のドキュメントを読んでみる.
FPSSample/Animation.md at master · Unity-Technologies/FPSSample · GitHub
三人称視点
FPSSampleはマルチプレイヤーシューティングなので,アニメーションをネットワーク上で同期(複製,ロールバック,予測,ラグ処理など)するためにカスタムPlayable Graphを使用している.一人称視点
ローカルクライアントでのみ再生されるので,AnimatorControllerを使用している. AnimatorControllerを使うとは言ったが,PlayableAPIを使わないとは言っていない(
PlayableAPIのドキュメントも読んでおく.
* Playable API - Unity マニュアル
* PlayableGraph - Unity マニュアル
* ScriptPlayable と PlayableBehaviour - Unity マニュアル
* Playable の例 - Unity マニュアル
3. 一人称視点の実装
まず簡単そうな方から読んでいく.
3.1 ファイル構成
Robot_A_1Pのコンポーネント
3.2 Animatorで再生される大まかな流れ
1. AnimGraph_AnimatorController.csでAnimatorControllerの参照を持つ
2. AnimGraph_Stack.csでAnimGraph_AnimatorController.csの参照を持つ
3. AnimStateController.csでAnimGraph_Stack.csの参照を持つ
AnimatorはAnimationPlayableOutputのsource Playableを再生するので*1それによりアニメーションが再生されている
3.3 PlayableGraph
ソースを読んで作った図.
この1枚にすべてが集約されている.
3.4 AnimGraph_AnimatorController.cs
まずソースを簡略化してみる gist.github.com
- RuntimeAnimatorControllerを保持している
- AnimGraphAssetを継承している
- 内部クラスとして,IAnimGraphInstanceを継承したInstanceがある
親クラスとインターフェースをみる gist.github.com gist.github.com
- InstantiateがInstatiateになっているが,おそらくUnityのAPIと被らないようにするためだと思われる
内部クラスInstanceをみる gist.github.com
- 主な処理をCharacterAnimatorControllerに委譲していることが見て取れる
- EntityManagerがあるので,ECSを使っている模様
CharacterAnimatorControllerをみる
コンストラクタとvoid Update()が大きい処理をしているので,その2つをみていく4.1 CharacterAnimatorControllerのコンストラクタ
gist.github.com- AnimatorControllerPlayableでRuntimeAnimatorControllerをラップしてる
- AnimatorController内のパラメータへのハッシュを,AnimStateParams型やActionStateParams型の配列として保持してる(文字列でパラメータにアクセスするよりint型のハッシュでアクセスする方が早いから)
パラメータ一覧
4.2 CharacterAnimatorControllerのUpdate gist.github.com gist.github.com - AnimatorController内のパラメータを更新している
以上からCharacterAnimatorControllerのUpdateに,アニメーションがとるべき次の状態(CharacterPredictedData.LocoStateや.Action)を渡すことで,アニメーションの状態(AnimatorController内のパラメータ)を更新していることがわかった.
3.5 AnimGraph_Stack.cs
簡略化 gist.github.com
- AnimGraph_AnimatorController.csと同じような構造
- しかしRuntimeAnimatorControllerではなく,List<AnimGraphAsset> を保持している
内部クラスGraphInstance gist.github.com コンストラクタで下図の部分の処理をしてる
3.6 AnimStateController.cs
簡略化 gist.github.com
- コンポーネントが非アクティブになるとDeinitialize()が呼ばれる
- public関数が4つある
public関数の中身をみる(簡略化ver) gist.github.com
- Deinitialize()でグラフの終了処理
- UpdatePresentationState()でグラフロジックを更新
- ApplyPresentationState()でグラフに現在のStateを適用(多分)
Initializeの中身をみる(簡略化ver) gist.github.com
- PlayableGraphを作って再生している
- AnimationPlayableOutputを作る時に,情報源としてAnimGraphのOutputを使っている
Initializeで下図の部分の処理をしている