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

为何已销毁的GameObject仍被FindGameObjectByTag()重复找到?

问题分析与解决方案

核心问题

  1. 赋值而非条件判断:if(saveNum = true)是赋值操作,不是逻辑判断,这会导致代码始终进入第一个分支,无法切换查找Tile/Block标签的逻辑。
  2. 单次标签查找的局限性:GameObject.FindGameObjectWithTag只会返回场景中第一个匹配标签的对象,即使销毁了第一个,循环内重复调用也无法保证正确获取下一个目标,且原逻辑中saveNum仅在循环结束后取反,两次循环都会查找同标签对象。
  3. 索引计算错误:存储位置需要3个元素(x/y/z),但原代码中j +=2,会导致后续位置数据覆盖或数组越界;存储旋转需要4个元素(x/y/z/w),但k +=3,同样会造成旋转数据混乱。
  4. 低效的对象查找方式:循环内重复调用查找方法性能差,且容易出现对象引用错误。

修正后的代码

public void SaveLevel()
{
    // 一次性获取所有需要处理的Tile和Block对象
    List<GameObject> allTargetTiles = new List<GameObject>(GameObject.FindGameObjectsWithTag("Tile"));
    allTargetTiles.AddRange(GameObject.FindGameObjectsWithTag("Block"));

    // 重置索引计数器
    int posIndex = 0;
    int rotIndex = 0;

    for (int i = 0; i < allTargetTiles.Count; i++)
    {
        GameObject currentTile = allTargetTiles[i];
        if (currentTile == null) continue;

        // 根据名称标记Tile类型
        if (currentTile.name.Contains("Hall"))
        {
            intTileList_forFile[i] = 0;
        }
        else if (currentTile.name.Contains("Corner"))
        {
            intTileList_forFile[i] = 1;
        }
        else if (currentTile.name.Contains("Edge"))
        {
            intTileList_forFile[i] = 2;
        }
        else if (currentTile.name.Contains("End"))
        {
            intTileList_forFile[i] = 3;
        }
        else if (currentTile.name.Contains("Middle"))
        {
            intTileList_forFile[i] = 4;
        }

        // 存储位置(x/y/z,每次占用3个索引位)
        intTilePlacement_forFile[posIndex] = currentTile.transform.position.x;
        intTilePlacement_forFile[posIndex + 1] = currentTile.transform.position.y;
        intTilePlacement_forFile[posIndex + 2] = currentTile.transform.position.z;
        posIndex += 3;

        // 存储旋转(x/y/z/w,每次占用4个索引位)
        intTileRotation_forFile[rotIndex] = currentTile.transform.rotation.x;
        intTileRotation_forFile[rotIndex + 1] = currentTile.transform.rotation.y;
        intTileRotation_forFile[rotIndex + 2] = currentTile.transform.rotation.z;
        intTileRotation_forFile[rotIndex + 3] = currentTile.transform.rotation.w;
        rotIndex += 4;

        // 销毁当前Tile
        Destroy(currentTile);
    }

    saveNum = !saveNum;
    Debug.Log("Complete");
}

关键改动说明

  • 批量获取对象:用FindGameObjectsWithTag(复数形式)一次性获取所有匹配标签的对象,避免循环内重复查找,确保遍历所有需要处理的Tile/Block。
  • 修复索引逻辑:位置存储后索引加3,旋转存储后索引加4,保证数组索引不越界、数据不覆盖。
  • 简化对象引用:直接用currentTile引用当前处理对象,避免依赖单元素列表TileList[0]的不稳定引用。
  • 修正条件逻辑:移除原代码中错误的赋值操作,改为批量处理所有目标对象(若需区分Tile和Block,可在遍历中添加标签判断)。

额外优化建议

  • 替换名称判断逻辑:给不同类型Tile添加枚举组件、专属标签或Layer,比判断对象名称更可靠且性能更好。
  • 改用List替代数组:intTileList_forFile、intTilePlacement_forFile等建议用List<float>/List<int>,避免固定数组长度导致的越界问题。
  • 优化销毁逻辑:若Tile数量较多,可考虑异步销毁或延迟销毁,避免卡顿。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.24 19:36:02