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 を歩きます。
必ず LayerMask と maxDistance を渡してください。毎フレームループは避け、
AI なら毎フレームではなく 0.2 秒ごとに 4 方向など。
よくある用途:shooting(hitscan、Rigidbody 弾なし)、
ground check(ジャンプ前に立っているか)、
mouse picking(
Camera.ScreenPointToRay() でクリックを 3D 光線に)、
line of sight(AI とプレイヤーの間に遮るものがあるか)。
Raycast の派生
直線のレイ。返すのは 最も近い Collider. ほとんどの用途に使う。
Physics.Raycast()
球体スイープ — キャラクター、大型武器、広範囲検出に向く。
Physics.SphereCast()
経路上の すべての Collider を返す。徹甲弾やガラス越しのライトに使う。
Physics.RaycastAll()
ハンズオン手順
原点と方向を決める
FPS なら Camera.main.transform.position と .forward、接地判定なら Vector3.down がよく使われます。
RaycastHit を宣言
RaycastHit hit; — Physics.Raycast() に out hit を渡す。GC 回避のため Update の外に置く。
LayerMask を設定
Inspector で割り当てるか、LayerMask.GetMask("Enemy", "Ground") で必要なものだけ検査。
maxDistance を制限
必ず最大距離を渡す——無限光線はシーン全体を検査。例:銃 50f、接地 1.2f。
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 を必ず渡す