Unityでキャラクターをジャンプさせよう。
キャラクターをジャンプさせるのは、アクション系のゲームを作る上では必須ですね。今回は、ジャンプに標準を合わせて基本的な方法を見ていきます。
- Rigidbodyを使用したジャンプ
- CharacterControllerを使用したジャンプ
今回はこの2つについて説明していきます。キャラクターの動かし方に合わせてこちらもどれにするか確認するのがいいと思います。
キャラクターの動かし方はこちらも参考にしてみてください。
それでは詳しくみていきます。
ジャンプについて考える
キャラクターがジャンプするとはどういうこと?
キャラクターがジャンプすることについて、ゲーム構造として考えてみます。
例えば、コントローラーのボタンを押す、キーボードの上やスペース等のジャンプボタンを押すとキャラクターがジャンプするようになって欲しい。ここではこれを基本と考えます。
ボタンを押すと、キャラクターがジャンプする、つまり、キャラクターが上方向に動くわけです。2DならばY軸方向かもしれないし、3DならばZ軸方向になるかもしれません。ゲームによってそこは変わるかもしれませんね。
つまり、ジャンプとはキャラクターがその決められた上という軸に向かって動く事になります。
では、上に行くだけでいいのでしょうか?違いますね。ジャンプしたら当然、落下があります。
勢いよく上にジャンプしたら今度は落下するのが重力のある世界では自然な減少となります。
この現象についても考えてみましょう。
重力による落下
この点に関して、Unityでは基本的に物理演算などで解決できます。
Rigidbodyコンポーネントを使えばこれが簡単にできます。
重力の大きさや、重さなどを設定することで、ジャンプの勢いや落下速度などを調整できます。
そのため、自然な落下を合わせたジャンプであれば、Rigidbodyを使う事が多くなるでしょう。
他にも方法があるので、それは色々試しながらどれがいいとか選んでください。
着地判定と連続ジャンプ
最後にこの問題について考えてみます。つまりは、「キャラクターはいつジャンプできるのか?」といったことです。
よくあるのが、ジャンプ機能だけ実装してジャンプしてしまう場合に起きる問題です。ボタンを押すと上方向に力が加わるということです。
これだけだと何が問題なのかというと、「いつでも」ジャンプできてしまうために、空中で連続ジャンプができてしまい、Rigidbodyのジャンプだと、どこまでも飛んで行ってしまいます。
これを制御するためには、「床にキャラクターがいるときだけ」ジャンプできるようにすることです。
BooleanというTrueやFalseを使ってキャラクターが床に設置している時だけジャンプできるようにすることで、制御でき、方法は複数あります。
また、空中で2回以上ジャンプできるようにしたいときもあるでしょう。
そのときは、回数を管理することでジャンプの回数を管理することもできますよ。
単なるジャンプですが意外とこの辺を考えておかないと、間違いが起こりやすので、考えておきたいところですね。
次から実際のジャンプの方法についてみていきたいと思います。
Rigidbodyを使用したジャンプ
Rigidbodyを使う方法は、物理エンジンを活用したリアルな動きを実現するのに適しています。
ちなみに、Rigidbodyや位置情報の基本、また、例で使うキューブの作成方法を知り合い場合は、こちらにあるので参考にしてください、
Unityでオブジェクトをジャンプさせる一番オーソドックスな方法として、キャラクターにRigidbody
コンポーネントをつけて、物理演算を使う方法があります。まずは、シンプルなキューブを例に、物理演算を利用したジャンプ方法とそのメリット・デメリットについて説明します。
キューブにRigidbodyを追加
- シーン内にキューブを作成します(ヒエラルキーウィンドウ → 3D オブジェクト → キューブ)。
- キューブを選択し、Inspectorパネルで「Add Component」ボタンをクリックします。
- 「Physics」カテゴリから「Rigidbody」を選択して追加します。
キューブのインスペクターにコンポーネントを追加します。
追加されたRigidbodyはインスペクターにに表示されます。質量や摩擦などが追加されます。
力を加えてジャンプさせる
次のコードをキューブにアタッチしてください。これでジャンプができます。
using UnityEngine;
public class Player : MonoBehaviour
{
//ジャンプ力
public float jumpForce = 5.0f;
//リジッドボディを入れる変数
private Rigidbody rb;
void Start()
{
//開始直後にリジッドボディを変数に代入
rb = GetComponent<Rigidbody>();
}
void Update()
{
//スペースを押す
if (Input.GetKeyDown(KeyCode.Space))
{
//押されたらジャンプする(上方向へ力を加える)
rb.AddForce(Vector3.up * jumpForce, ForceMode.Impulse);
}
}
}
すると、こんなかんじで、ジャンプできますね。上方向に力を加えることで、ジャンプし、物理演算で落下するため、綺麗な落下になっていますね。
ただ、これだけだと、地面との接地判定がないため、連続ジャンプができてしまいます。
今回はこの点には触れないので、このような現象が起きるという事だけ覚えておいてください。
Rigidbodyを使用したジャンプのメリットとデメリット
Rigidbodyを使用した場合、メリットとデメリットは次の通りです。細かな制御を考えるときは、別の方法を検討することもありそうですが、基本的にはメリットが多い方法だと思います
メリット
- リアルな物理挙動:
- RigidbodyはUnityの物理エンジンと連携しているため、重力や他の力の影響を受けたリアルな動きを実現できます。
- 力や速度、摩擦などの物理パラメータを調整することで、ジャンプの挙動を細かくコントロールできます。
- シンプルな実装:
- Rigidbodyの
AddForce
メソッドを使用するだけでジャンプを実現できるため、実装が比較的簡単です。
- Rigidbodyの
- 他の物理オブジェクトとの相互作用:
- 他のRigidbodyを持つオブジェクトと自然に相互作用できるため、物理的な衝突や反発を簡単に扱えます。
デメリット
- 制御の難しさ:
- リアルな物理挙動を持つため、意図しない動きが発生することがあります。例えば、斜面や動くプラットフォームでの挙動が予期しない結果になることがあります。
- 精密なキャラクター制御が必要な場合、Rigidbodyを使うと制御が難しくなることがあります。
- パフォーマンスの影響:
- 多数のRigidbodyを持つオブジェクトを扱う場合、物理計算が増加し、パフォーマンスに影響を与える可能性があります。
- 地面との接触判定:
- 地面に接しているかどうかの判定が難しくなることがあります。特に、複雑な地形や不規則な形状の地面では、正確な接触判定を行うために追加のロジックが必要です。
- 非物理的な動作が難しい:
- 物理エンジンを使わないジャンプや浮遊などの非物理的な動作を実装する際には、Rigidbodyを使用すると逆に手間がかかることがあります。
CharacterControllerを使用したジャンプ
CharacterControllerコンポーネントは、特に3Dキャラクターの移動を制御するためによく使われます。
シンプルなキャラクターの設定
- シーンにキャラクターとなるキューブを配置します。
- オブジェクトを選択し、Inspectorパネルで「Add Component」をクリックし、「Character Controller」を検索して追加します。
Physics内にあるCharacter Controllerコンポーネントを追加します。
ステップ1: CharacterControllerの設定
キャラクターにCharacterControllerコンポーネントを追加します。
スクリプトの追加
次のスクリプトをアタッチしましょう。
using UnityEngine;
public class Player : MonoBehaviour
{
public float speed = 6.0f;
public float jumpSpeed = 8.0f;
public float gravity = 20.0f;
private Vector3 moveDirection = Vector3.zero;
private CharacterController controller;
void Start()
{
controller = GetComponent<CharacterController>();
}
void Update()
{
if (controller.isGrounded)
{
moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));
moveDirection = transform.TransformDirection(moveDirection);
moveDirection *= speed;
if (Input.GetButton("Jump"))
{
moveDirection.y = jumpSpeed;
}
}
moveDirection.y -= gravity * Time.deltaTime;
controller.Move(moveDirection * Time.deltaTime);
}
}
このコードについては補足をしておきます。
CharacterController
は物理エンジンを直接使わないため、より簡単に制御が可能isGrounded
プロパティを使って地面にいるかどうかを確認可能- コントローラーを一元管理できるため、シンプルなコードに
- 重力などもコード内で管理可能
以上の特性があります。動きとしては次のようになります。
動き全体を一元管理しつつ、接地判定や重力も自由ですね。
CharacterControllerを使用したジャンプのメリットとデメリット
CharacterControllerを使用したジャンプはより直観的かつ軽量に動きを制御できる点がいいところですね。ただ、他に物理演算を使うものとの連携が取りずらい点が難点といえます。
メリット
- 簡単な制御:
- CharacterControllerは、キャラクターの移動やジャンプを簡単に制御するための高レベルなAPIを提供します。物理エンジンの詳細を知らなくても、直感的にキャラクターの動作を設定できます。
- 地面との接触判定が簡単:
isGrounded
プロパティを使用することで、キャラクターが地面に接しているかどうかを簡単に判定できます。これにより、ジャンプ可能な状態かどうかを簡単に判断できます。
- パフォーマンス:
- Rigidbodyを使用した場合よりも軽量で、計算量が少ないため、パフォーマンスに優れています。特に複雑な物理計算が不要なゲームでは、CharacterControllerを使うことでパフォーマンスが向上します。
- 柔軟な移動制御:
- CharacterControllerは、移動やジャンプだけでなく、滑りや坂の移動などの動作を簡単に制御できるため、より多様なキャラクターの動きを実現できます。
デメリット
- 物理エンジンとの連携が難しい:
- CharacterControllerは物理エンジンの一部ではないため、他の物理オブジェクトとの相互作用(例えば、衝突や力の影響)が難しいです。これにより、物理的なリアリズムが求められる場合には不利になります。
- 複雑な物理挙動の再現が難しい:
- CharacterControllerは基本的な動きには適していますが、複雑な物理挙動を再現するには向いていません。例えば、リアルな反発や摩擦を実現するのが難しいです。
- カスタマイズの制限:
- 高レベルなAPIを提供する一方で、細かい挙動のカスタマイズが制限される場合があります。特に、独自の物理挙動や特殊な動きを実装する場合には、柔軟性が不足することがあります。
- 動作の予測可能性:
- CharacterControllerは予測可能で一貫した動作を提供しますが、逆に言えば動作が単純すぎて、複雑なゲームプレイの要件に対応するためには工夫が必要になることがあります。