【Unity】RayCastを使いこなせ!判定や表示に使ってみよう

Unityでゲームを作っていると注視アイテムの情報を取得したかったり、fpsの攻撃判定を実装したかったりする場面があると思います。そんな時にはUnityのraycastという機能を使えば簡単に実装できます。この記事では、

  • rayとは
  • rayを使って何ができるのか?
  • 複数のオブジェクトの取得
  • rayの可視化

といったように基本的な内容から少し応用的なことについてもわかりやすく解説いたします!

目次

rayとは?

そもそもrayとは和訳すると光線という意味になる英単語のことです。Unityで使われる場合も光線という意味合いで使われます。

ray(光線)の一般的な使用方法としてraycastという機能があります。raycastとは指定した場所から透明な光線を打ち、光線に当たったオブジェクトの情報を取得する機能のことです。

※オブジェクトにはコライダがアタッチされていないと当たりません

何ができるの?

これだけではわかりにくいと思うのでraycastを使った具体例を挙げていきましょう。

raycastを使った例として銃で敵を攻撃する場合などがあります。rayを弾丸に見立ててrayが当たったオブジェクトに弾が当たった時の処理を記述することで簡単に実装できます。

また、他の例としては画面上にあるアイテムの情報をタップして取得する場合などがあります。これはマウスカーソルからrayを飛ばすことにより実装できます。

実際に使ってみよう!

まずはraycastの使い方を説明しておきましょう。raycastはまず飛ばす光線部分(ray)を作ります。その後raycastを使って光線を飛ばしていきます。raycastは、

Physics.Raycast(Vector3 origin(rayの開始地点), Vector3 direction(rayの向き),RaycastHit hitInfo(当たったオブジェクトの情報を格納), float distance(rayの発射距離), int layerMask(レイヤマスクの設定));

といったように使います。いくつか要素がありますが、必要な要素はorigin(rayの開始地点)とdirection(rayの向き)のみです。hitInfoはオブジェクトの情報を取得したい場合入力してください。

他の要素を記入しなかった場合、distance(rayの発射距離)は永遠に続き、layerMask(レイヤマスクの設定)は初期設定のレイヤになります。発射されたrayとコライダがぶつかったらtrue、それ以外はfalseが返されます。

それでは実際に使ってみましょう。今回はタップしたところからrayを発射し、当たったオブジェクトの座標を取得してみます。まずはオブジェクトとスクリプトを用意してください。スクリプトに、

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

public class Test : MonoBehaviour {

     void Update()
    {   
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        RaycastHit hit;
        if (Physics.Raycast(ray,out hit,10.0f))
        {
            Debug.Log(hit.collider.gameObject.transform.position);
        }
    }
}

を記入してください。出力結果は、

タップした画像の位置情報を取得できていますね!簡単にコードの解説をしておきましょう。今回はUpdate関数の中に記述していきます。

Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);

ではカメラ上で画面をタップした場所の位置情報と方向をrayに格納しています。

 if (Physics.Raycast(ray,out hit,10.0f))
        {
            Debug.Log(hit.collider.gameObject.transform.position);
        }

の部分でraycastを行い、もしrayがオブジェクトのコライダに当たったらその位置情報をログ出力します。raycastでは引数にrayの位置情報と方向は必須でしたが、今回はrayにそれら二つの情報が格納されています。

hitに当たったオブジェクトの情報が格納され、10.0fというのはrayが飛んでいく距離です。

さらに応用的な使い方

raycastのさらに応用的な使い方についてみていきましょう。複数のオブジェクトを取得、rayの可視化、raycastを使う上での注意点をそれぞれ書いていきます。

複数のオブジェクトを取得

先ほどの例ではrayがはじめに当たったオブジェクトの情報しか取得できませんでした。この章ではrayが当たった全てのオブジェクトを取得してみます!わかりやすくするためにrayの軌道上にオブジェクトを三つ連ねて置いておきます。

それではコードを書いていきましょう!

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

public class Test : MonoBehaviour {

     void Update()
    {
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        foreach (RaycastHit hit in Physics.RaycastAll(ray))
        {
            Debug.Log(hit.collider.gameObject.transform.position);
        }

    }
}

このコードでは前回と同じようにタップした位置からrayを飛ばしています。違うのはrayに当たった全てのオブジェクトの位置情報を取得している点です。実行結果は、

配置した三つのオブジェクトの位置情報を全て取得しています!コードの解説をしておきましょう。先ほどのコードと異なる点は、

foreach (RaycastHit hit in Physics.RaycastAll(ray))
        {
            Debug.Log(hit.collider.gameObject.transform.position);
        }

の部分ですね。foreach文とRaycastAllを使っている点が異なります。RaycastAllはrayを引数に取って使います。

rayの可視化

次はrayの可視化を行いましょう。

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

public class Test : MonoBehaviour {

     void Update()
    {   
        Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
        RaycastHit hit;
        if (Physics.Raycast(ray,out hit,10.0f))
        {
            Debug.Log(hit.collider.gameObject.transform.position);
        }
        Debug.DrawRay(ray.origin, ray.direction * 10, Color.red, 5);
    }
}

実行結果は、

Sceneビューでrayが可視化されていますね!このコードは最初のコードに

Debug.DrawRay(ray.origin, ray.direction * 10, Color.red, 5);

を追加しただけです。使い方は、

Debug.DrawRay (Vector3 start(rayを開始する位置), Vector3 dir(rayの方向と長さ), Color color(ラインの色), float duration(ラインの表示される時間), bool depthTest(ラインがカメラから近いオブジェクトによって隠された場合にラインを隠すかどうか));

となっています。必須部分はstartとdirのみです。

raycastを使う上での注意点

最後にraycastを使う上でのちょっとした注意点を書いておきましょう。raycastを使いすぎると処理が重くなりますので、ほどほどにしましょう。また、rayの長さを短くすると軽量化を図ることができます。

まとめ

いかがでしたか?Unityのraycastについて説明してきました。raycastを使いこなせれば作れるゲームの幅が広がるので、ぜひ使ってみてくださいね!

この記事を書いた人

学生時代を含めると、かれこれ10年以上プログラマーとして過ごしています。
様々な言語や環境、プロジェクトに関わってきましたので、より実践的な記事をみなさんにお届きるよう情報発信していきます!

目次