Unity 6でキャラクターを動かしてジャンプさせる ― Input SystemとRigidbody2Dの基本

広告

はじめに

前回の記事では、transform.position を書き換えてPlayerを動かしました。この方法は簡単ですが、床に乗る、壁にぶつかる、ジャンプして落ちるといった動きは、自分で計算する必要があります。

今回は、動きを物理エンジン(Rigidbody2D)に任せる方法に切り替えます。左右の移動とジャンプを作り、「空中ではジャンプできない」ところまで仕上げます。

今回作るもの

左右移動、接地中のスペースキーでジャンプ、GroundCheckによる接地判定の3つの操作を示した図
  • A / D キー(または矢印キー)で左右に動く
  • スペースキーでジャンプする
  • 地面に立っているときだけジャンプできる(空中ジャンプは不可)

準備

Input Systemの準備(Project-wide Actions の InputSystem_Actions、Active Input Handling)は前回の記事と同じです。まだの方は、前回の記事を先に確認してください。

① 地面(Ground)を作る

  1. Hierarchyで右クリック → 2D Object → Sprites → Square を作り、名前を Ground にする
  2. Position を (0, -3, 0)、Scale を (10, 1, 1) にする
  3. Add Component で Box Collider 2D を追加する
  4. Inspector右上の Layer → Add Layer で Ground というレイヤーを作り、Groundに設定する

② Playerを作る

  1. Square を作り、名前を Player にする(Positionは (0, 0, 0))
  2. Rigidbody 2D を追加する(Body Type は Dynamic のまま)
  3. Box Collider 2D を追加する
  4. Rigidbody 2D の Constraints を開き、Freeze Rotation の Z にチェックを入れる(倒れて転がるのを防ぐ)
  5. Gravity Scale を 3 にする(落ち方が重くなり、ジャンプが操作しやすくなる)

③ 足元の目印(GroundCheck)を作る

  1. Player を右クリック → Create Empty で子オブジェクトを作り、名前を GroundCheck にする
  2. Position を (0, -0.5, 0) にする(標準のSquareは1×1なので、足元はちょうど -0.5。大きさを変えた場合は足元に合わせる)

Player自身は Ground レイヤーにしません(Defaultのままにします)。

スクリプトを書く

Player に PlayerController というスクリプトを追加し、次のように書きます。

using UnityEngine;
using UnityEngine.InputSystem;

public class PlayerController : MonoBehaviour
{
    [SerializeField] private float moveSpeed = 5.0f;
    [SerializeField] private float jumpSpeed = 10.0f;
    [SerializeField] private Transform groundCheck;
    [SerializeField] private float groundCheckRadius = 0.1f;
    [SerializeField] private LayerMask groundLayer;

    private Rigidbody2D rb;
    private InputAction moveAction;
    private InputAction jumpAction;

    private void Start()
    {
        rb = GetComponent<Rigidbody2D>();
        moveAction = InputSystem.actions.FindAction("Player/Move");
        jumpAction = InputSystem.actions.FindAction("Player/Jump");
    }

    private void Update()
    {
        // 左右:横方向の速さだけ決める。縦方向は今の速さのまま(重力に任せる)
        Vector2 moveInput = moveAction.ReadValue<Vector2>();
        rb.linearVelocity = new Vector2(moveInput.x * moveSpeed, rb.linearVelocity.y);

        // ジャンプ:押した瞬間 かつ 地面にいるとき
        if (jumpAction.WasPressedThisFrame() && IsGrounded())
        {
            rb.linearVelocity = new Vector2(rb.linearVelocity.x, jumpSpeed);
        }
    }

    private bool IsGrounded()
    {
        // 足元の小さな円がGroundレイヤーのColliderに触れているか
        return Physics2D.OverlapCircle(groundCheck.position, groundCheckRadius, groundLayer) != null;
    }
}

Inspector で次のように設定します。

項目設定
Move Speed5
Jump Speed10
Ground CheckPlayerの子の GroundCheck をドラッグ
Ground Check Radius0.1
Ground LayerGround

再生して、A / D(または矢印キー)で動き、スペースキーでジャンプできれば成功です。

コードを読む

入力の取り方(前回と同じ)

InputSystem.actions.FindAction("Player/Move") で、Project-wide Actions の Player マップにある Move を取得します。Jump も同じ形で取ります。毎フレーム探さず、Start で1回だけ探して保存しておきます。

rb.linearVelocity:速さを直接決める

Rigidbody2D の速さ(1秒あたりに進む距離)です。横方向は入力から決め、縦方向は rb.linearVelocity.y(今の値)をそのまま残しています。こうすると、落下や着地は物理エンジンに任せたまま、左右だけ操作できます。

古い記事で rb.velocity と書かれていたら、Unity 6では rb.linearVelocity に読み替えます。

WasPressedThisFrame():押した瞬間だけ true

スペースキーを押したそのフレームだけ true になります。押しっぱなしでも1回しか反応しないので、ジャンプの入力に向いています。

Physics2D.OverlapCircle:足元に地面があるか

足元(GroundCheck)に小さな円を置き、Ground レイヤーのColliderに触れているかを調べます。触れていればそのColliderが返り、何もなければ null が返ります。!= null で「地面にいるか」の true / false にしています。

数字で見る

Gravity Scale 3、Jump Speed 10 の場合の目安です(Physics 2D の重力は標準で 9.81)。

項目計算目安
重力9.81 × 3約 29.4
ジャンプの高さ10 × 10 ÷ (2 × 29.4)約 1.7(Playerの高さの約1.7倍)
空中にいる時間2 × 10 ÷ 29.4約 0.68 秒
横の移動Move Speed 51秒で 5 進む

Jump Speed や Gravity Scale を変えて、高さと時間がどう変わるか試してみましょう。

よくあるつまずき

症状原因と直し方
何も動かない / NullReferenceExceptionFindAction の名前が違う(Player/Move、Player/Jump)か、Project-wide Actions が未設定。前回の記事の確認手順を見直す
ジャンプできないGround Layer が未設定、Ground Check が未割り当て、地面のレイヤーが Ground になっていない
空中で何度でもジャンプできるPlayer自身が Ground レイヤーになっている(自分のColliderに触れて、常に「地面にいる」になる)
Playerが倒れて転がるRigidbody 2D の Freeze Rotation Z にチェックが入っていない
壁に押し付けると張り付いて落ちない壁との摩擦が原因。Physics Material 2D を作って Friction を 0 にし、PlayerのColliderに設定する
ジャンプが高すぎる / ふわふわするJump Speed を下げる、または Gravity Scale を上げる

もう一歩

物理の処理は FixedUpdate に書くのが本来の形です。ただし、ボタンを押した瞬間の入力は Update で受け取らないと取り逃すことがあります。慣れてきたら、Update で「ジャンプを押した」という印(bool)だけ保存し、FixedUpdate で速さに反映する書き方にも挑戦してみましょう。

まとめ

  • 動きを物理に任せるときは、Rigidbody2D の linearVelocity を使う
  • 横は入力から決め、縦は今の値を残す
  • ジャンプは WasPressedThisFrame() と接地判定の組み合わせで作る
  • 接地判定は、足元の円(OverlapCircle)とレイヤーで行う

次回は、このPlayerを含むゲームを、Build Profilesを使ってWebGLやAndroidに出力します。

訪問数 9 回, 今日の訪問数 9回

広告