今回はボタンをタイミング良く押すと連続攻撃になる動作を作成します。
格ゲーのようなコマンド入力ではなく、3Dアクションによくあるような非常に単純なもの です。
ボタン連打でコンボ攻撃
3Dゲームなどで「ボタンを連打したら連続攻撃」という機能をよく見ます。
今回はコンボ表現の単純な紹介をしようと思いましたが、コレが思ったより重要な要素の塊だったので、解説しながら内容を紹介していきます。
なお格ゲーが作りたいならPlayableAPIで再生するアニメーションを選択する部分を自分で拡張するがお勧めです。
今回の動作を作るにあたり、使用したコードは「Animatorのトリガーを呼ぶ」くらいで、殆どスクリプトを記述せず実現出来ました。
1. ボタンを押したら殴る
最初のステップでは、ボタンを押したら(Attackトリガーが有効になったら)殴るモーションに入らせます。
- [アイドル] と [パンチ] のモーションのトランジション(遷移)を設定
- [アイドル] → [パンチ]のコンディションにAttackトリガーを設定
- [パンチ] → [アイドル] のコンディションはHasExit(終了時間あり)を設定
これで実行時にAttackトリガーを押せば[パンチ]と[アイドル]の間を行ったり来たりします。
ポイントは[アイドル]→[パンチ]のHasExit(終了時間あり)を外す事です。
アイドルや走行といった他のアニメーションに即時切り替わることが期待されているモーションは、HasExitを外さないとモッサリします。
2. ボタンを押したら次の攻撃への実現
単発ではなく、順番に攻撃アニメーションを行うように修正を行います。
上ではアニメーション終了時に即座に戻っていましたが、今回はトリガーが押されたら次のアニメーションへとなるようにAnimatorControllerを修正します。
考え方は簡単で、攻撃モーションをトリガーで繋いでいくだけです。全ての遷移にはAttackのトリガーによる切り替えを設定しておきます。
ここでのポイントはトリガーはトランジションを通ると即座にOFFになる事です。複数のステートの巡回を行いつつちゃんとアニメーション終了待ちさせるといった点では、トリガーは非常に有用です。
ただし「トランジションを通らなければOFFにならない(スクリプトでOFFにする必要がある)」為、使いすぎるとトリガーのリークが起こります。
3. 攻撃の入力待ち時間の調整
Attackトリガーの入力待ち受け時間とモーションの繋ぎを調整します。
まず注目すべきはオレンジで囲った「終了時間」の部分です。この部分がAttackトリガーの入力を受け付ける時間です。初期値では0.5となっているので、これを出来る限り後ろの方(せめて大体の攻撃モーションが終了して収束する0.8割くらいの位置)に移動します。
ここで重要な考えはトリガーの判定は終了待ちで指定したタイミングを「通過した瞬間」に行われるという点です。トリガーが通過すると次に判定するのは次の周の終了待ちのタイミングなので、終了待ちを早めに設定すると簡単にタイミングを逃します。
終了待ちを行わないという選択肢もありますが、その場合「攻撃モーションをキャンセルして次の攻撃モーションが始まる」可能性があります。
4. モーションの繋ぎの調整
入力待ち時間の設定が終わったらモーションの切り替えにかかる時間を調整します。
ここでのポイントは遷移間隔を短くすることです。ここが長いとモーションのブレンド時間が伸びてモーションがボンヤリします。
遷移時間を短くすることで発生する急激な軸足の変化は、オフセットをズラして調整します。
なお遷移間隔とオフセットでズレた位置が次のステートの開始点です。
つまり遷移時間が0.25(初期値)で次のステートの終了待ちが0.5(初期値)の場合、0.25~0.5までにトリガーを押さないとタイミングを逃します。
5. ボタンが押されなかったらキャンセルする
タイミングよくボタンを押したら攻撃は出来ました。次はタイミングを逃してボタンを押さなかった場合にモーションをキャンセルしてアイドル状態に戻す挙動を作ります。
やり方は[パンチ]や[フック]といったモーションからアイドルへ「終了時間あり」つきでトランジションを作ります。
この時、必ず終了時間を[パンチ]→[フック]への終了待ち時間より後に設定します。
これでモーション完了時にボタンが押されていなければ[アイドル]へ戻るようになります。
なお、どうしても[パンチ]→[フック]の終了時間よりも[パンチ]→[アイドル]の終了時間が前に来る(必ず先に[パンチ]→[アイドル]の遷移が始まってしまう)という場合は、中断要因を使用して強引にフックモーションを実行するという力技もあります。
(これは理解できない挙動の要因になりえるので、余り使わない方が良いと思います)
6. ボタンで攻撃を分岐させる
コンボ中に押すボタンによって攻撃を切り替えます。
ステートマシンの途中で分岐が発生しますが、この分岐はInt型のパラメーターをもたせる事で解決します。このInt型のパラメーター(AttackType)をボタンと一致させれば、ボタンで挙動が変わるコンボが的なのを実現出来ます。
ボタンに応じたトリガーという手もありますが、トリガーのリーク(トリガーが開放されず押した状態が保持されてしまう状態的な)が発生するので、パラメーターで分岐させるほうが好みです。
今回はAttackTypeのパラメーターで分岐しましたが、実際には「移動中か?」や「HPの割合」等をコンディションに渡して再生するアニメーションを切り替えるのも良いかもしれません。
7. ステートマシンを整理する
さて分岐を追加したことでステートマシンが割と大変な感じになってきました。最後にサブステートを使用してステートマシンを整理しておきます。
最初のポイントは、ステートマシンはサブステートに入るとEntryから始まり、Exitで出るとサブステートから遷移するという点です。
- サブステートマシン[アタック]を作成
- [アタック]と[アイドル]のトランジションを作成。[アイドル]→[アタック]のコンディションはAttack
- [アタック]へ攻撃系のモーションを全て移動
- 攻撃系モーションの遷移先をExitへ変更
(終了時間は1に設定)
ダイジェストすると、下のような感じです。
まだ攻撃処理が分岐する部分(ハイキックとアッパー)がゴチャゴチャしそうなので、少し過剰ですがもう少し整理しておきます。
分岐する攻撃をサブステート[アタック(分岐)]へ移動します。
[フック]→[アタック(分岐)]へのトランジションは「Attackトリガー」だけで良いです。判断はサブステートマシン側で行います。
サブステート側では、Entryから[アッパー]と[キック]へのトランジションを設定します。その際、分岐はAttackTypeのみです。
あとはアニメーション終了時にExitに持っていけば、親サブステート[アタック]のExitへ到達し、最終的に[アイドル]へ戻ります。
関連
AnimatorControllerの整理系
tsubakit1.hateblo.jp終了待ちキャンセル
攻撃モーションが「他の全ての攻撃モーションに遷移する」場合にステートがスパゲティ化するのを何とかするアプローチ