
こんにちは!夜の街2Dアクションゲームを制作中の怪獣です🦖
Unity2Dでプレイヤーをジャンプさせたいけど、
- ジャンプのさせ方が分からない
- ジャンプが高くなりすぎる
- 連続ジャンプしてしまう
- 地面判定がうまくいかない
といったことはありませんか?
この記事では、ジャンプさせる実装法(解説付き)、二重ジャンプ防止対策も含めて
初心者向けにわかりやすく解説します!
Unityの移動処理には「AddForce・velocity・transform」の3種類の実装方法がありますが、
今回は重力を活かして自然なジャンプにしたいので、AddForceを使った実装方法を解説しています。
他の実装方法の解説、比較もしていますので、よければご参照ください!
① 今回の完成イメージ
- Input System を使ってジャンプ操作をさせる
- 地面にいる時だけジャンプ可能(空中連打で多段ジャンプしない)
- Rigidbody2D を使用
- 接地判定は BoxCast で足元をチェック
Input Systemでボタン操作を設定している前提で進めています。
Input Systemの導入がまだ出来ていない場合は、まずこちらの記事から読むとスムーズです👾
(※旧Input版の実装方法も後半で解説あり)
② 事前準備
プレイヤー、プレイヤーが立てる床のオブジェクトを用意しておきます。
⇩インスペクターの設定を以下のような感じにしておきます
プレイヤー側
Rigidbody2DCollider2D(BoxCollider2Dなど)
床側
Collider2D(BoxCollider2D / TilemapCollider2Dなど)
③ ジャンプ処理の基本コード
✅ Input System の Jump を呼ぶ前提で _OnJump() を用意しています。
旧Input(Input.GetKeyDown)版も後半で紹介します。
public class Player : MonoBehaviour
{
[SerializeField, Header("ジャンプ速度")]
private float _jumpSpeed;
[SerializeField, Header("接地判定用レイヤー(Floorなど)")]
private LayerMask _groundMask; // インスペクターでFloorを指定
private bool _bJump;
private Collider2D _col; // 実寸取得用
void Start()
{
_col = GetComponent<Collider2D>();
_bJump = false;
}
void Update()
{
_HitFloor();
}
// 今床に触れているか、空中状態か判定する
private void _HitFloor()
{
// もしプレイヤーのColliderが存在しなければ処理しない
if (_col == null) return;
// 接地判定のためのBoxCast(四角形の当たり判定を下に飛ばす)を準備する
// プレイヤーのコライダーの範囲を取得
Bounds b = _col.bounds;
// 判定を出す位置(プレイヤーの足元より少し下に設定)
Vector2 center = new Vector2(b.center.x, b.min.y - 0.05f);
// 判定の大きさ(横幅はキャラより少し小さめ、高さはごく薄い矩形)
Vector2 size = new Vector2(b.size.x * 0.9f, 0.12f);
// BoxCastを実行
// ・center:判定の中心位置
// ・size :判定の大きさ
// ・0f :角度は回転なし
// ・Vector2.down:真下に向けて判定
// ・0.05f :判定を飛ばす長さ(わずかに下へ伸ばす)
// ・_groundMask:Floorなど「地面」とするレイヤーにだけ反応させる
RaycastHit2D hit = Physics2D.BoxCast(center, size, 0f, Vector2.down, 0.05f, _groundMask);
// 当たり判定の情報取得
bool grounded = (hit.collider != null);
// 地面と触れたか確認
if (grounded)
{
// 地面にいる → ジャンプ可能
_bJump = false;
}
else
{
// 空中にいる → ジャンプ不可
_bJump = true;
}
}
// ジャンプ処理
public void _OnJump(InputAction.CallbackContext context)
{
// 押下(performed)でなければ無視 / 空中なら無視
if (!context.performed || _bJump) return;
// Impulse:初速が早く徐々に減速、Force:初速が遅く、徐々に加速
_rigid.AddForce(Vector2.up * _jumpSpeed, ForceMode2D.Impulse);
// 連打での多段を防ぐために即座に空中扱い
_bJump = true;
}
}④ 各処理の解説(初心者向け)
↓※以下は各処理の説明です。わかってるよという方は⑤まで読み飛ばしてください
フィールド変数の追加
[SerializeField, Header("ジャンプ速度")]
private float _jumpSpeed;
[SerializeField, Header("接地判定用レイヤー(Floorなど)")]
private LayerMask _groundMask; // インスペクターでFloorを指定
private bool _bJump;
private Collider2D _col; // 実寸取得用
_jumpSpeed:ジャンプの強さ(大きいほど高く跳ぶ)。インスペクターで強さを調整します。(15くらいがおすすめ)_groundMask:「床」と判定するレイヤーを指定します。(Floorなど)インスペクターで Floor レイヤーを選びます。
✅ Tag判定でも同じことが出来ますが、今回はLayerMaskで進めています。
LayerMaskは「物理判定の対象を限定するための仕組み」で今回のような地面だけ判定するような接地判定に向いています。
Start(必要コンポーネントを取得)
void Start()
{
_col = GetComponent<Collider2D>();
_bJump = false;
}
Collider2D(プレイヤー自身に付いている当たり判定情報)を取得して変数に保存。_bJumpは「今ジャンプ中かどうか」を管理するフラグです。初期値はfalse(ジャンプ可能)。
Update(接地状態を更新)
void Update()
{
_HitFloor(); // 接地状態をチェック
}
Updateは毎フレーム呼び出されるUnityの共通機能です。
ここで _HitFloor() を呼び出して、接地中かどうかを更新します。
_HitFloor (BoxCastで接地判定する)
Colliderが存在するか確認
if (_col == null) return;ここでは
プレイヤーのColliderが取得できているかを確認しています。
もしColliderが存在しない状態で処理を続けると
エラーが発生してしまうため、Colliderが無い場合 処理を中断するという安全対策です。
プレイヤーの当たり判定サイズを取得
Bounds b = _col.bounds;ここでは
**プレイヤーのコライダーの範囲(サイズ・位置)**を取得しています。
Boundsには次のような情報が入っています。
| 情報 | 内容 |
|---|---|
| center | コライダーの中心 |
| min | コライダーの一番下 |
| size | コライダーのサイズ |
つまりプレイヤーの大きさ、プレイヤーの位置を取得しています。
接地判定の中心位置を決める
Vector2 center = new Vector2(b.center.x, b.min.y - 0.05f);ここでは
地面を判定する位置を決めています。
ポイントはここです。
b.min.y
これは、プレイヤーコライダーの一番下の位置です。
さらに-0.05fをしている理由はプレイヤーの足元より少し下で判定するためです。
プレイヤー
┌─────┐
│ │
│ │
└─────┘ ←ここがb.min.y □ ←この少し下で接地判定
────────── 地面
こうすることで
足元に地面があるかを正確に判定できます!
判定する矩形サイズを決める
Vector2 size = new Vector2(b.size.x * 0.9f, 0.12f);ここではBoxCastのサイズを設定しています。
b.size.x * 0.9f(横幅)で、プレイヤーの幅より少しだけ小さくしています。
理由は、壁に触れたときに地面と誤判定しないようにするためです。
0.12f(高さ)はかなり薄くしています。
これは、足元のわずかな範囲だけを判定するためです。
BoxCastで地面をチェック
RaycastHit2D hit = Physics2D.BoxCast(
center,
size,
0f,
Vector2.down,
0.05f,
_groundMask
);ここが この処理の一番重要な部分です。
BoxCastとは四角形を飛ばして当たり判定をチェックする機能です。
【イメージ】
プレイヤー
│
▼[ □ ] ←判定ボックス
│
▼
地面
各引数の意味はこちら。
| 引数 | 意味 |
|---|---|
| center | 判定の中心 |
| size | 判定の大きさ |
| 0f | 回転なし |
| Vector2.down | 下方向に判定 |
| 0.05f | 飛ばす距離 |
| _groundMask | 地面レイヤーだけ判定 |
BoxCastの他にも、Unityにはいくつかの判定方法があります。
| 方法 | 形 | 用途 |
|---|---|---|
| Raycast | 線 | 足元・視線判定 |
| CircleCast | 円 | 丸いキャラ向き |
| BoxCast | 四角形 | 2Dキャラの接地判定に最適 |
なぜジャンプ判定でBoxCastを使うのか?
プレイヤーは四角いことが多いですよね。
□ ← プレイヤー
 ̄ ̄ ̄ ̄ ← 床
