このブログで使用しているUnityのVer
・Unity 2022.3.19f1
こんちゃっす!個人でゲーム制作しています、えきふるです!
ゲーム制作でアニメーションをつけていて、プレイヤーがボタンを押したら今のアニメーションをキャンセルして別のアニメーションに遷移して欲しいな…とか、ダメージモーション中に追加でダメージ喰らったらそのタイミングでまたダメージモーションの最初に遷移して欲しい…とか良くありますよね。
そんなお悩みを解決!今回はInterruption SourceとOrdered Interruptionを使った遷移の割り込みについて紹介していきます。
↓こんな感じで遷移中に割り込みができるように!やったね!
今回の記事で学べること
・Interruption Sourceとは何か?遷移の割り込みとは?
・Ordered Interruptionとは何か?遷移の優先度とは?
・Interruption Sourceの具体的な使い方と注意点
それでは見ていきまっしょい!
遷移の割り込みとは:概要
遷移の割り込みの前に、まず遷移について。
Animatorウインドウでのステートの繋ぎ方やトランジションに条件を付けることで、ステート間を任意にブレンドさせながら移動させる事ができました。
これがアニメーションの遷移になります。
この時、ステートからステートへの遷移中に他の遷移条件を満たした際、
今の遷移(ステート間の移動)は一旦止めて、別の遷移に移動する事を「遷移の割り込み」と言います。
例えば下記の画像ではIdleというステートからMove02への遷移中にIdleからMove01の遷移条件が成立、
遷移途中だけどそっち側の遷移にアニメーションが移動した(遷移の割り込みが発生した)例になります。
冒頭で話したような格ゲーとかでよくある「ボタンキャンセル」みたいなやつですね。
この遷移の割り込み条件をInterruption SourceとOrdered Interruption、2つの項目を駆使して設定していきます。
それでは遷移の割り込み方法について、まずは公式マニュアルの説明を確認してみましょう!
基本は公式の説明なのよ!
遷移の割り込み
Interruption Source と Ordered Interruption プロパティを使って、遷移の割り込みの仕方を制御します。
遷移の順序は、概念的に説明すると、遷移がキュー (順番に待機している状態) のようになっていて、最初に挿入された遷移から最後に挿入された遷移の順に、パースされます。
Interruption Source プロパティ
AnyState の遷移は、常にキューの先頭に加えられます。その後、他の遷移が Interruption Source の値に基づいてキューに加えられます。
Ordered Interruption プロパティ
Ordered Interruption プロパティによって、予約されたものがどのようにパースされるかが変わります。
その値によって、予約されたもののパースは以下のリストにある異なるタイミングで終了します。
https://docs.unity3d.com/ja/2023.2/Manual/class-Transition.html#TransitionInterruption
わかんねぇふる…
うん、難しいですね。
1つ1つ挙動を確認しながら丁寧にみていきましょう!
「Interruption Source」と「Ordered Interruption」とは
・Interruption Source…アニメーションの遷移中にどのステートの遷移の条件を見て割り込みさせるか決める
・Ordered Interruption…割り込み時に再生するアニメーションをステート側で決めた優先度に従うか決める
となります。(文字だけだと分かりづらいですね。ゆっくり説明していくので安心して下さい。)
この項目はAnimatorウインドウでステート同士を繋げているトランジションを選択することでInspector上に表示されます。
逆に言えば、各トランジション毎にこれらを設定してあげないといけない、という事になりますね。
Animatorウインドウやステートに関してわからない場合は下記記事で詳細に扱っているので参考にしてみて下さい。
Interruption Sourceでの各割り込み条件設定
Interruption Sourceでできる割り込み設定は指定したステートの遷移条件(condition)が遷移中に成立したら遷移を止めて、成立した方へ移動する、というものです。
ちなみにInterruption Sourceは日本語では「中断の情報源」になるよ
ここで指定できる各条件を見ていきましょう。
None
この設定では遷移の割り込みは行われません。
Current State
遷移している「Current」=「現在」のステートから伸びている遷移からの割り込みを許可します。
トランジション(遷移)を中心に考えるのでCurrentは遷移元のステート、という事になります。
例えば、下記の画像ではIdle→Move02間のトランジションでInterruption SourceをCurrent Stateに設定した場合Idleから伸びている「Move01」への遷移の割り込みを許可する(=Idle→Move02移動中にIdle→Move01への移動を許可する)という事です。
Next State
遷移している「次」のステートから伸びている遷移の割り込みを許可します。
こちらもトランジション(遷移)を中心に考えるのでNextでは遷移先のステート、という事になります。
下記の画像で言うとIdle→Move02間のトランジションでInterruption SourceをNext Stateに設定すると次のステートから伸びているMove02→Move03からの遷移の割り込みを許可する(Idle→Move02移動中にMove02→Move03の遷移に移動許可する)ことになります。
Current State Then Next State
この設定では現在と次のステート、つまりCurrentとNext、両方からの遷移を許可します。
ただし同時に条件が成立した場合にはCurrent側が優先されます。
Next State Then Current State
この設定でも同様に現在と次のステート、つまりCurrentとNext、両方からの遷移を許可します。
ただし、こちらでは先ほどとは逆で同時に条件が成立した場合にはNext側が優先されます。
Ordered Interruptionでの優先度設定
Ordered Interruptionはシンプルです。チェックするかしないかだけ。
このチェックは何かというと遷移の割り込みが発生した時にステート側で設定しているTransitions(=それぞれの遷移)の優先度を確認して、割り込まれたアニメーション遷移の優先度が今のアニメーション遷移より低ければ無視する、というもの。
実際に簡単にですが例を見てみましょう。
今、ステートとトランジションは下記のような関係になっています。
「Idle」というオレンジのステートから見て、
TriggerAというスイッチをOnにするとMove01へ遷移(赤色の四角)します。
TriggerBというスイッチをOnにするとMove02へ遷移(水色の四角)します。
この時、先ほど見たように遷移の優先度は Idle→Move01よりIdle→Move02の方が優先度は高い状態です。
※「Idle」ステートのInspector内のTranditions欄の上ほど優先度が高い。
この状態でOrdered InterruptionのチェックをOnにするとこのTranditionの優先度に沿ってアニメーションの割り込みを処理します。
それでは、「Idle→Move01」「Idle→Move02」両方のトランジションのOrdered InterruptionのチェックをOnにして見てみましょう。
「Idle」アニメーションを再生中にTriggerAを押して「Move01」への遷移中にTriggeerBを押すと「Move02」に割り込み(Move02のトランジションにアニメーション移動)が発生します。
※アニメーションの移動はアニメーションしているオブジェクトを選択していると青色のバーになって見えます。
「Idle」→「Move01」より「Idle」→「Move02」の方が優先度は高いので当然ですね。
逆はどうでしょうか。「Idle」→「Move02」遷移中にTriggerAを押してみます。
「Idle」→「Move02」の方が遷移の優先度は高いため割り込みが発生しませんでした!
念の為「Idle」→「Move02」のトランジションのOrdered InterruptionのチェックをOFFにして再度試してみると
ちょっと分かりづらいですが6秒くらいの所で「Idle」→「Move02」から「Move01」へ割り込みがしっかり発生していますね。
Ordered Interruptionはアニメーションの種類によって使い所を適切に考えて付けると非常に効果がありそうです!
必殺技中は無敵になってダメージキャンセルされない、とかの時に優先度は使えそうふるね!
Interruption SourceとOrdered Interruptionの違い
Interruption Sourceは設定するトランジションから見た「Current(遷移元)」と「Next(遷移先)」どのステートからの遷移の割り込みを許可するか、どちらを優先するかなのに対して
Ordered Interruptionはステートで設定された遷移の優先度を参照するかどうかということですね。
まだ少しややこしいかも知れません。
でも、次の項目から実際に触りながら手順を見ていきますので、なんとなくの理解でも大丈夫!(たぶん)
実際に触ってみればスグ理解できるふる!
Interruption Sourceを使った遷移の割り込み
各項目の意味が分かったところで、実際に使ってみて挙動を確認してみましょう。
割り込み方に細かいポイントがあるので要確認!
Animation状況設定
Interruption Sourceの挙動を見ていくにあたり、下記のようなBOXアニメーションの状況を作ってみました。
基本姿勢が「Idle」状態でそこから
・TroggerrAがONでMove01へ遷移(待機から→歩きのイメージ)
・TroggerrBがONでAttack01へ遷移(待機から→弱攻撃のイメージ)
・Attack01からTroggerrCがONでAttack02へ遷移(弱攻撃から→中攻撃のコンボ攻撃のイメージ)
また、中攻撃が終わると「Next」ステートに移動して待機モーション(「Idle」ステート)に戻るようなイメージにしました。
このアニメーション構造をベースに、挙動を見ていこうと思います。
遷移の割り込み設定
それでは、各遷移の割り込み設定をしていきましょう。
まず「Idle」ステートのTransitions優先度はAttack01への遷移の方が優先度が高い状態です。
次に、各ステート同士を繋ぐTransitionの遷移の設定をInspectorでしていきます。
まず、「Idle」→「Move01」のトランジション設定は
・HasExitTimeをOff
・Interruption Source「CurrentState」
・Ordered InterruptionはOn
このようにしました。
次にIdle→Attack01トランジションの設定は
・HasExitTimeをOff
・InterruptionSource「Next State Then Current State」
・OrderedInterruptionはON
先ほどとほとんど同じですが、Interruption Sourceを「Next State Then Current State」にすることで次のステートからの遷移の割り込みの方が元(=Idle)より優先されるようにしました。
イメージとしては攻撃のコンボの方が移動入力より優先される、という事です。
さて、この遷移の先の「Attack01」→「Attack02」のトランジション設定ですが
・HasExitTimeをOn (ExitTimeを0.5)
・InterruptionSource「Next State Then Current State」」
・OrderedInterruptionはOff
としました。
HasExitTimeに関しては仕様の詳細を後で説明しますが、これをOnにする事で任意のタイミング(この場合0.5)までにボタン入力がなければ割り込みはスルーされます。
この場合、一度「Attack01」の再生が最後まで再生された後、また初めから再生され、再度0.5(アニメーションが50%再生)の時点に来た時に割り込みが発生します。
ただ、イメージ的には弱攻撃の後に中攻撃が連携するパターンなので、弱攻撃がループされるのは良くわからない状況なのでこのタイミングでAttack01のループ再生はOffにしました。
最後に、一応「Attack02」→「Exit」のトランジション設定も見ておきましょう。
・HasExitTimeをOn (ExitTimeを1.0)
・InterruptionSource「None」
・OrderedInterruptionはInterruptionSourceがNoneのため効力発生せず
というようにしました。これはアニメーションが100パーセント再生されたらExitステートに移動して終わり、Idle状態に戻るよ、という事ですね。
ここまでの設定を1枚にまとめてみました。(文字が小さくて見にくいけど…)
実際にアニメーションを確認
それでは実際にアニメーションの割り込みを見てみましょう。
ここでは、待機モーションから移動モーションへの遷移中に割り込みして弱攻撃→さらに割り込みで中攻撃のコンボという感じでやってみます。
ステート名で言うと「Idle」→「Move01」(割り込み)→「Attack01」→(割り込み)「Attack02」という感じです。
一応コンボ失敗パターンも見て見ましょう。
「Attack01」のExitTimeである0.5(=アニメーションが50%)地点を超えてからTriggerCを入力してみます。
再生してTriggerを入力してみると…
コンボ失敗はしていますが…なんか思っていた挙動と違う!!
どうやら「Attack01」のループが止まっても内部的にはまた一周して0.5のタイミングでTriggerCがONかOffか確認しているみたいですね?
という事はイメージに近づけるには「Attack01」の再生が最後まで行ったら待機モーションに戻る所を明記しておいた方が綺麗そうです。
ということで↓こんな感じに「Attack01」から「Exit」に繋いで
「Attack01」→「Exit」間のトランジションの条件を↓みたいにしました。
ExitTimeはデフォルトの設定のままですがここを1.0にすると終わりと同時に判定するからか、
挙動が変になってしまった(そのまま止まってしまって、Exitにすぐ遷移しなかったり)ので1.0より小さい数字の方が無難そうです。
今度はどうでしょうか。
上手くいきました!「Attack01」再生時にTriggerCの入力が0.5以内にできなかった場合、待機モーションに戻っています。これでコンボ判定っぽい事ができますね。
なお、今回はやりませんでしたが、実際にはボタン入力でトリガーをOnにした場合、無視して待機モーションに戻ってもトリガーがOnのままになっている可能性があるので、何処かで(例えばアニメーションの終わりとかで)トリガーをOffに戻してあげるような入力を仕込んであげるととより実用的かもしれません。
ここで一度、最初に見た
「Idle」→「Move01」(割り込み)→「Attack01」→(割り込み)「Attack02」
の遷移の割り込みによるアニメーションの流れを画像で確認してみましょう。
このような形でアニメーションの遷移、ブレンド中にも他の遷移へ割り込みを発生させる事ができました!
実際のゲームの目指す使用感に向けて調整しよう!
Tips:HasExitTimeのOnOffによる遷移の挙動の違い
先ほどトランジションの設定をする時にHasExitTimeをOnやOffにしてました。
Onにした場合、ExitTimeで指定した値(0.5とか)のフレームでConditions(=遷移条件)が達成されているかどうかを確認しにいきます。
これはつまり、ExitTimeで設定したフレームを過ぎたタイミングでTriggerがOnになったとしても、一度アニメーションが終わってから再度0.5まで再生されるまで遷移が起こらない、という事です。
要するにExitTimeとConditionsの両方の条件が成立=and条件になっているという事ですね。
そしてこれは遷移の割り込みの時も適用されます。
元のステートのアニメーションがExitTimeで設定されている数値の場所を通過している場合、条件が成立(TriggerOnなど)しても割り込みが発生しません。
これは元のステートが遷移条件を確認していないので、当然といえば当然ですね。
これを逆手にとって、攻撃コンボの入力タイミングやボタンキャンセル(いつまでに入力しないとキャンセルできない)みたいな事が実装できるかもしれません。
ちなみに、HasExitTimeは遷移条件が何も設定されていない場合(TriggerがOnになったら移動みたいな)はOnにしないとトランジションが有効化されず、そのままそこのステートで再生され続けます。(遷移条件が何も無いんで当然ですね。)
HasExitTimeなどの詳細に関しては下記記事を参考にしてみてください。
Tips:割り込み時のアニメーションブレンド
割り込みが発生した際、アニメーションはビジュアル的にどんな感じでブレンドされるのか、気になりますよね。
これはシンプルで「割り込みが発生した瞬間のフレーム」から割り込む遷移へブレンドされます。
Tips:遷移の割り込みなので、あくまでトランジション中での割り込み
また、ここまで話をしてきた内容はあくまで「遷移の割り込み」なのでステート間の移動(遷移)が終わってしまい、ステートの中でループ再生されてたりしている時はこの割り込みは発生させる事ができないので、特に何も効力を発揮しません。
このパターンの場合、また別に仕組み(各遷移の繋ぎ方とか)を考えないといけないふるね
Tips:AnyStateとの競合に関して
また、似たような機能としてAnyStateがありますがAnySateとの関係性は公式にて
Interruption Source プロパティ
AnyState の遷移は、常にキューの先頭に加えられます。その後、他の遷移が Interruption Source の値に基づいてキューに加えられます。
https://docs.unity3d.com/ja/2023.2/Manual/class-Transition.html#TransitionInterruption
と記載があり、AnyStateの方が優先度が高いようですね。
AnyStateに関しては下記記事で掘り下げていますので気になる方はどうぞ。
Interruption Source実際の使い所に関して
ここまでInterruptionSourceを使った遷移の割り込みを詳しく見てきましたが、これを使うことで
・格闘ゲームでのコンボやヒットモーション
・アクションゲームでのヒットモーション、ディレイ(割り込み時に遷移時間をランダムにするとか?)
・リアルタイムストラテジーやタワーディフェンスとかの攻撃途中にダメージが入ってWaitする(動きが止まる)
などなど、こんな感じのリアルタイムにボタン入力やダメージが入ったりするものに上手く使えそうです。
終わりに
実はこの遷移の割り込みのわかりにくさに関しては公式も認めている感があり、公式マニュアルでも補足の説明がされています(全部英語だけどね…)
遷移の割り込みに関するさらに詳しい情報は、Unity ブログの State Machine Transition Interruptions を参照してください。
https://docs.unity3d.com/ja/2023.2/Manual/class-Transition.html#TransitionInterruption
基本的なところは今回の記事にておさえられたと思うので、追加で確認しておくとさらに知識が補強されるかもしれません。
いろんな意見を見ると理解が深まるのよ
◾️Unityアニメーションのマトメ記事はこちら
えきふるからのご相談!
当ブログ「えきふるゲームラボ」では出来るだけ分かり易く読みやすい記事の作成を目指しています!
もし読んでくださった方の中で
「ここが良く分からなかった」「ここをもう少し掘り下げて欲しい」等ありましたら
ぜひコメントで教えて下さい!
コメント貰えると元気も出ますので、どうぞお気軽にお願いしますふる!
※このブログは、UnityTechnologiesまたはその関連会社が後援または提携しているものではありません。「Unity」は、UnityTechnologiesまたはその関連会社の米国およびその他の国における商標または登録商標です。
コメント