Unity Term Book
物理

Raycasting

Raycasting は不可視の光線を飛ばして Collider を探します——射撃、接地判定、マウスピック、視線チェックの基盤です。LayerMask と maxDistance、RaycastHit、SphereCast の使い分けを実践的に身につけられます。図解とシミュレーターで光線を追えます。

想像してみてください...

Raycast は暗闇の懐中電灯です。一方向に照らすと、何か当たるまでビームが進みます。 すると何に当たったか、どれだけ遠いかどこか面がどちらを向いているかを報告します。 シューターでは本物の物理弾の代わりに Raycast を使う——安く、速く、精密です。

概念の詳細

Physics.Raycast() は原点と方向を取り、光線が Collider に当たると true を返します。 詳細は RaycastHit に入ります:ヒット位置( .point)、面の向き(.normal)、距離( .distance)、物体(.collider)。

Unity には派生があります:Physics.RaycastAll() は経路上の全 Collider(最近傍だけではない)、 Physics.SphereCast() は球のスイープ(キャラの「スナップ」が滑らか)、 Physics.BoxCast() は箱のスイープ。Unity 2022+ では Physics.RaycastCommand で Job System 上の並列レイキャストも可能です。

パフォーマンス: Raycast は無料ではない——毎回 broadphase BVH を歩きます。 必ず LayerMaskmaxDistance を渡してください。毎フレームループは避け、 AI なら毎フレームではなく 0.2 秒ごとに 4 方向など。

よくある用途:shooting(hitscan、Rigidbody 弾なし)、 ground check(ジャンプ前に立っているか)、 mouse pickingCamera.ScreenPointToRay() でクリックを 3D 光線に)、 line of sight(AI とプレイヤーの間に遮るものがあるか)。

Raycast の派生

Raycast

直線のレイ。返すのは 最も近い Collider. ほとんどの用途に使う。

Physics.Raycast()

SphereCast

球体スイープ — キャラクター、大型武器、広範囲検出に向く。

Physics.SphereCast()

RaycastAll

経路上の すべての Collider を返す。徹甲弾やガラス越しのライトに使う。

Physics.RaycastAll()

ハンズオン手順

1

原点と方向を決める

FPS なら Camera.main.transform.position と .forward、接地判定なら Vector3.down がよく使われます。

2

RaycastHit を宣言

RaycastHit hit; — Physics.Raycast() に out hit を渡す。GC 回避のため Update の外に置く。

3

LayerMask を設定

Inspector で割り当てるか、LayerMask.GetMask("Enemy", "Ground") で必要なものだけ検査。

4

maxDistance を制限

必ず最大距離を渡す——無限光線はシーン全体を検査。例:銃 50f、接地 1.2f。

5

Scene ビューに Debug Ray を描く

Debug.DrawRay(origin, direction * maxDist, Color.green) — Play 中に見え、ビルドには影響なし。

インタラクティブシミュレーター

キャンバス上でマウスを動かして光線を狙い、障害物をドラッグできます。

マウスを動かしてください...

まだヒットなし

コード例

基本

Hitscan 射撃——Rigidbody 弾なしで撃つ。

using UnityEngine;

public class HitscanGun : MonoBehaviour
{
  public float range = 50f;
  public int damage = 25;
  public LayerMask shootMask;
  public ParticleSystem muzzleFlash;

  Camera cam;
  RaycastHit hit; // Declare outside Update to avoid GC

  void Start() => cam = Camera.main;

  void Update()
  {
      if (Input.GetButtonDown("Fire1")) Fire();
  }

  void Fire()
  {
      muzzleFlash.Play();

      // Ray from camera center, forward
      if (Physics.Raycast(cam.transform.position,
                         cam.transform.forward,
                         out hit, range, shootMask))
      {
          Debug.Log("Hit: " + hit.collider.name +
                     " at " + hit.distance.ToString("F1") + "m");

          hit.collider.GetComponent<Health>()
             ?.TakeDamage(damage);
      }
  }
}

コード例

上級

正確な接地判定とマウス→ワールドピック——最もよく使う二つ。

using UnityEngine;

public class RaycastUtils : MonoBehaviour
{
  [Header("Ground Check")]
  public float groundCheckDist = 1.2f;
  public LayerMask groundLayer;
  bool isGrounded;

  [Header("Mouse Picking")]
  public LayerMask clickable;

  Camera cam;
  RaycastHit hit;

  void Awake() => cam = Camera.main;

  void Update()
  {
      // Ground check every frame — SphereCast is smoother than Raycast
      isGrounded = Physics.SphereCast(
          transform.position, 0.4f,
          Vector3.down, out hit,
          groundCheckDist, groundLayer
      );

      // Click → world position
      if (Input.GetMouseButtonDown(0))
      {
          Ray ray = cam.ScreenPointToRay(Input.mousePosition);
          if (Physics.Raycast(ray, out hit, 100f, clickable))
          {
              Debug.Log("Clicked: " + hit.collider.name);
              // Move the character to hit.point
              MoveTo(hit.point);
          }
      }
  }

  void OnDrawGizmosSelected()
  {
      Gizmos.color = isGrounded ? Color.green : Color.red;
      Gizmos.DrawLine(transform.position,
          transform.position + Vector3.down * groundCheckDist);
  }
}

📌 要点

  • 常に LayerMask + maxDistance を渡す
  • RaycastHit は Update の外で一度宣言(GC 回避)
  • マウス→3D は Camera.ScreenPointToRay()
  • Scene ビューで光線を見るなら Debug.DrawRay()
  • キャラ移動には Raycast より SphereCast が滑らか

⚠️ よくあるミス

  • ❌ 光線が自分に当たる(self-hit)

    原点が射手の Collider 内——常に true

    ✅ 原点をオフセット(前方 +0.1f)、または自分の Layer を無視

  • ❌ MaxDistance なしで毎フレーム Raycast

    無限光線がシーン全体を検査し FPS が落ちる

    ✅ 用途に合った maxDistance を必ず渡す