Raycast(線)だと、
□
|
|
 ̄ ̄ ̄ ̄
→ ちょっとズレると判定ミスします。
でも BoxCast なら:
□
███ ← 薄い箱
 ̄ ̄ ̄ ̄
足元全体をチェックできるので安定しやすくなります🚶
地面に当たったか確認
bool grounded = (hit.collider != null);BoxCastが
- 地面に当たった → colliderが存在
- 当たってない → null
になります。
つまり hit.collider != nullは、地面に触れているかどうかを意味しています。
ジャンプ可能かどうかを設定
if (grounded)
{
_bJump = false;
}
else
{
_bJump = true;
}
bool grounded = (hit.collider != null);bool grounded = (hit.collider != null);ここでは、
| 状態 | 処理 |
|---|---|
| 地面にいる | ジャンプ可能 |
| 空中 | ジャンプ不可 |
という状態を設定しています。
この _bJump をジャンプ処理で使います。
_OnJump
public void _OnJump(InputAction.CallbackContext context)
{
// 入力が押された瞬間以外は無視 / 空中中は無視
if (!context.performed || _bJump) return;
// Rigidbodyに上方向の力を加える
_rigid.AddForce(Vector2.up * _jumpSpeed, ForceMode2D.Impulse);
// ジャンプ直後は空中扱いにして多段ジャンプを防ぐ
_bJump = true;
}
context.performed… 入力が「押された瞬間」だけ反応します。_bJumpがtrueのとき(空中)は処理をスキップ。- ジャンプ処理にはいくつかの実装方法がありますが、
AddForce(Rigidbodyに力を加える関数)を使う理由は物理挙動を活かして自然なジャンプにするためです。
上方向(Y軸プラス方向)に対しジャンプの強さ(高さ)を図り、ForceMode2D.Impulseを引数で渡すことで、一瞬だけ強い力を加えることができます。
こうすることで、初速を一気に与えて自然なジャンプ挙動になります。
AddForceは重力と組み合わさることで、
上昇→減速→落下の自然なカーブを描きます。
そのため、より気持ちのいいジャンプになります!
今回のようなアクションゲームならAddForceがおすすめです!
⬇️他にも、AddForce以外には以下のような方法があります。
| 方法 | 特徴 | 物理挙動 | 主な用途 |
|---|---|---|---|
| _rigid.AddForce | 力を加える | ◎(自然) | ジャンプ・吹っ飛び |
| _rigid.velocity | 速度を直接指定 | ○(やや物理) | 移動、定速移動 |
| transform | 位置を直接変更 | ✕(物理なし) | UI・演出・単純移動 |
velocityでジャンプさせる方法(速度を直接指定)
速度を直接指定でき、瞬時に移動させることが出来るのが特徴です。
_rigid.velocity = new Vector2(_rigid.velocity.x, _jumpSpeed);メリット・・・操作が安定する(毎回同じ動き)、細かい制御がしやすい横移動との相性が良い
デメリット・・・物理感は少し薄れる、慣性が消える(急に止まる)
向いている用途は、プレイヤーの左右移動、シンプルなジャンプ制御、アクションゲーム全般です。
transformでジャンプさせる方法(位置を直接変更)
Rigidbodyを使用せず、位置を直接変更する方法です。
transform.position += Vector3.up * 5f;メリット・・・シンプルで分かりやすい、Rigidbody不要、軽い
デメリット・・・当たり判定が壊れやすい、物理エンジン無視、壁すり抜けなどが起きる
向いている用途は、UI、カメラ移動、背景スクロール、演出効果などです。
⑤ Floor レイヤーの作成
「床」と判定するFloor レイヤーを追加します。
新しいレイヤーを作る
どのオブジェクトでもいいのでクリックし、「Inspector」ウィンドウを確認
「Layer」の右端にあるプルダウンをクリック → 一番下の 「Add Layer…」 を選びます。
(インスペクターが Tags & Layers の設定画面に切り替わります。)

