Unity C# 如何让NPC鱼不在玩家身上或过近位置生成
问题根因
你的NPC鱼生成在玩家身上的核心问题是Start方法执行顺序写反:
- 你在Start中先调用了
Spawn()方法,之后才给minDistance赋值为5f - C#中float值类型默认值为0,
Spawn()运行时minDistance实际等于0,判断条件两点距离 < 0永远不可能成立,用于过滤过近生成点的while循环完全不会执行,生成点完全随机,自然会刷在玩家位置。
代码另外还有3个问题:
quaternion.identity拼写错误,Unity四元数类名首字母需大写,正确写法为Quaternion.identity,会直接导致编译不通过- 每次循环都调用
GameObject.FindGameObjectWithTag("Player")查找玩家,存在不必要的性能开销,玩家未及时加载时还会触发空引用报错 - while循环没有设置重试上限,若玩家位置覆盖了绝大多数生成区域,循环会无限运行导致游戏卡死
- 距离计算混用Vector2和Vector3类型,写法不严谨
修正后完整代码
public class Spawner : MonoBehaviour { [Header("生成配置")] public GameObject[] itemsToPickFrom; public int numberToSpawn; public float minDistance = 5f; // 直接在字段处初始化,避免执行顺序错误 private Transform _playerTrans; // 生成范围常量,方便统一调整 private const float RangeMinX = -10f; private const float RangeMaxX = 9f; private const float RangeMinY = -4f; private const float RangeMaxY = 4f; private const int MaxRetry = 50; // 最大重试次数,防止死循环 void Start() { // 启动时一次性缓存玩家位置引用,不用每次生成都查找 _playerTrans = GameObject.FindGameObjectWithTag("Player").transform; Spawn(); } void Spawn() { for (int i = 0; i < numberToSpawn; i++) { int randomFishIndex = Random.Range(0, itemsToPickFrom.Length); Vector3 spawnPos = Vector3.zero; bool findValidPos = false; int retryCount = 0; while (retryCount < MaxRetry) { float randX = Random.Range(RangeMinX, RangeMaxX); float randY = Random.Range(RangeMinY, RangeMaxY); spawnPos = new Vector3(randX, randY, 0); // 统一用Vector3计算距离,避免隐式类型转换 if (Vector3.Distance(_playerTrans.position, spawnPos) >= minDistance) { findValidPos = true; break; } retryCount++; } // 找到合法位置才生成鱼,重试超限则跳过该次生成,避免卡死 if (findValidPos) { Instantiate(itemsToPickFrom[randomFishIndex], spawnPos, Quaternion.identity); } } } }
优化说明
- 把
minDistance设为可在Inspector面板直接调整的公开字段,后续改距离不用修改代码 - 启动时一次性缓存玩家Transform组件,减少重复查找的性能消耗
- 增加最大重试次数兜底,彻底避免while死循环导致的游戏无响应
- 统一距离计算的向量类型,消除隐式转换的不稳定问题
- 生成范围抽成常量,后续调整地图边界不用逐行找数值修改
内容的提问来源于stack exchange,提问作者Nat
相关产品推荐
相关产品推荐

