Unity运行时动态增减小队及成员时newpositions数组越界如何解决
动态阵型系统修复方案
核心问题说明
现有代码存在两个核心故障点:
- 动态增减成员/小队时,仅更新了
squadMembers列表,未同步更新配套的endpositions列表,导致索引越界 - 缺少数量减少时的对象销毁、列表同步移除逻辑
修复步骤
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
相关产品推荐
相关产品推荐

