You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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),提升代码可读性

其他均匀分布方案:泊松圆盘采样

如果需要更自然的均匀分布(避免纯随机可能出现的局部密集/稀疏),可以用泊松圆盘采样算法,核心是保证每个点与其他点的距离不小于设定值,同时分布更贴近真实场景。

简单实现思路:

  1. 将地图划分成边长为最小距离/√2的网格,每个网格最多放一个物体,减少距离检测次数
  2. 随机生成第一个点,加入活跃列表和已生成点列表
  3. 从活跃列表随机选一个点,在其周围(10~20的环形区域)生成多个候选点
  4. 检查候选点是否在地图范围内,且与所有已生成点距离≥10,对应网格为空
  5. 符合条件的候选点加入活跃列表和已生成点列表;无符合条件的点则将当前点从活跃列表移除
  6. 重复步骤3-5,直到活跃列表为空或生成足够数量的点

这种方法生成的物体分布更均匀自然,适合场景生成需求。

内容的提问来源于stack exchange,提问作者Ted Hutter

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 07:59:52