在NavMesh上生成相机视野外敌人的代码无效问题排查
问题排查与修复方案
你的代码没效果主要有几个核心问题,逐一解决:
1. NavMesh检测方式错误
你用的NavMesh.Raycast是用来检测两点之间的NavMesh路径是否存在障碍物,不是用来验证某个点是否在NavMesh上。要找有效NavMesh位置,应该用NavMesh.SamplePosition,它能返回离目标点最近的有效NavMesh采样点。
2. 生成位置与检测位置不一致
原代码里NavMesh.Raycast的终点和Instantiate的位置是两次独立的随机计算,就算Raycast命中了,生成的位置也可能完全不在NavMesh上。必须用同一个随机位置来检测和生成。
3. 敌人数量没有递减逻辑
生成敌人后enemiesAmount只会增加,但敌人被销毁时你没处理这个数值的递减,导致第一波生成后enemiesAmount永远不为0,再也不会触发下一波生成。
修复后的完整代码
using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.AI; public class EnemySpawner : MonoBehaviour { private int waveNumber = 0; public int enemiesAmount = 0; public GameObject EnemyPrefab; // 重命名更清晰 public Camera cam; public float spawnOffsetFromCamera = 10f; // 相机视野外的偏移距离,可调整 public float spawnRange = 5f; // 生成点的随机范围,可调整 void Start () { if (cam == null) cam = Camera.main; enemiesAmount = 0; } void Update () { if (enemiesAmount == 0) { waveNumber++; StartCoroutine(SpawnWave()); // 用协程避免一帧生成太多敌人,可选 } } IEnumerator SpawnWave() { for (int i = 0; i < waveNumber; i++) { // 计算相机视野外的随机目标点 Vector3 targetSpawnPos = GetOffCameraSpawnPos(); NavMeshHit hit; // 检测目标点附近的有效NavMesh位置 if(NavMesh.SamplePosition(targetSpawnPos, out hit, spawnRange, NavMesh.AllAreas)) { Debug.Log("生成敌人在NavMesh上:" + hit.position); GameObject enemy = Instantiate(EnemyPrefab, hit.position, Quaternion.identity); enemiesAmount++; // 给敌人添加销毁时的回调 EnemyHealth enemyHealth = enemy.GetComponent<EnemyHealth>(); if(enemyHealth != null) { enemyHealth.OnEnemyDeath += () => enemiesAmount--; } else { // 如果没有EnemyHealth脚本,直接给敌人加销毁监听 Destroy(enemy, 10f); // 示例:10秒后销毁,实际替换成你的敌人死亡逻辑 StartCoroutine(DecrementEnemyCountAfterDestroy(enemy)); } } else { Debug.LogWarning("找不到有效NavMesh位置,跳过本次生成"); } yield return new WaitForSeconds(0.5f); // 每0.5秒生成一个,避免卡顿 } } Vector3 GetOffCameraSpawnPos() { // 获取相机视野的边界 float camHeight = cam.orthographicSize; float camWidth = cam.orthographicSize * cam.aspect; // 随机选择相机的四个方向外生成(这里选上方,你可以扩展其他方向) float randomX = Random.Range(cam.transform.position.x - camWidth - spawnRange, cam.transform.position.x + camWidth + spawnRange); // 生成在相机视野上方的外侧 float spawnZ = cam.transform.position.z + camHeight + spawnOffsetFromCamera + Random.Range(0, spawnRange); return new Vector3(randomX, cam.transform.position.y, spawnZ); } IEnumerator DecrementEnemyCountAfterDestroy(GameObject enemy) { yield return new WaitUntil(() => enemy == null); enemiesAmount--; } }
额外注意事项
- 确保你的场景已经正确烘焙了NavMesh(Window > AI > NavMesh),并且敌人的Layer不在NavMesh的排除列表里。
- 如果你的敌人有自己的死亡脚本(比如EnemyHealth),要在死亡时触发
OnEnemyDeath事件,或者直接在销毁时调用enemiesAmount--。 - 调整
spawnOffsetFromCamera和spawnRange参数,适配你的游戏场景大小。
内容的提问来源于stack exchange,提问作者Rodrigo Aben-Athar
相关产品推荐
相关产品推荐

