見出し画像

【Unity初心者向け】Raycast の活用② | Raycastで地面や壁を判定する

Raycast は、指定した場所から指定した方向へ見えない線を飛ばして、Collider があるかを調べる仕組みです。

2Dでは、

Physics2D.Raycast()

を使って Raycast を飛ばすことができます。
今回は、Raycast をもう一歩実用的に使ってみましょう。

Raycastを使って、

  • 何かに当たったか

  • 何に当たったのか

  • 地面だけを調べる

  • 壁だけを調べる

といった判定を行います。

ゲーム制作では、

  • プレイヤーが地面に立っているか調べる

  • 敵の前に壁があるか調べる

といった場面で Raycast を利用できます。

それでは、実際に確認していきましょう。



Raycast() を実行

前回の確認

まずは前回のおさらいです。

次のように書くと、オブジェクトの位置から下方向へRaycastを飛ばすことができます。

RaycastHit2D hit = Physics2D.Raycast(
    transform.position,
    Vector2.down,
    2f
);

それぞれ、

  • transform.position → Raycastを飛ばし始める位置

  • Vector2.down → Raycastを飛ばす方向

  • 2f → Raycastを飛ばす距離

そして、

Physics2D.Raycast()

を実行した結果を、RaycastHit2D hit に保存しています。

今回は、この hit の中身を使っていきます。


Raycastが何かに当たったか調べる

Raycastを飛ばしたとき、何かに当たったのかを確認するには、

hit.collider

を使います。
たとえば、次のように書きます。

if (hit.collider != null)  //何かに当たっていたら
{
    Debug.Log("何かに当たりました");
}

ここで登場する、

hit.collider

には、Raycast が当たった Collider の情報 が入ります。
Raycast が Collider に当たっていれば、hit.collider にはその Collider が入ります。

反対に、何にも当たっていない場合は、null になります。
そのため、

hit.collider != null

と書くことで「hit.colliderがnullではない」
つまり「Raycastが何かに当たった」ことを確認できます。


何に当たったのか確認

Raycastが何かに当たったことが分かったら、次は何に当たったのか?も確認することができます。

次のように変更してみましょう。

if (hit.collider != null)
{
    Debug.Log(hit.collider.name);
}

ここでは、

hit.collider.name

を表示しています。

hit.collider には Raycast が当たった Collider が入っているため、
.name
を付けることで、そのColliderが付いているオブジェクトの名前を取得できます。

たとえば、地面オブジェクトの名前が「Ground」なら、Consoleには、

Ground

と表示されます。

壁に当たって、そのオブジェクト名が「Wall」なら、

Wall

と表示されます。

つまりRaycastでは「当たったかどうか」だけではなく、「何に当たったのか」も確認できます。


RaycastHit2Dのその他情報

今回使用している、

RaycastHit2D hit

には、Collider以外にもさまざまな情報が入っています。
たとえば、

  • hit.point → Raycastが当たった位置

  • hit.normal → 当たった面の向き

などを調べることができます。
この部分は次回以降の解説で、改めて説明します。

まずは「RaycastHit2Dには、Raycastが当たった結果についてのさまざまな情報が入っている」ということを覚えておきましょう。



Raycastを使って地面を判定

それでは、Raycastを使って地面があるか調べてみましょう。

次のスクリプトを作ります。

public class GroundCheck : MonoBehaviour
{
    void Update()
    {
        // Raycastを使って地面の有無をチェック
        RaycastHit2D hit = Physics2D.Raycast(
            transform.position,     // Raycastの発射位置
            Vector2.down,           // Raycastの方向(下方向)
            1f                      // Raycastの距離
        );

        if (hit.collider != null)   // Raycastが何かに当たった場合
        {
            Debug.Log("地面があります");
        }
    }
}

今回は、

Vector2.down

を指定しているため、オブジェクトから下方向へRaycastが飛びます。

if (hit.collider != null)

でColliderに当たったか確認しています。
オブジェクトの下にColliderがあれば、

地面があります

と表示されます。
これだけを見ると、地面を判定できているように見えます。

しかし、現在のRaycastは Collider であれば何にでも反応します。

たとえばオブジェクトの下に、

  • 地面

  • 敵

  • アイテム

  • 壁

などがあった場合でも、Collider が付いていれば Raycast は当たります。
つまり現在のスクリプトでは、

地面があります

と表示されたとしても、本当に地面に当たっているとは限りません。
そこで、調べたい対象だけにRaycastを反応させる仕組みを使います。

それが、LayerMask です。


Layerとは

Unity の GameObjectには、Layer を設定することができます。

たとえば、

  • Player

  • Enemy

  • Ground

  • Wall

のように、GameObject を種類ごとに分けることができます。
Raycastでは、このLayerを利用して、

  • Groundだけ調べる

  • Wallだけ調べる

といった指定をすることができます。


Ground Layerを指定

まず、地面として使用しているGameObjectを選択します。

Inspector上部にある、Layer を確認します。

