【Unity】Raycastの使い方|当たり判定・距離取得・可視化と当たらない原因
UnityのRaycastは、始点から指定方向へ線を伸ばし、途中にあるColliderを調べる機能です。Physics.Raycastで当たった相手を取得し、hit.distanceで距離を測れます。見えない線を確認するときはDebug.DrawRayを使いましょう。
まずは前方に1本飛ばす例で、判定・距離・可視化をまとめて確認します。後半では、当たらないときの確認方法と、3本/360度に飛ばす例を紹介します。対象は3DのPhysics.Raycastです。
RaycastとColliderの関係
Colliderは当たり判定に使う「形」、Raycastはその形に線が交わるかを調べる「処理」です。相手にBoxColliderなどが必要ですが、Raycastで検出するだけならRigidbodyは必須ではありません。衝突イベントの条件とは分けて考えましょう。
Colliderの種類や設定は、Colliderの使い方で解説しています。足元の地面を調べる、照準の先にある物体を調べる、といった場面にRaycastを使えます。
前方の物体を検出し、距離を取得する
Cubeを2つ配置する
Hierarchyで右クリックし、3D Object → Cubeから2つ作成します。動かさずに試すなら、Rigidbodyは追加しなくて大丈夫です。次の配置なら、左のCubeの前方(ローカルZ方向)が右のCubeを向きます。
| 設定 | Rayを出すCube | 検出するCube |
|---|---|---|
| 名前 | RayOrigin | Target |
| Position(X, Y, Z) | (-2, 1, 0) | (0, 1, 0) |
| Rotation(X, Y, Z) | (0, 90, 0) | (0, 0, 0) |
| Scale | (1, 1, 1) | (1, 1, 1) |
| BoxCollider | 付いたままでOK | 有効・Is Triggerはオフ |

