Last Updated 2023.11.03
格闘ゲームにおける「投げ」を実装してみます。
なお、自分がネットで検索する程度の範囲には、作例も情報も「有用なもの」は見つけられませんでした。サンプルや先人に頼らず、仕組みや仕様を自分で考えた方が速そうです。
どういったやり方が正しいのか、あるいは効率的なのか──本当に解らない状態からなので、我流のやり方になりますがご了承下さい。
Blenderでモーションの作成
まずはじめに、投げる側のモーションを用意します。
投げ抜けを作る場合には、相手と自分に更に1つずつ追加されますが、流石に今回は省略します。
動作全体の流れにはモチーフがあったので、それを元に自作しました。
次に、投げられる側のモーション作成。
Blenderの[アペンド]機能を使って、先ほど作った投げる側、投げ成立後モーションファイルの[Armature]を読み込みます。
開始位置が同じ状態で読み込むと、Armatureが重なった状態からになってしまうので、投げる側か投げられる側の開始位置をあらかじめ移動させておきましょう。今回は投げられる側の位置で調整しました。
無事に読み込めれば、投げる側のモーションを確認しながら作業できるようになるので、それに合わせて投げられる側のモーションを作成していきます。
投げる側と投げられる側のモーションが出来たら、FBX形式でエクスポート。
ここで 重要 なのですが、アペンド機能を使った側をそのままエクスポートしてしまうと、Unity上で色々と不都合があるので、アペンドした部分はこの段階で削除してからエクスポートします。
デフォルト設定だと、画面右上の欄から選択→右クリック→削除。
謎のモジャモジャと(表情用の)顔が残るので、これも範囲ツールで選択して削除しておきましょう。
モーションをUnityに取り込んで設定する
今回、Blender上では投げる側の位置に合わせてモーションを作ったので、Unity上で位置を制御したいのは、主に投げられる側になります。
fbxファイル選択 → [Rig]タブ → AnimationTypeを [Humanoid] に
投げる側のモーション設定。
[RootTransfomRotation] と [RootTransfomPosition] のチェックは外してます。
Rotationは投げ後の向き、Positionは投げ後の位置に影響し、今回のモーションでRotationにチェックを入れると、投げの後にまた投げを開始した際の向き(今回の場合は逆方向)を向くことになってしまいます。この辺はモーションによって変わってくるので、実際に確認しながら調整して下さい。
投げられる側のモーション設定。
Blender側で作成の際に、位置や回転状況を『投げる側』基準のままエクスポートしているので、モーションの向きを180度回転、[RootTransfomPosition] の [BasedUpon] を [Center of Mass] に設定しています。
Animator設定
掴むモーションに投げ判定用のコライダーを設定して、投げが成立したら投げる側と投げられる側のAnimatorに遷移を開始させる……という流れになるのですが、投げられる側はダメージを受ける、の延長でいけるんですが、投げる側のアニメーション遷移条件をbool型とTrigger型、どちらを使うかが悩ましいです。
自分の場合、なぜかbool側だと上手くいかず、Trigger型だとあっさり通ったりしたので、シンプルなのはTrigger型なんでしょうが、投げの条件満たしたのに、投げる側だけ上手く遷移しないケースがあったので、この辺もう少し細かく突き詰めたいと思います。
スクリプトで制御する要素
書いてある場所も分かれてるので、ざっくりと要点のみに絞ります。
・お互いのCharacterControllerが干渉し、密着状態にならないので、どちらかのレイヤーを干渉しないように変更します。
SidePlayer1.layer = 任意のレイヤー番号;
・掴んだ時
void OnTriggerEnter(Collider other) { if (other.name == "2Pplayer") { if (animator.GetCurrentAnimatorStateInfo(0).IsName("Throw"))//1P側が投げモーション { //相手がダウン中でなければ投げに移行 if (other.tag != "Down") { gameManager.IsDirection = true;//演出に入るチェック。入力受付拒否の条件等に使用。 gameManager.IsThrow = true;//投げ中であるか否か。カメラの変更やダメージチェックに使用。 gameManager._1PAnimator.SetTrigger("Catch");//投げる側のAnimator遷移条件 gameManager._2PAnimator.SetBool("Thrown", true);//投げられる側のAnimator遷移条件 gameManager._2PAnimator.applyRootMotion = true; gameManager.SidePlayer2.transform.LookAt(gameManager.SidePlayer1.transform.position);//2Pが1P方向を向く return; } } } }
・【必須】 投げられた側が(任意のタイミングで)ダメージを受ける
・【必須】変更したレイヤーを投げ演出中に元に戻す
・【演出】 カメラワークを変更する
これら一連の作業を終えた結果がこちらになります。
正直、素人でも大変なのが想像できた「投げ」のシステムだったんですが、実際に自作してみると、投げひとつにここまで色んな要素や設定が必要なのかと思い知らされました。モーション作成からUnityに取り込んで、スクリプトが想定通りに通るまで数日かかりましたよ……
とはいえ、ゲーム制作に着手し始めた段階では作れる気がしなかったシステムでもあるので、こうして作れたのは、素人ながらにも前進はしてるのかな?……と思います。思いたい。
まだまだ細部の調整は必要ですが、それでも「投げ」というシステム自体の取っ掛かりが作れたのは大きな収穫でした。