Unity2D均匀分布预制体遇空引用异常,求解决方案
Unity 2D俯视角游戏:随机生成树木/岩石的问题修复与均匀分布方案
问题描述
制作2D俯视角游戏时,需要在地图(范围-70到70)内随机生成树木、岩石预制体,要求每个新生成的物体与最近已生成物体的距离至少为10。当前代码运行时第19行触发NullReferenceException,需要修复代码或获取其他均匀分布实现方案。
原始代码
void SpawnNature() { for (int i = 0; i < 100; i++) { Pos = new Vector3(Random.Range(-70, 70), Random.Range(-70, 70), 0); type = Random.Range(1, 3); distance = 100; GameObject nearestObject = null; float shortestDistance = float.MaxValue; foreach(GameObject Object in SpawnedObjects) { float dist = Vector2.Distance(Object.transform.position, Pos); if (dist < shortestDistance) { shortestDistance = dist; nearestObject = Object; } } distance = Vector2.Distance(nearestObject.transform.position, Pos); if (distance >= 10) { if (type == 1) { Instantiate(rock, Pos, Quaternion.identity); } if (type == 2) { Instantiate(tree, Pos, Quaternion.identity); } } } }
错误原因
第一次循环时,SpawnedObjects列表是空的,foreach循环不会执行,导致nearestObject始终为null,此时访问nearestObject.transform必然触发空引用异常。另外,原始代码没有将生成的物体添加到SpawnedObjects列表,后续循环无法检测已生成的物体,距离检查完全失效。
修复后的代码
// 先在类开头初始化列表,确保rock、tree预制体已在Inspector中赋值 public List<GameObject> SpawnedObjects = new List<GameObject>(); public GameObject rock; public GameObject tree; void SpawnNature() { for (int i = 0; i < 100; i++) { Vector3 spawnPos = new Vector3(Random.Range(-70, 70), Random.Range(-70, 70), 0); int objectType = Random.Range(1, 3); bool canSpawn = true; // 只有已有生成物体时,才执行距离检查 if (SpawnedObjects.Count > 0) { float shortestDistance = float.MaxValue; foreach(GameObject spawnedObj in SpawnedObjects) { float dist = Vector2.Distance(spawnedObj.transform.position, spawnPos); if (dist < shortestDistance) { shortestDistance = dist; } } // 最近距离小于10则放弃当前位置 if (shortestDistance < 10) { canSpawn = false; } } if (canSpawn) { GameObject newObj = null; if (objectType == 1) { newObj = Instantiate(rock, spawnPos, Quaternion.identity); } else if (objectType == 2) { newObj = Instantiate(tree, spawnPos, Quaternion.identity); } // 将生成的物体加入列表,供后续循环检测 if (newObj != null) { SpawnedObjects.Add(newObj); } } else { // 当前位置不符合要求,重试一次 i--; } } }
修复点说明
- 新增
SpawnedObjects.Count > 0判断,彻底避免空引用 - 生成物体后将实例添加到列表,确保后续距离检查有效
- 位置不符合要求时通过
i--重试,保证最终生成足够数量的物体 - 优化变量名(如
Pos改为spawnPos),提升代码可读性
其他均匀分布方案:泊松圆盘采样
如果需要更自然的均匀分布(避免纯随机可能出现的局部密集/稀疏),可以用泊松圆盘采样算法,核心是保证每个点与其他点的距离不小于设定值,同时分布更贴近真实场景。
简单实现思路:
- 将地图划分成边长为
最小距离/√2的网格,每个网格最多放一个物体,减少距离检测次数 - 随机生成第一个点,加入活跃列表和已生成点列表
- 从活跃列表随机选一个点,在其周围(10~20的环形区域)生成多个候选点
- 检查候选点是否在地图范围内,且与所有已生成点距离≥10,对应网格为空
- 符合条件的候选点加入活跃列表和已生成点列表;无符合条件的点则将当前点从活跃列表移除
- 重复步骤3-5,直到活跃列表为空或生成足够数量的点
这种方法生成的物体分布更均匀自然,适合场景生成需求。
内容的提问来源于stack exchange,提问作者Ted Hutter
相关产品推荐
相关产品推荐

