キャラクターの接地をRaycastで判定【Unityゲーム作成】

Unityで「キャラクターが地面に着地しているかを判定する」のを実装していきます。いわゆる接地判定というものですね。

色々な方法がありますが、今回はRaycastを利用していきます。Raycastは接地だけでなく、オブジェクト(物)の有無判定にも使えます。

はじめに

「Unity 2020.3.26f1」ヴァージョンで作成しています。

2Dゲームで「プレイヤー(キャラクター)が地面に着地している時だけジャンプできる」のを実装していきます。2段ジャンプをできないようにするという感じですね。

実装開始

実装は「フィールド作成」→「プレイヤー作成」→「判定追加(Raycast)」の順番で行います。

フィールド作成

まずは簡単に画面を作成。

「2Dオブジェクト」→「スプライト」→「正方形」を追加。

名前をPlayerにしておきます。

同じく、正方形のオブジェクトを追加。位置、スケール、色を変更して地面にします。

下記の様な感じにします。白い四角がプレイヤー、黒い下部分が地面です。

プレイヤーのジャンプ

プレイヤーがジャンプできるように「Box Collider 2D」と「Rigidbody 2D」をアタッチ。

地面には「Box Collider 2D」を追加。

PlayerJumpと言う名前で、下記のスクリプトを作成スペースキーを押したらジャンプするという簡単なものです。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerJump : MonoBehaviour
{
    [SerializeField] private float jumpPower;
    private Rigidbody2D _rigidbody;
 
   void Start()
    {
        _rigidbody = GetComponent<Rigidbody2D>();
    }

    void Update()
    {
        if (Input.GetKey(KeyCode.Space))
        {
            _rigidbody.velocity = new Vector2(_rigidbody.velocity.x, jumpPower);
        }
    }
}

プレイヤーにアタッチします。

スペースキーを押してジャンプすればOK、連続でスペースを押すとジャンプし続けます。

接地判定追加

スクリプトを変更して「プレイヤーが地面に着地している時だけ」ジャンプできるようにします。

下記の様に変更します。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerJump : MonoBehaviour
{
    [SerializeField] private float jumpPower;
    [SerializeField] private LayerMask groundLayer;
    private Rigidbody2D _rigidbody;

    void Start()
    {
        _rigidbody = GetComponent<Rigidbody2D>();
    }

    void Update()
    {
        if (Input.GetKey(KeyCode.Space) && isGrounded())
        {
            _rigidbody.velocity = new Vector2(_rigidbody.velocity.x, jumpPower);
        }
    }
    private bool isGrounded()
    {
        RaycastHit2D raycastHit = Physics2D.Raycast(transform.position, Vector2.down, 0.6f, groundLayer);
        return raycastHit.collider != null;
    }
}

Raycastを直訳すると「Ray=光線」、「cast=投げる」と言う感じですかね。センサーを出して、接触したオブジェクトを検知するという感じです。

上記の場合のパラメータは、「センサーの発射位置」、「方向」、「長さ」、「対象のレイヤー」です。

プレイヤーの原点から下方向に短いセンサーを飛ばし、当たったか当たっていないかを判定しているという感じです。

Groundのレイヤーに「Ground」を追加し、Playerのスクリプトのパラメータをセット。

これでプレイヤーが地面に着地している時しかジャンプ出来なければOK。

ギズモ

実際にセンサーがどう出ているのかをGizmoで表示してみます。

スクリプトに下記を追加。

    void OnDrawGizmos()
    {
        Gizmos.color = Color.red;
        Gizmos.DrawRay(transform.position, new Vector3(0, -0.6f, 0));
    }

画面に赤線が出ます。この赤線にGroundが触れると検知されます。

下記スクリプトに変更すると、プレイヤーの下からセンサーが出ている感じになります。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerJump : MonoBehaviour
{
    [SerializeField] private float jumpPower;
    [SerializeField] private LayerMask groundLayer;

    private Rigidbody2D _rigidbody;
    void Start()
    {
        _rigidbody = GetComponent<Rigidbody2D>();
    }

    void Update()
    {
        if (Input.GetKey(KeyCode.Space) && isGrounded())
        {
            _rigidbody.velocity = new Vector2(_rigidbody.velocity.x, jumpPower);
        }
    }
    private bool isGrounded()
    {

        RaycastHit2D raycastHit = Physics2D.Raycast(_rayposition(), Vector2.down, 0.1f, groundLayer);
        return raycastHit.collider != null;
    }
    void OnDrawGizmos()
    {
        Gizmos.color = Color.red;
        Gizmos.DrawRay(_rayposition(), new Vector3(0, -0.1f, 0));
    }

    private Vector3 _rayposition()
    {
        return new Vector3(transform.position.x, transform.position.y - (transform.localScale.y / 2), transform.position.z);
    }
}

下記の様な場合、線ではなくボックスでセンサーを飛ばすBoxCastを利用すると正しく判定出来たり。

「何」を「どう動かしたいか」で利用するのが変わってきますね。

接地を判定するので下方向に飛ばしていますが、上に飛ばしたり、横に飛ばすことで他にも利用できますね。

タイトルとURLをコピーしました