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.Linecast | Physics.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を使った視線チェックで不安定な挙動が出るときは、このオフセットと手法の選択を一度確認してみてください。
ディスカッション
コメント一覧
まだ、コメントがありません