【Unity】AnimationController間でStateMachineBehaviourのインスタンスを共有するSharedBetweenAnimatorsの挙動
SharedBetweenAnimatorsというAttributeがあります。
簡単に言えば「StateMachineBehaviour」のインスタンスを共有するAPIです。少しだけ動作に疑問があったので確認してみました。
インスタンスを共有するSharedBetweenAnimators
StateMachineBehaviourはAnimationControllerのStateに設定する、以下のタイミングで駆動してくれるスクリプトです。
- ステートに入ったタイミング
- ステートから抜けたタイミング
- ステートが動作してる
- 子ステートが動作してる
- IK動かしてる
- RootMotionでキャラクターを動かす
上手く使用すれば、特定のアニメーション(ステート)再生時にのみ処理を行うといった動作が期待出来ます。地面判定とか
このStateMachineBehaviourですが、AnimationController毎に異なるインスタンスが生成されます。AnimationControllerを動かすキャラクター毎に状態が違う可能性があるからです。また同様に各ステート毎に異なるインスタンスを持ちます。
要するにAnimationControllerが持つ、各State毎に複数持つ事が出来ます。つまり、
がある場合、以下のStateMachineBehaviourインスタンスが生成されます。
- 100*10*2で20000インスタンス
これが要らないケースもあります。そういった場合SharedBetweenAnimatorsを使用する事で、異なるAnimationControllerの同一Stateのインスタンスを共有します。
つまり、先程と同じ条件の場合、以下のStateMachineBehaviourインスタンスが生成されます。
- 1*10*2で20インスタンス
さらにステート間でインスタンスをシェアしたいなら、SubStateMachineを使用して親ステートにStateMachineBehaviourを設定すると良いかもしれません。
パラメータはシェアされる
SharedBetweenAnimatorsでシェアしたインスタンスですが、インスタンスが共有という事は変数等も今日ウユになります。
例えば下のようなAnimationControllerとSceneがあったとします。
- SampleというStateMachineBehaviourがあり、Tagというフィールドを持つ
- StateはIdleとRunに二種類で、各々異なるTagを持つ
- Animator1とAnimator2という二つのAnimatorがあり、同じAnimationControllerを参照している
これを実行した結果が、下の内容です。
- Animator1とAnimator2で同一のState.csを動かしているが、ステートのカウントは常に進む
- 異なるStateのStateMachineBehaviourでは値がリセットされ1からスタートしている
という事で、同じステートの同じStateMachineBehaviourではパラメータが共有されている事が分かります。
このため、例えば同一State間で共通して参照するコンポーネント等がある場合、どれか一つのStateMachineBehaviourに値を設定してやれば、以降は設定する必要が無くなります。
どんな時に使うべきか
使うべきタイミングは、ステートが動的に動かすフィールドを持たないStateMachineBehaviour等でしょうか。
例えばMatch Targetでキャラクターを動かすStateMachineBehaviourの場合、設定すべきパラメータは以下の通りです。
- MatchTargetの終着点
- アニメーションに対するMatchTargetの開始と終了タイミング
- MatchTargetで支点とする部位
終着点は動的かつキャラクター毎に設定する必要がありますが、それ以外はステート単位で共有しても問題無い項目です。
ですので、終着点は都度Animatorから取得しそれ以外の項目はシェアしても良いというアイディアが出ます。
他にも足音を鳴らす、Animator終了待ちイベントを発行する等も、StateMachineBehaviourを共有しても問題無さそうです。
StateMachineBehaviour全体でシェアするならStatic、同じステートでシェアするならSharedBetweenAnimatorsとなりそうです。
値がリセットされない
多分バグだとは思いますが、どうもSharedBetweenAnimatorsを使用すると値がリセットされないようです。
例えば上の例で言えば、ゲームの再生を終了して再度ゲームを再生すると、Entry5からスタートします。
ので、値が変動する物を使いたい場合、いずれかのAnimatorをAwake辺りのタイミングでリセットしてやる必要がありそうです。*1
関連
*1:というか、共有対象をフィールドにしてくれたらシンプルになりそうなんですけどね