【Unity】Animatorのスパゲティなステートマシンを整理する
UnityのAnimatorはノードベースのステートマシンでアニメーションを制御する機能を持ちます。しかしながら、どんどんノードを繋げていくと昨日の記事のように複雑なグラフ図が出来上がってしまいます。
その辺りを踏まえて、自分なりに「こうすれば良かろうなのだ」みたいなのを考えてみます。
変形!ロボから飛行機へ、飛行機から戦車へ、戦車からロボへ。…好きかも https://t.co/Bhk0pwcB7S pic.twitter.com/oAINRIqSty
— 椿 (@tsubaki_t1) October 23, 2015
前回の3形態に変形するロボを例として、ちゃんと手直ししていきます。
ノードを整理する
このノード軍が複雑な理由は一つ、お互いに参照しあっているノードが存在する事です。このロボは飛行機・戦車・ロボに変形し各形態で各々のアクションが存在するので、非常に複雑なフローが出来てしまっています。
これを各モード毎のサブステートでまとめてしまいます。やり方はサブステートマシン作ってソコへ各ステートをドラッグ&ドロップです。
ただし、このままでは他のサブステートへ直接接続しており参照関係が非常に複雑になってしまうので、一旦サブステートの持つステートへの接続は破棄し、各サブステート間でつなぎ直します。
なお、サブステートからステートを取り出すには、親レイヤーを表すステート(親がBase LayerならばBaseLayer)へドラッグ&ドロップすればOKです。
パラメータ
この制御に使用していたTriggerは、実は少しに扱いにくいパラメータです。Triggerの特性は「一度通ったらOFFになる」なので、想定外の動作を行う事があります。
例えば、Triggerを事前に打っておいたら、トリガーが動くタイミングになったらいきなり動いてしまった…なんてこともあり得ます。
ジャンプとスライディングをAnimatorのTriggerで管理している場合、スライディング・ジャンプと押すと、スライディングが終わると即ジャンプが発動する…なんて事もあり得ます。
他にも、Planeモード時にTankへの変形を行い、その途中でRobo→Planeの順番でTriggerを入力したらどうなるか。初期のステートではPlaneはTankに変形後、再び変形する訳ですが、アニメーションの順番はPlane→Roboの順番です。この食い違いは単純に実行優先度がPlane>Roboだったからです。
等々、いろいろとあるので個人的にはモードやステートといった物はIntやBoolで管理するのが良いかなと思っています。
そうして善かれと思って作ったパラメータがこちら。enumがあればもっとクールでしたが、無いので運用でカバー。
トランジションはこんな感じ
EntryとExit
ステート内での収支はEntryとExitにお任せします。
このEntryとExitはは、サブノードの開始時にEntryから入り、Exitに届くとサブノードから出て判定を行います。サブノード単位で制御を管理していると、EntryとExitを使って制御が出来る訳です。
例えば、戦車モードから飛行機モードへ変形してみます。
Tankのサブステートから開始です。まずはTankでモードがPlaneになったので、TankToPlaneステート(変形するアニメーション)を通り、Exitへ出ます。
いったんTankサブステートから抜け、RobotかPlaneかどちらかへ移行します。今回はPlaneモードを指定しているのでPlaneサブステートへ。
Planeサブステートでは特に何かを指定されていないので、Entryから入り、Planeへ着地します。
これはこれで上手く動くのですが、ここにキャンセルが入ると途端に面倒くさい事になります。つまり、モーションをキャンセルして他のモーションへ移行するケースです。
それが勝利ポーズといった特殊なアクションならば、何処からでも条件が揃えば呼べるAnyStateを使うのが妥当だと思いますが、キャンセル技のような物ならば素直にAnimator.Play
やAnimator.CrossFade
を使用してステートをスクリプトでジャンプしてしまった方が理に適ってるような気がします。*1勿論ゲームにも寄りますが。
ステートのフォーカスが勝手に動かないように
最後にちょっとしたTipsですが、今回のようにサブステートへビュンビュン飛ぶ場合、どのサブステートに居るのか確認したい場合があります。
そんな時はAnimatorのAuto Live Linikを外して、アニメーションを追わないようにします。
Auto Live Linikが外れている場合でも、現在のステートを持つサブステートが青くなるので、追跡は割と簡単に出来ます。
関連記事
*1:Unity 5.3.1でCrossfade中にCrossfade出来ない問題も解決しましたし。