新しく、Ground というLayerを作成し、地面オブジェクトに設定しておきましょう。

これでUnity側では、このオブジェクトはGroundであるという区別ができます。


LayerMaskをスクリプトに追加

次にスクリプトへ、LayerMask 型の変数として

public LayerMask groundLayer;

を追加します。

保存してUnityへ戻ると、Inspector にLayerを指定する項目が表示されます。ここで、

Ground

を選択します。


RaycastにLayerMaskを設定

続いて、

Physics2D.Raycast()

を変更します。

RaycastHit2D hit = Physics2D.Raycast(
    transform.position,
    Vector2.down,
    1f,
    groundLayer  // Raycastが当たるレイヤーを指定
);

4つ目の引数に、対象のレイヤーを指定しました。

この指定によって、groundLayerに設定したLayerだけをRaycastで調べることができます。

今回、InspectorからGroundを設定しているため、Ground LayerのColliderだけに反応するRaycast になります。


完成した地面判定

ここまでをまとめると、次のようになります。
この先の展開を考えて、Rayを飛ばす距離も変数で追加します。

public class GroundCheck : MonoBehaviour
{
    public LayerMask groundLayer;
    public float rayDistance = 5f;  // Raycastの距離

    void Update()
    {
        // Raycastを使って地面の有無をチェック
        RaycastHit2D hit = Physics2D.Raycast(
            transform.position,
            Vector2.down,         
            rayDistance,            // Raycastの距離(変数に置き換え)
            groundLayer             // Raycastが当たるレイヤーを指定
        );

        if (hit.collider != null)   // Raycastが何かに当たった場合
        {
            Debug.Log("地面があります");
        }
    }
}

Raycastを見えるようにして確認

Raycastそのものはゲーム画面には表示されません。
そこで前回使用した、

Debug.DrawRay()

を使って確認してみましょう。
Update関数内に、以下のコードを追記します。

Debug.DrawRay(                      // デバッグ用にRayを可視化
    transform.position,             // Raycastの発射位置
    Vector2.down * rayDistance,     // Raycastの方向と距離
    Color.red                       // Rayの色
);

Playボタンを押して確認すると、オブジェクトから下方向へRayが伸びていることを確認できます。

もし地面判定がうまくいかない場合は、

  • Raycastの方向

  • Raycastの長さ

  • 地面の Layer と BoxCollider2D

  • Inspector の LayerMask

などを確認してみましょう。


壁も同じ考え方で判定できる

ここまで地面を調べてきましたが、壁の判定も基本的な考え方は同じです。地面の場合は、Vector2.down を使って下方向へRaycastを飛ばしました。
壁を調べたい場合は、横方向へRaycastを飛ばします。
たとえば右方向なら、Vector2.right を使って

RaycastHit2D hit = Physics2D.Raycast(
    transform.position,
    Vector2.right,
    1f,
    wallLayer
);

壁にも、Wall というLayerを設定しておき、

public LayerMask wallLayer;

を使えば、壁だけを調べることができます。


LayerMaskを使う理由

ここまで見ると、

hit.collider.name

を使って、

if (hit.collider.name == "Ground")

のように判断してもよさそうに見えるかもしれません。
しかし、Raycastでは最初からLayerMaskを使って、調べる必要のないColliderを対象から外しておく方が分かりやすくなります。

たとえば、

  • 地面判定 → Ground Layerだけ調べる

  • 壁判定 → Wall Layerだけ調べる

と役割を分けることができます。

ゲームが大きくなり、Colliderを持つオブジェクトが増えてくるほど、Layerを使った管理が便利になります。


今回のまとめ


次回は「崖から落ちない敵」を作ろう

今回は、下方向へRaycastを飛ばして地面を調べる方法と、横方向へRaycastを飛ばして壁を調べる方法を確認しました。

では、この2つを同時に使うとどうなるでしょうか。

次回は、

  • 前に壁があったら引き返す

  • 足元に地面がなくなったら引き返す

という2つのRaycastを組み合わせて、壁にぶつからず、崖からも落ちない敵を作ってみます。

今回学んだ地面判定と壁判定が、実際のゲームの動きにどうつながるのか確認していきましょう。


こちらはUnity初心者向けの記事をテーマ別にまとめています。
▼ Unity初心者向け記事まとめはこちら


こちらのマガジン「ミニゲーム作成講座 全8回セット」でもシーンの切り替えなどを活用して、初心者でも知識ゼロから作れるミニゲーム作成講座を紹介しています。

さらにステップアップの「スマホで遊ぶジャンプゲーム 8回セット」のマガジンもぜひご活用ください。


ファイブボックスでは、スクラッチやUnityの個別指導のオンラインレッスンを行っています。
ご興味のある方は当サイト、オンラインレッスンから、無料体験授業へお問い合わせ下さい。

いいなと思ったら応援しよう!

ファイブボックス よろしければ応援お願いします! いただいたチップはクリエイターとしての活動費に使わせていただきます!