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

Unity中Destroy方法无法销毁GameObject实例问题求助

瓦片销毁失败问题排查

问题描述

我正在编写一个随玩家移动,在其周围动态生成和移除瓦片的脚本。后续计划用噪声算法为每个坐标匹配瓦片类型,确保玩家返回旧区域时样式一致,因此无法使用静态图像方案。

当瓦片块超出渲染范围时,我对每个grassTile GameObject实例调用Destroy()方法,但这些瓦片并未从屏幕上消失。我查阅过同类问题,确认没有误销毁GameObject以外的对象,尝试DestroyImmediate()也无效。

相关代码

using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using Unity.Collections;
using Unity.VisualScripting;
using UnityEditor.SearchService;
using UnityEngine;

public class TileManager : MonoBehaviour
{
    // Objects & Variables
    public int chunkRadius = 1;
    public int renderRadius = 1;

    public GameObject grassTile;
    public GameObject background;
    public GameObject player;
    
    private Vector2 playerPosition => player.transform.position;
    private Dictionary<Vector2, GameObject[]> chunks = new Dictionary<Vector2, GameObject[]>();
    private int chunkWidth;

    // Unity Functions

    void Awake() {
        chunkWidth = 1 + 2 * chunkRadius;
        DrawChunk(GetChunkPlayerIsIn());
    }

    void Update() {
        foreach(Vector2 chunk in GetChunksToDraw()){
            DrawChunk(chunk);
        }

        Debug.Log($"Destroying {GetChunksToDestroy().Count} chunks");
        foreach(Vector2 chunk in GetChunksToDestroy()){
            DestroyChunk(chunk);
        }
    }

    // Private Functions

    private List<Vector2> GetChunksToDraw(){
        List<Vector2> chunksToDraw = new List<Vector2>();
        Vector2 playerChunk = GetChunkPlayerIsIn();
        int minX = (int)playerChunk.x - renderRadius * chunkWidth;
        int maxX = (int)playerChunk.x + renderRadius * chunkWidth;
        int minY = (int)playerChunk.y - renderRadius * chunkWidth;
        int maxY = (int)playerChunk.y + renderRadius * chunkWidth;

        for(int x = minX; x <= maxX; x += chunkWidth){
            for (int y = minY; y <= maxY; y += chunkWidth){
                Vector2 center = new Vector2(x, y);
                if(!chunks.ContainsKey(center)){
                    chunksToDraw.Add(center);
                }
            }
        }

        return chunksToDraw;
    }

    private List<Vector2> GetChunksToDestroy(){
        List<Vector2> chunksToDestroy = new List<Vector2>();
        foreach(Vector2 chunk in chunks.Keys){
            float distance = Mathf.Abs((chunk - playerPosition).magnitude);
            if(distance > chunkWidth){
                Debug.Log($"Destroying chunk {chunk} that is {distance} away");
                chunksToDestroy.Add(chunk);
            }
        }

        return chunksToDestroy;
    }

    private Vector2 GetChunkPlayerIsIn(){
        float nearestX = Mathf.Abs(playerPosition.x) + chunkRadius / 2f;
        nearestX -= nearestX % chunkRadius;
        nearestX *= playerPosition.x > 0 ? 1 : -1;

        float nearestY = Mathf.Abs(playerPosition.y) + chunkRadius / 2f;
        nearestY -= nearestY % chunkRadius;
        nearestY *= playerPosition.y > 0 ? 1 : -1;

        return new Vector2(nearestX, nearestY);
    }

    private void DrawChunk(Vector2 center) {
        int minX = Mathf.FloorToInt(center.x) - chunkRadius;
        int maxX = Mathf.FloorToInt(center.x) + chunkRadius;
        int minY = Mathf.FloorToInt(center.y) - chunkRadius;
        int maxY = Mathf.FloorToInt(center.y) + chunkRadius;

        GameObject[] tiles = new GameObject[(int)Mathf.Pow(1 + 2 * chunkRadius, 2)];
        for(int x = minX; x <= maxX; x++){
            for(int y = minY; y <= maxY; y++){
                GameObject tile = Instantiate(grassTile, background.transform);
                tile.transform.position = new Vector2(x, y);
                tiles.Append(tile);
            }
        }

        chunks.Add(center, tiles);
    }

    private void DestroyChunk(Vector2 chunk) {
        for(int i = 0; i < chunks[chunk].Count(); i++){
            Destroy(chunks[chunk][i]);
        }

        chunks.Remove(chunk);
    }
}

调试更新

感谢各位评论!提问后我做了更多调试,发现grassTile预制体实例添加到数组后变为null。我编写了极简代码复现该问题:

// Objects & Variables
public static TerrainManager instance;

public GameObject grassTilePrefab;
private GameObject[] grassTiles = new GameObject[1];
private int lifeTime = 100;

// Unity Functions

void Start(){
    if (instance == null) instance = this;
    else Destroy(gameObject);
    
    grassTiles.Append(Instantiate(grassTilePrefab));
}

void Update(){
    --lifeTime;
    if(lifeTime <= 0){
        Destroy(grassTiles[0]);
    }
}

运行这段代码时,grassTilePrefab会被实例化,但永远不会消失,即使取消单例模式也无效。

而以下代码可以正确销毁grassTile游戏对象:

// Objects & Variables
public static TerrainManager instance;

public GameObject grassTilePrefab;
private GameObject grassTile;
private int lifeTime = 100;

// Unity Functions

void Start(){
    if (instance == null) instance = this;
    else Destroy(gameObject);
    
    grassTile = Instantiate(grassTilePrefab);
}

void Update(){
    --lifeTime;
    if(lifeTime <= 0){
        Destroy(grassTile);
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 13:08:12