Custom Animator
イントロ
Quantumの決定性アニメータはUnityのMecanim Controllerの情報をベイクすることで作用します。ステート、ステート間移行、モーションクリップなどの全ての設定をインポートします。
この機能の主なメリット は、マシン間のアニメーションを100%同期するようにコントロールできることです。ロールバックによって数フレーム前に移行が発生したことが通知されると、アニメーションが正しいステートへと切り替えます。つまり、アニメーションに基づいたかなり正確なティック が提供されます。これは全てのクライアントでシミュレーションが完全に同期されていることが求められる格闘ゲームやスポーツゲームなどで必要とされるものです。
アニメータはSDK 1.2.xバージョンには搭載されていたものでした。このアニメータツールの強化をやめたのは現在Unityのmecanim上にある依存性のためと、このドキュメントが書かれた日までに、Unityがまだ新しい安定したアニメーションツールをローンチしていなかったためです。
そのため、アニメータをquantum.stateおよびquantum.systemsプロジェクトにインポート、そしてニーズに合わせて変更、再ビルドできるオープンソースコードとして保持することとしました。
このドキュメントではカスタムアニメータのインポート方法とプロジェクト内での使用方法について説明します。Quantum 1.2.xバージョンでは、まだデフォルトのアニメータを搭載していますので、こちらは置き換えになります。
PS: このドキュメントではQuantum 1.2.xバージョンに焦点を絞った説明をしていますが、お使いのバージョンがQuantum 2.0の場合は、V2ドキュメントの同様の記事を参照してください。
カスタムアニメータパッケージをインポートする
- ここからカスタムアニメータをダウンロードします。;
- カスタムアニメータを解凍し、QuantumCustomAnimator_stateフォルダのコンテンツをquantum.stateプロジェクトに入れます。;
- QuantumCustomAnimator_systemsのコンテンツを- quantum.systemsプロジェクトに入れます。;
 PS: 独自のカスタムアニメータコードを保持するため変更できるファイルがあります。クラスの名前はオリジナルのアニメータと同じですが、これらはすべて- Quantum.Custom.Animator名前空間の配下にあり、お互いのみを参照するため旧アニメータのクラス・構造体を使用することはありません。
- このパッケージにはFrame.InitUserメソッドの部分実装が搭載されています。このメソッドはCustomAnimatorUpdaterの初期化を処理します。既にプロジェクトに同メソッドの部分実装がある場合はInitUser内で忘れずにInitializeAnimatorUpdaterメソッドへの呼び出しを含めるようにしてください。そして、このパッケージからFrame.User.csファイルをインポートしないでください。;
- 自分のソリューションに全てそろったら、quantum.systemsソリューションをビルドします。;
- Unityで、プロジェクトにQuantumCustomAnimator.unitypackageファイルをインポートします。;
- 1.2.4.2  より前のバージョンを使用されている場合は、QuantumAOT生成での修正をインポートする必要があります。codegen_unity.zipを解凍し、コンテンツを<YourProjectRoot>/tools/codegen_unityフォルダに入れます。その後、 自分のquantumソリューションを再度リビルドします。
これでビルドと実行の初めのステップが完了しました。それでは、コンポーネント、アセット、ベイキングツールを実際に使用していくにあたっての説明を以下に記します。
カスタムアニメータを使用する
- Insert the CustomAnimatorコンポーネントをエンティティに挿入します。 : - use CustomAnimator;
- Unityでは、 - CustomAnimatorGraphタイプのデータアセットを新しく作成します。このアセットはUnityのmecanim controllaerに関連する情報の蓄積を担います。カスタムアニメータを設定するためにはquantum側でこのアセットを見つける必要があります。 アニメータアセットを見つける方法:
 - var animatorGraphAsset = DB.FindAsset<CustomAnimatorGraph>("MyAssetGUID");
- CustomAnimatorコンポーネントを初期化する: 
 - CustomAnimator.SetCustomAnimatorGraph(&knight->CustomAnimator, animatorGraphAsset);
