UnityでRaycastを撃つときにVector3.upを加える理由

はじめに

Unityで「敵がプレイヤーを見ているか」を判定する処理や、キャラクターの視線チェックを実装するとき、Raycastの始点に Vector3.up * 0.2f のようなオフセットを加えるコードを見かけることがあります。

Vector3 from = transform.position + Vector3.up * 0.2f;
Vector3 to   = target.position + Vector3.up * 0.2f;

なぜ「ちょっと上」にずらす必要があるのでしょうか?

この記事では、その理由と実践での調整ポイントを解説します。


1. 自分自身のコライダーを避けるため

Raycastをオブジェクトのtransform.position(多くの場合はキャラクターの中心や足元)から飛ばすと、自分自身のコライダーに当たってしまうことがあります。

その結果、毎回「遮蔽物あり」と判定されてしまい、正しく動作しません。

オフセットを少し加えることで、レイの始点が自分のコライダーの外に出るため、誤検出を回避できます


2. キャラクターの「視線の高さ」を表現するため

もしRayを足元から飛ばすと、ゲーム的には「地面スレスレの視線」になります。

これでは自然さに欠けるだけでなく、腰の高さの壁や柵にすぐに遮られてしまいます。

Vector3.up * 0.2f のようにオフセットを加えることで、キャラクターの目の位置からレイを飛ばすイメージを作れます。

実際のゲームでは 0.2f より大きな値(例:1.5f)にして「人間の目線の高さ」を再現することもあります。


3. 遮蔽物との交差を防ぐため

床や壁に少しでも埋まっている状態でRaycastを撃つと、始点がコライダーの内部になり、「常に遮蔽されている」扱いになってしまうことがあります。

上方向に少しずらすことで、始点が空間中にある状態を保証でき、安定した動作が期待できます。


4. 値(0.2f)はどう決める?

0.2f という数値は「小さなオブジェクトを前提にした一例」であり、固定のルールはありません。

  • 小さな敵キャラ:0.2f ~ 0.5f
  • 人型キャラクター:1.0f ~ 1.8f(身長に応じて)
  • 大型キャラクター:コライダーの半分程度

つまり、キャラクターのコライダーサイズやモデルの目線に合わせて調整するのが正解です。


5. 実用的なコード例

以下は、敵がプレイヤーを見ているかどうかを判定し、NavMeshAgentの挙動を切り替えるサンプルです。

using UnityEngine;
using UnityEngine.AI;

public class EnemyVision : MonoBehaviour
{
    [SerializeField] private LayerMask obstacleMask;
    [SerializeField] private Transform target;
    private NavMeshAgent agent;

    void Awake()
    {
        agent = GetComponent<NavMeshAgent>();
    }

    void Update()
    {
        if (target == null) return;

        // 始点と終点を少し上にずらす
        Vector3 from = transform.position + Vector3.up * 0.2f;  
        Vector3 to   = target.position + Vector3.up * 0.2f;

        if (!Physics.Linecast(from, to, obstacleMask, QueryTriggerInteraction.Ignore))
        {
            // 遮蔽物なし → 視線が通っている
            agent.isStopped = false;
            agent.SetDestination(target.position);
            Debug.DrawLine(from, to, Color.green);
        }
        else
        {
            // 遮蔽物あり
            agent.isStopped = true;
            Debug.DrawLine(from, to, Color.red);
        }
    }
}

ここでは Linecast を使って簡潔に書いています。始点・終点に同じオフセットを加えるのがポイントです。


6. RaycastNonAlloc と Linecast の違い

Unityで「敵とプレイヤーの間に遮蔽物があるか?」を調べるとき、代表的なのが RaycastNonAlloc と Linecast です。

それぞれの違いを整理してみます。

項目Physics.LinecastPhysics.RaycastNonAlloc
書き方Physics.Linecast(start, end, …)Physics.RaycastNonAlloc(start, dir, results, distance, …)
扱う範囲始点~終点の直線そのもの始点+方向+距離で指定
戻り値bool(何かに当たったか)int(当たった数)
結果1つ(最初のヒット)複数ヒットを配列に格納
可読性シンプルで直感的設定項目が多く少し複雑
向いている用途可視線チェックなど単純な「通ってる/遮られてる」判定弾丸やレーザー、複数ヒット情報を活用する処理(壁の裏に何があるかなど)

どちらを選ぶべきか?

  • 視線チェックや単純な当たり判定→ Linecast のほうが簡潔で分かりやすい
  • ヒットしたオブジェクトのリストが欲しい / GC削減を重視→ RaycastNonAlloc のほうが適している

つまり、「敵がプレイヤーを見えているかどうか」だけなら Linecastで十分 です。

一方で「視線の途中に複数の壁があるかどうか」や「最も手前のヒット対象を自分で選びたい」場合には RaycastNonAlloc が有効です。


まとめ

  • Vector3.up * 0.2f は 自己ヒット回避・視線の自然さ・誤検出防止 のために加える。
  • 値は キャラクターの大きさや目線の高さ に合わせて調整するのがベスト。
  • Linecast はシンプルに「通ってる/遮られてる」だけを判定できる。
  • RaycastNonAlloc は複数ヒットや性能最適化に向いている。

Raycastを使った視線チェックで不安定な挙動が出るときは、このオフセットと手法の選択を一度確認してみてください。


訪問数 3 回, 今日の訪問数 3回

C#,Ray,Unity

Posted by hidepon