You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

技术求助:实现无限生成障碍物与边界碰撞时的统一删除逻辑

解决Unity中障碍物组碰撞边界后统一删除的问题

嘿,我太懂你卡了两天的感受——处理这种批量生成的组合物体的销毁逻辑,确实容易在“联动删除”这里卡壳。结合你给出的代码片段,我给你梳理几个靠谱的实现方案,都是Unity里常用的思路:

核心思路:给障碍物组做“标记”

因为你的障碍物是5个立方体组成的整体,关键是要让程序知道“这5个立方体是一伙的”,这样只要其中一个碰到边界,就能把整个组都删掉。下面是两种具体实现方式:

方案1:用父物体统一管理障碍物组

这是最直观的方式,生成时把5个立方体放到同一个空父物体下,销毁父物体就会自动删掉所有子立方体,还方便管理:

首先修改你的生成协程:

public List<GameObject> spawning = new List<GameObject>();
public Vector3[] positions = new Vector3[5];
public GameObject barrier;
public GameObject boundary;
private int spawnInterval = 2; // 自定义生成间隔,比如2秒

void Start()
{
    StartCoroutine(SpawnBarrier());
}

IEnumerator SpawnBarrier()
{
    while (true)
    {
        // 创建空父物体作为障碍物组的容器
        GameObject barrierGroup = new GameObject($"BarrierGroup_{Time.time}");
        
        for (int i = 0; i < 5; i++)
        {
            GameObject newBarrier = Instantiate(barrier, positions[i], Quaternion.identity);
            // 把立方体设为父物体的子对象
            newBarrier.transform.SetParent(barrierGroup.transform);
            spawning.Add(newBarrier);
        }
        
        yield return new WaitForSeconds(spawnInterval);
    }
}

然后给你的boundary物体加一个脚本,用碰撞触发器来检测并删除整个组:

// 挂在边界物体上的脚本
public class BoundaryCleanup : MonoBehaviour
{
    // 假设你的障碍物立方体有"BarrierCube"标签,记得给预制体加上
    public string barrierTag = "BarrierCube";
    // 引用你的spawning列表,或者直接通过父物体查找
    public List<GameObject> spawningList;

    private void OnTriggerEnter(Collider other)
    {
        // 检测碰撞的是不是障碍物立方体
        if (other.CompareTag(barrierTag))
        {
            // 获取整个障碍物组的父物体
            GameObject barrierGroup = other.transform.parent.gameObject;
            
            // 从spawning列表中移除所有子立方体
            foreach (Transform child in barrierGroup.transform)
            {
                if (spawningList.Contains(child.gameObject))
                {
                    spawningList.Remove(child.gameObject);
                }
            }
            
            // 销毁整个障碍物组(子物体会自动被销毁)
            Destroy(barrierGroup);
        }
    }
}

方案2:用组ID标记同一组障碍物

如果不想用父物体,可以给每个立方体加一个组ID脚本,让程序识别哪些立方体属于同一组:

首先创建一个BarrierCube脚本挂在障碍物预制体上:

public class BarrierCube : MonoBehaviour
{
    public int groupId; // 同一组的立方体groupId相同
}

然后修改生成协程,给同一组的5个立方体设置相同的groupId:

private int currentGroupId = 0;

IEnumerator SpawnBarrier()
{
    while (true)
    {
        currentGroupId++; // 每次生成新组,ID自增
        for (int i = 0; i < 5; i++)
        {
            GameObject newBarrier = Instantiate(barrier, positions[i], Quaternion.identity);
            BarrierCube cubeScript = newBarrier.GetComponent<BarrierCube>();
            if (cubeScript != null)
            {
                cubeScript.groupId = currentGroupId;
            }
            spawning.Add(newBarrier);
        }
        
        yield return new WaitForSeconds(spawnInterval);
    }
}

同样在边界的脚本里处理碰撞,找到同组的所有立方体删除:

public class BoundaryCleanup : MonoBehaviour
{
    public List<GameObject> spawningList;

    private void OnTriggerEnter(Collider other)
    {
        BarrierCube hitCube = other.GetComponent<BarrierCube>();
        if (hitCube == null) return;

        // 找到所有同groupId的障碍物
        List<GameObject> groupToDelete = spawningList.Where(cube => 
            cube.GetComponent<BarrierCube>()?.groupId == hitCube.groupId).ToList();

        // 从列表移除并销毁每个立方体
        foreach (GameObject cube in groupToDelete)
        {
            spawningList.Remove(cube);
            Destroy(cube);
        }
    }
}

注意事项

  • 确保你的障碍物预制体有Collider,如果用触发器的话要勾选Is Trigger;同时如果需要物理碰撞触发,还要给障碍物加Rigidbody(可以勾选Kinematic避免物理影响)
  • 不要在Update的foreach循环里直接修改spawning列表(会触发遍历修改错误),一定要先创建列表副本再处理删除
  • 如果不想用碰撞检测,也可以在Update里判断物体位置是否超出边界,逻辑和上面类似,只是把碰撞触发换成位置判断即可

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

火山引擎 最新活动