- Unityと同様アニメータに読み取り・書き込みを行うには、GettersとSettersを使用します。 
C#
// Getters
CustomAnimator.GetBoolean(&fighter->Animator, "Defending");
CustomAnimator.GetBoolean(&fighter->Animator, "Direction");
CustomAnimator.GetBoolean(&fighter->Animator, "Speed");
// Setters
CustomAnimator.SetBoolean(&fighter->Animator, "Defending", true);
CustomAnimator.SetInteger(&fighter->Animator, "Direction", 25);
CustomAnimator.SetFixedPoint(&fighter->Animator, "Speed", FP._1);
- 重要な留意点として、ここでは Unityのトリガーパラメータ がブーリアンのように作用します。つまり、パラメータをトリガーするのに、 - SetBoolean(&fighter→Animator, "MyTrigger", true)を使用してtrueに設定し、次のティックで- SetBoolean(&fighter→Animator, "MyTrigger", false)を設定しトリガーが再度有効化しないようにする必要があります。各トリガーパラメータを毎ティックごとにfalseに設定するプレアニメーションシステムもあります。;
- CustomAnimator.qtnファイルで以下の配列のサイズを変えることで カスタムアニメータがサポートしているパラメータの量を増やすことが できます。
C#
array<CustomAnimatorRuntimeVariable>[8] AnimatorVariables;
- 各 - AnimatorStateにはカスタムアセットにリファレンスを作成できる- AssetRefがあります。Unityのアニメータから情報を多く引っ張り、Unityのベイキングプロセスを拡張することも、これらの情報をカスタムアセットに保存してステート上で参照することも可能なので、シミュレーションで読み取ることができます。例えば、- FPAnimationCurvesの形式でベイクされたhitbox・hurtbox情報をもつアセットを作成できます。Unityイベントの名前・時間をアセットに保存できるため、シュミレーション上でアニメーションイベントがいつ発生するかなど把握することができます。;
- 自分の - SystemSetup.csファイルで、以下の置換を行います。:
C#
// Old
new Core.AnimatorSystem(),
// New
new CustomAnimatorSystem(),
- Unityで、コンテキストメニューCreate/Quantum/CustomAnimatorGraphからカスタムアニメータグラフアセットを作成します。
デフォルトステートでは以下の様な構成になっています。:
 
- Controllerフィールドを使用してUnityのAnimator Controllerアセットを参照し、- Import Mecanim Controllerボタンをたたきます。それから、ステート、移動、パラメータなどのアニメーション情報フィールドを確認してください。:
 
- EntityPrefabRootクラスを開き、- public CustomQuantumAnimator CustomQuantumAnimator;フィールドを追加します。置換が目的ですので、希望する場合は- QuantumAnimatorフィールドを削除することもできます。;
 PS: このファイルは、Quantumのバージョンアップグレードで上書きされる可能性があります。必要に応じてカスタムコードは再度挿入するようにしてください。
- アニメーション化するGameObjectsに - CustomQuantumAnimatorコンポーネントを追加します。もちろん、- EntityPrefabRootは必要なので追加したコンポーネントへの参照を、上記の説明で作成したフィールドを使用して作成してください。;
 
- On your EntityPrefabViewUpdaterに、Animatorコンポーネントを既定のエンティティから受け取る行がありますが、ここが代わりにCustomAnimatorを検索するようになりました。そのため、行の入れ替えを行います。:
C#
// Old
if (instance.QuantumAnimator) {
  var animator = Entity.GetAnimator(entity);
  if (animator != null) {
    instance.QuantumAnimator.Animate(animator);
  }
}
// New
if (instance.CustomQuantumAnimator) {
  var animator = Entity.GetCustomAnimator(entity);
  if (animator != null) {
    instance.CustomQuantumAnimator.Animate(animator);
  }
}
- 最後に、UnityのAnimatorコンポーネントを自分のオブジェクトに追加します。EntityPrefabRootのある同じオブジェクトに配置されるか、子オブジェクトに配置される可能性もあります。:
 
quantumコードでの置換が完了したので、今度はUnityサイドで置換を行います。Unityのmecanim controllerから直接ベイクした、情報を持つCustomAnimatorGraphもあります。準備が整いました。
コードの一部には簡単なコメントが付けられています。Quantumサイドには、AnimatorConditionsなど内部ステートマシンそのものに関連するものすべてがあります。AnimatorConditionsはAnimatorTransitions、AnimatorVariables (パラメータ)、Layers、Motionsなどで使用されています。
Unityサイドでは、Custom Animator Graphアセットのカスタムエディタの描写に関連するコードとベイキング手順の処理を行うすべてのコード(これは今後より多くのデータを衝突情報のFPAnimationCurves、Unityのアニメーションイベントなどのアニメータアセットにベイクするために確実に拡張することになります)があります。
既知の問題
CustomAnimatorにはデフォルトで以下の通り挙げる既知の制限があります。
- 階層ステートサポートなし;
- Unityのアニメーションイベントサポートなし;
- モーションを持たない(アニメーションクリップがない)ステートに対するサポートなし;
- Layersメニューのサポートなし、つまりAvatar MasksやBlendingなど複数レイヤー間でのアニメーションの融合は不可能;