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

Unity随机平台关卡生成器:销毁实例化Prefab Transform报错求助

问题解决:关卡销毁后出现MissingReferenceException错误

问题背景

开发随机平台关卡生成器,使用预制件生成关卡的功能正常,但玩家死亡时调用DestroyAllLevelParts()销毁旧关卡,再调用CreateLevel()生成新关卡时,触发MissingReferenceException错误,提示已销毁的Transform仍被访问。因计划用ML Agent训练AI,不想重新加载场景,需实现销毁+重置关卡的逻辑。

错误原因

  1. 未清空引用列表:调用DestroyAllLevelParts()销毁对象后,all_LevelParts列表中仍保留着已销毁对象的Transform引用,后续操作可能误访问这些无效引用。
  2. 使用DestroyImmediate不当:DestroyImmediate是同步销毁方法,运行时使用可能导致帧内引用异常,更适合编辑模式下使用。
  3. 残留引用未重置:生成新关卡时,若未彻底清除旧关卡的状态引用,可能引发无效访问。

解决方案

1. 销毁后清空引用列表

销毁所有关卡部件后,立即清空all_LevelParts,避免后续代码访问无效引用。

2. 替换DestroyImmediate为Destroy

运行时使用异步销毁方法Destroy,让Unity在帧末处理销毁逻辑,避免同步销毁导致的引用异常。

3. 生成新关卡前重置状态

在CreateLevel方法开头重置起始位置,并添加双重保险确保关卡部件列表为空。

修改后的完整代码

public class LevelGenerator : MonoBehaviour
{
    [SerializeField] private Transform levelPart_Start;
    [SerializeField] private List<Transform> levelPartList;
    [SerializeField] private Transform levelPart_Finish;
    [SerializeField] private int platforms;

    private List<Transform> all_LevelParts = new List<Transform>();
    private Vector3 lastEndPosition;

    public void CreateLevel()
    {
        // 重置起始位置,确保不受旧关卡影响
        lastEndPosition = levelPart_Start.Find("EndPosition").position;
        
        // 双重保险:确保列表为空(防止之前销毁逻辑未执行完全)
        if(all_LevelParts.Count > 0)
        {
            DestroyAllLevelParts();
        }
        
        for(int i = 0; i < platforms; i++)
        {
            SpawnLevelPart();
        }
        SpawnLevelPart(levelPart_Finish, lastEndPosition);
    }
 
    public void SpawnLevelPart()
    {
        Transform chosenLevelPart = levelPartList[Random.Range(0, levelPartList.Count)];
        Transform lastLevelPartTransform = SpawnLevelPart(chosenLevelPart, lastEndPosition);
        lastEndPosition = lastLevelPartTransform.Find("EndPosition").position;
    }

    public Transform SpawnLevelPart(Transform levelPart, Vector3 spawnPosition)
    {
        Transform levelPartTransform = Instantiate(levelPart, spawnPosition, Quaternion.identity);
        all_LevelParts.Add(levelPartTransform);
        return levelPartTransform;
    }

    public void DestroyAllLevelParts() 
    {
        foreach (Transform currentLevel in all_LevelParts)
        {
            // 运行时使用Destroy替代DestroyImmediate
            Destroy(currentLevel.gameObject);
        }
        // 清空列表,移除无效引用
        all_LevelParts.Clear();
    }
}

额外注意事项

  • 调用顺序必须是:先执行DestroyAllLevelParts(),再调用CreateLevel()。Unity的异步销毁逻辑不会影响新对象的生成,无需额外等待帧。
  • 确保玩家死亡逻辑所在的脚本,调用LevelGenerator方法时,LevelGenerator对象未被销毁。

内容的提问来源于stack exchange,提问作者Hai Dinh

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 16:24:19