Last Updated 2025.02.11
格闘ゲームにおける「投げ技」を実装してみます。
なお、自分がネットで検索する程度の範囲には、作例も情報も "有用なもの" は見つけられませんでした。サンプルや先人に頼らず、仕組みや仕様を自分で考えた方が速そうです。
どういったやり方が正しいのか、あるいは効率的なのか──本当に解らない状態からなので、我流のやり方になりますがご了承下さい。
Blenderでモーションの作成
投げる側のモーション作成
まずはじめに、投げる側のモーションを用意します。


投げ抜けを作る場合には、相手と自分に更にモーションが必要になってくるので、流石に今回は省略します。『動作全体の流れ』 にはモチーフがあったので、それを元に自作しました。
投げられる側のモーション作成
次に、投げられる側のモーション作成。
Blenderの〈アペンド〉機能を使って、先ほど作った投げる側、『投げ成立後』のモーションファイルのArmatureを読み込みます。
開始位置が同じ状態で読み込むと、Armatureが重なった状態からになってしまうので、投げる側か投げられる側の開始位置をあらかじめ移動させておきましょう。今回は投げられる側の位置で調整しました
無事に読み込めれば、投げる側のモーションを確認しながら作業できるようになるので、それに合わせて投げられる側のモーションを作成していきます。
FBX形式で出力する
投げる側と投げられる側のモーションが出来たら、FBX形式でエクスポート。
ここで 重要 なのですが、アペンド機能を使った側をそのままエクスポートしてしまうと、Unity上で色々と不都合があるので、アペンドした部分はこの段階で削除してからエクスポートします。
デフォルト設定だと、画面右上の欄から選択→右クリック→削除
※VRMモデルを使っていた場合、モジャモジャ(エンプティ)とFaceオブジェクトが残るので、これも範囲ツールで選択して削除しておきましょう
モーションを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;
// 2Pキャラが1Pキャラを向く。モーションによっては不要。
gameManager.SidePlayer2.transform.LookAt(gameManager.SidePlayer1.transform.position);
}
}
}
}・【必須】 投げられた側が(任意のタイミングで)ダメージを受ける
・【必須】変更したレイヤーを投げ演出中に元に戻す
・【演出】 カメラワークを変更する
動作確認
▼ これら一連の作業を終えた結果がこちらになります。
正直、素人でも大変なのが想像できた「投げ」のシステムだったんですが、実際に自作してみると投げひとつにここまで色んな要素や設定が必要なのかと思い知らされました。
モーション制作からUnityに取り込んで、スクリプトが想定通りに通るまで数日かかりましたよ……
とはいえ、ゲーム制作に着手し始めた段階では作れる気がしなかったシステムでもあるので、こうやってカタチに出来ただけでも、(素人ながらに)前進はしてるのかな?……と思います。思いたい。
まだまだ細部の調整は必要ですが、それでも「投げ」というシステム自体の取っ掛かりが作れたのは大きな収穫でした。
