Unity OnBecameVisible问题:穿墙检测及场景视图误触发求助
解决方案
问题根源
Renderer.isVisible和OnBecameVisible/OnBecameInvisible会响应所有相机,包括Unity编辑器的场景视图相机,测试时自然会误触发。- 这俩API只判断物体是否在相机视锥范围内,不检测遮挡物,所以墙后的敌人也会被判定为可见。
修正方案
要实现需求,得同时做到两点:
- 只针对玩家主相机判断可见性,排除场景视图的编辑器相机。
- 加视线遮挡检测,确保敌人和玩家之间没障碍物,且真在玩家相机视野里。
修改后的代码
using UnityEngine; using UnityEngine.AI; public class EnemyChase : MonoBehaviour { public NavMeshAgent enemy; public Transform player; // 直接拖入玩家相机,比Camera.main更靠谱 public Camera playerCamera; private Renderer m_Renderer; private void Start() { m_Renderer = GetComponent<Renderer>(); // 没指定相机的话自动取主相机 if (playerCamera == null) { playerCamera = Camera.main; } } private void Update() { // 只在玩家按空格键时检测 if (Input.GetKey(KeyCode.Space)) { // 1. 先判断敌人是否在玩家相机的画面范围内,且在相机前方 Vector3 viewportPos = playerCamera.WorldToViewportPoint(transform.position); bool isInCameraView = viewportPos.x >= 0 && viewportPos.x <= 1 && viewportPos.y >= 0 && viewportPos.y <= 1 && viewportPos.z > 0; // 2. 再检测敌人是否没被遮挡,真的能被玩家看到 bool isVisibleToPlayer = false; if (isInCameraView) { RaycastHit hit; Vector3 direction = transform.position - playerCamera.transform.position; // 从相机射射线到敌人,看是不是直接命中敌人 if (Physics.Raycast(playerCamera.transform.position, direction.normalized, out hit, direction.magnitude)) { isVisibleToPlayer = hit.transform == transform; } } // 满足条件就追玩家,不然可以停住 if (isVisibleToPlayer) { Debug.Log("敌人可见,开始追逐"); enemy.SetDestination(player.position); } else { Debug.Log("敌人不可见,停止追逐"); enemy.SetDestination(transform.position); } } } }
关键细节说明
- 玩家相机指定:直接拖入玩家相机组件,避免
Camera.main在场景多相机时出错。 - 视口范围判断:用
WorldToViewportPoint把世界坐标转成0-1的视口坐标,确保敌人在相机画面内,z>0保证在相机前方。 - 射线遮挡检测:从相机射射线到敌人,只有射线直接命中敌人时,才判定没遮挡。还可以给射线加层级过滤,比如只检测墙壁层,忽略敌人和玩家,让检测更精准。
额外优化建议
- 如果敌人是多部件的模型,可以用
Physics.SphereCast代替射线,检测范围更大,避免射线偏移导致误判。 - 可以加个延迟检测,比如每0.1秒检测一次,减少Update里的性能消耗。
内容的提问来源于stack exchange,提问作者user21241519
相关产品推荐
相关产品推荐

