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など複数レイヤー間でのアニメーションの融合は不可能;