【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の個別指導のオンラインレッスンを行っています。
ご興味のある方は当サイト、オンラインレッスンから、無料体験授業へお問い合わせ下さい。
いいなと思ったら応援しよう!
よろしければ応援お願いします! いただいたチップはクリエイターとしての活動費に使わせていただきます!