Physics.RaycastとRaycastHitのコード
ForwardRaycast.csを作成し、次のコードを保存してRayOriginにアタッチします。再生すると、前方5ユニットまでを判定し、当たった相手の名前と距離をConsoleへ出力します。SceneビューのGizmosもオンにしてください。
using UnityEngine;
public class ForwardRaycast : MonoBehaviour
{
[SerializeField] private float rayDistance = 5f;
private void Update()
{
Ray ray = new Ray(transform.position, transform.forward);
bool hasHit = Physics.Raycast(ray, out RaycastHit hit, rayDistance);
// 判定する距離全体を赤い線で表示
Debug.DrawRay(ray.origin, ray.direction * rayDistance, Color.red);
if (hasHit)
{
Debug.Log($"相手: {hit.collider.name} / 距離: {hit.distance:F2}");
}
}
}Ray構造体には始点と方向をまとめます。Physics.Raycastの戻り値は「当たったかどうか」のbool値です。out RaycastHit hitは結果を受け取る変数を用意する書き方で、hitの情報はtrueになったときだけ使います。この書き方では、線上で最も近い対象の情報を取得します。
| 値 | 分かること |
|---|---|
| hit.collider | 当たったCollider。名前はhit.collider.nameで取得 |
| hit.distance | 始点から当たった位置までの距離 |
| hit.point | 当たった位置のワールド座標 |
| hit.normal | 当たった面の法線(面に垂直な向き) |
この配置では、始点からTargetの中心までは2ユニットですが、手前の面までは1.5ユニットです。hit.distanceは中心間の距離ではありません。Consoleには当たっている間ログが出続けるので、確認後はDebug.Logを外して使いましょう。
Debug.DrawRayでRayを可視化する
上のコードでは、判定する方向と距離を赤い線で描いています。Debug.DrawRayの第2引数は「方向×表示する長さ」で、終点の座標ではありません。Raycastによる判定と、線の描画は別の処理です。
線が見えないときは、再生中か、SceneビューのGizmosがオンかを確認します。GameビューにもGizmosをオンにすれば表示できます。ゲーム内のレーザーなど、プレイヤーに見せる線にはLineRendererなどを使います。
表示時間を省略すると線は1フレームだけ描かれるため、この例ではUpdateから毎フレーム呼んでいます。物体に隠れる場合は、確認用に第5引数のdepthTestをfalseにすると見つけやすくなります。
Debug.DrawRay(ray.origin, ray.direction * rayDistance, Color.red, 0f, false);Raycastが当たらないときの確認ポイント
| 確認する場所 | 見直すこと |
|---|---|
| Collider | 対象に3DのColliderがあり、有効になっているか。対象GameObjectもアクティブか |
| 方向と距離 | transform.forwardは物体の向きに追従する。線が対象まで届くかDebug.DrawRayで確認 |
| 始点 | 3DのRaycastでは、始点を内側に置いたCollider自身は検出されない。対象の外から飛ばす |
| LayerMask | 対象のLayerが判定に含まれるか。既定ではIgnore Raycastレイヤーは対象外 |
| Is Trigger | Triggerを無視する設定になっていないか。必要ならQueryTriggerInteraction.Collideを指定 |
| 2Dとの違い | BoxCollider2DなどはPhysics2D.Raycastで調べる。3D用とはAPIも判定対象も別 |
LayerとTriggerを指定する場合
特定のLayerだけ調べたい場合は、ForwardRaycastクラスのrayDistanceの下に次のフィールドを追加します。InspectorのHit Layersで対象Layerを選び、Physics.Raycastの行を次のように置き換えてください。この例ではTriggerを無視します。
[SerializeField] private LayerMask hitLayers = Physics.DefaultRaycastLayers;bool hasHit = Physics.Raycast(ray, out RaycastHit hit, rayDistance,
hitLayers, QueryTriggerInteraction.Ignore);Triggerも調べるならIgnoreをCollideに変えます。UseGlobalはPhysics設定に従います。LayerMaskはLayer番号そのものではなく、対象Layerの組み合わせを表す値です。Inspectorで選ぶと取り違えを防げます。
Rayを3本飛ばす:前・右斜め・左斜め
ThreeRays.csとして保存し、発射側にアタッチします。1本の例と同時に動かす必要はないので、ForwardRaycastは無効にしてください。前方に加え、左右45度の方向も調べます。ラベルを付けると、どの線が当たったかをログで区別できます。
using UnityEngine;
public class ThreeRays : MonoBehaviour
{
[SerializeField] private float rayDistance = 5f;
private void Update()
{
Cast("Forward", transform.forward);
Cast("Right", (transform.forward + transform.right).normalized);
Cast("Left", (transform.forward - transform.right).normalized);
}
private void Cast(string label, Vector3 direction)
{
if (Physics.Raycast(transform.position, direction,
out RaycastHit hit, rayDistance))
{
Debug.Log($"{label}: {hit.collider.name}");
}
Debug.DrawRay(transform.position, direction * rayDistance, Color.red);
}
}斜め方向は、前と右(または左)を足してnormalizedで正規化します。詳しくはVector3の加算・正規化の使い方を参照してください。
Rayを360度に飛ばす:レーダー風の判定
RadialRays.csを作成し、ほかの例を無効にして発射側へアタッチします。ワールドのXZ平面に、36本なら10度間隔でRayを飛ばします。発射側のX・Z回転が変わっても、この例の線は水平に広がります。
using UnityEngine;
public class RadialRays : MonoBehaviour
{
[SerializeField] private float rayDistance = 10f;
[SerializeField, Min(1)] private int rayCount = 36;
private void Update()
{
for (int i = 0; i < rayCount; i++)
{
float angle = i * 360f / rayCount;
// ワールドの水平面(XZ平面)に広げる
Vector3 direction = Quaternion.Euler(0f, angle, 0f) * Vector3.forward;
if (Physics.Raycast(transform.position, direction,
out RaycastHit hit, rayDistance))
{
Debug.Log($"Ray[{i}] 角度 {angle:F0}°: {hit.collider.name}");
}
Debug.DrawRay(transform.position, direction * rayDistance, Color.cyan);
}
}
}Rayは細い線なので、線と線の間にある小さな物体は見逃します。周囲の範囲内にある物体を拾うならPhysics.OverlapSphere、太さを持たせて調べるならPhysics.SphereCastなど、目的に合う判定を選びましょう。大量のRayや毎フレームのログは負荷にもつながります。
まとめ
Raycastは、Colliderに向けて始点・方向・距離を指定するのが基本です。まず1本の線をDebug.DrawRayで見えるようにすると、向きや距離の間違いを見つけやすくなります。判定できたらhitの情報を使い、必要に応じてLayerの絞り込みや複数方向へ広げてみてください。
参考資料
仕様はUnity 6.0の公式資料で確認しています。Physics.Raycast / RaycastHit / Debug.DrawRay / Physics2D.Raycast
サイトアイコン-2-150x150.png)