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

Unity运行时动态增减小队及成员时newpositions数组越界如何解决

动态阵型系统修复方案

核心问题说明

现有代码存在两个核心故障点:

  1. 动态增减成员/小队时,仅更新了squadMembers列表,未同步更新配套的endpositions列表,导致索引越界
  2. 缺少数量减少时的对象销毁、列表同步移除逻辑

修复步骤

1. 新增必要的私有字段

在Formations类中新增以下变量,用于缓存旧值、存储依赖引用:

private int oldNumberOfSquadMembers;
private int oldNumberOfSquads;
public GameObject squadMemberPrefab; // Inspector面板拖入成员预制体
private GameObject squadsParent;

2. 初始化缓存值

修改Start方法,初始化旧值缓存和父对象引用:

private void Start()
{
    squadsParent = GameObject.Find("Squads");
    oldNumberOfSquadMembers = numberOfSquadMembers;
    oldNumberOfSquads = numberOfSquads;
    InitFormations();
}

3. 完善动态成员增减逻辑

替换你原有写在Update里的成员校验逻辑,新增同步更新endpositions、销毁多余对象的处理:

// 放在Update的ready判断分支内
if(oldNumberOfSquadMembers != numberOfSquadMembers)
{
    int diff = numberOfSquadMembers - oldNumberOfSquadMembers;
    if (diff > 0)
    {
        // 新增成员
        for (int i = 0; i < diff; i++)
        {
            var go = Instantiate(squadMemberPrefab);
            go.name = "Member " + (squadMembers.Count + i);
            go.tag = "Squad Member";
            // 默认挂到第一个小队下,可按需修改分配逻辑
            go.transform.parent = GameObject.FindGameObjectsWithTag("Squad")[0].transform;
            squadMembers.Add(go);
            // 同步补全endpositions的偏移值
            Vector3 center = total / squadMembers.Count;
            Vector3 startVec = go.transform.position - center;
            endpositions.Add(startVec);
        }
    }
    else
    {
        // 删除多余成员
        int removeCount = -diff;
        for (int i = 0; i < removeCount; i++)
        {
            int lastIndex = squadMembers.Count - 1;
            Destroy(squadMembers[lastIndex]);
            squadMembers.RemoveAt(lastIndex);
            endpositions.RemoveAt(lastIndex);
        }
    }
    oldNumberOfSquadMembers = numberOfSquadMembers;
    // 同步更新步长、速度数组
    randomSpeeds = RandomSpeeds(randSpeedMin, randSpeedMax, squadMembers.Count);
    step = new float[squadMembers.Count];
    ChangeFormation();
}

4. 新增动态小队增减逻辑

在Update中补充小队数量变化的处理逻辑:

// 放在Update的ready判断分支内
if(oldNumberOfSquads != numberOfSquads)
{
    int diff = numberOfSquads - oldNumberOfSquads;
    var existingSquads = GameObject.FindGameObjectsWithTag("Squad").OrderBy(s=>s.name).ToList();
    if (diff > 0)
    {
        // 新增小队
        for (int i = 0; i < diff; i++)
        {
            GameObject newSquad = new GameObject();
            newSquad.name = "Squad " + (existingSquads.Count + i);
            newSquad.tag = "Squad";
            newSquad.transform.parent = squadsParent.transform;
            // 生成小队对应成员
            for (int x = 0; x < numberOfSquadMembers; x++)
            {
                var go = Instantiate(squadMemberPrefab);
                go.name = "Member " + x;
                go.tag = "Squad Member";
                go.transform.parent = newSquad.transform;
                // 按原有逻辑分配小队颜色
                switch ((existingSquads.Count + i) % 6)
                {
                    case 0: ColorSquad(go, Color.green); break;
                    case 1: ColorSquad(go, Color.red); break;
                    case 2: ColorSquad(go, Color.blue); break;
                    case 3: ColorSquad(go, Color.yellow); break;
                    case 4: ColorSquad(go, Color.cyan); break;
                    case 5: ColorSquad(go, Color.magenta); break;
                }
                squadMembers.Add(go);
                Vector3 center = total / squadMembers.Count;
                Vector3 startVec = go.transform.position - center;
                endpositions.Add(startVec);
            }
        }
    }
    else
    {
        // 删除多余小队
        int removeCount = -diff;
        for (int i = 0; i < removeCount; i++)
        {
            int lastSquadIndex = existingSquads.Count - 1 - i;
            var squadToRemove = existingSquads[lastSquadIndex];
            // 先移除成员列表对应记录
            foreach (Transform member in squadToRemove.transform)
            {
                int memberIndex = squadMembers.FindIndex(m=>m == member.gameObject);
                if (memberIndex >= 0)
                {
                    squadMembers.RemoveAt(memberIndex);
                    endpositions.RemoveAt(memberIndex);
                }
                Destroy(member.gameObject);
            }
            Destroy(squadToRemove);
        }
    }
    oldNumberOfSquads = numberOfSquads;
    randomSpeeds = RandomSpeeds(randSpeedMin, randSpeedMax, squadMembers.Count);
    step = new float[squadMembers.Count];
    ChangeFormation();
}

注:如果ColorSquad方法定义在SquadsGenerator类中,需要将其移动到Formations类,或者改为公共方法跨类调用


越界问题说明

原FormationSquare中每次新建newpositions的逻辑是完全正确的,无需修改。之前触发索引越界的根本原因是新增成员时仅更新了squadMembers列表,未同步更新endpositions列表长度,导致循环访问endpositions[i]时索引超出范围。保证endpositions和squadMembers长度完全一致后,就不会再出现越界问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 23:54:03