その空欄に Floor と入力してください。
(大文字・小文字は区別されないですが、コードと統一した方が安全です)

床オブジェクトに Floor レイヤーを割り当てる
- Hierarchy 上で「床」となるオブジェクトを選択。
- Inspector の Layer プルダウンから、先ほど作成した Floor を選びます。

Ground MaskにFloorレイヤーを割り当てる
- Playerオブジェクトを選択
- Ground Maskに今作成した Floor を選びます。

ここまで設定したらジャンプ処理の完成です!
⑥ よくあるエラーと対処法
↓ジャンプが動かない、挙動が変な場合は以下を確認してみてください
❌ 地面にいるのにジャンプできない
- 床オブジェクトのLayerMaskが設定されていない
- ✅Layer:「Floor」を設定する

- プレイヤー側の「床」と判定するレイヤー(
_groundMask)の指定がされていない- ✅GroundMask:「Floor」を設定する

❌ 空中で連続ジャンプできる(多段になってしまう)
_HitFloor()が呼ばれていない/判定が機能していない- ジャンプ後
_bJump = true;を入れていない
✅ 対処:_OnJump の最後で _bJump = true; を必ず入れる
❌ 斜面や段差で接地判定がガタつく
- sizeが薄すぎる/小さすぎる
- distanceが短すぎる
✅ 対処:size.y や 0.05f を少し増やす(例:0.08f、0.1f)
⑦(任意)旧Input版(Input.GetKeyDown)での書き方
Input Systemを使っていない場合は、Updateでこう書けばOKです🙆
if (Input.GetKeyDown(KeyCode.Space) && !_bJump)
{
_rigid.AddForce(Vector2.up * _jumpSpeed, ForceMode2D.Impulse);
_bJump = true;
}まとめ
今回の処理は次の流れになっています。
① プレイヤーのコライダー情報を取得
② 足元の位置を計算
③ 小さい矩形を作る
④ BoxCastで下方向に判定
⑤ 地面に当たったか確認
⑥ ジャンプ可能か設定
この処理によって
- 空中ジャンプ防止
- 正確な接地判定
が実現できます!!
今回は、Unity2Dでのジャンプ実装方法を解説しました。

最後まで読んでいただきありがとうございました!
他にも、
「プレイヤーを追従させるカメラワークを作りたい」
「歩行やジャンプ時にアニメーションをつけたい」
という実装したい人は、こちらの記事もご興味あれば覗いてみてください👾





コメント