游戏队列系统Bug求助:前端角色销毁后队列无响应及生成异常
队列系统Bug分析与修复方案
核心问题排查
1. 初始化代码的语法/逻辑错误
原初始化代码中PreviousPerson的赋值存在语法错误,三元运算符不完整,会导致PreviousPerson未正确初始化:
APeople* PreviousPerson = (Peoples.Num() - 2)? Peoples[Peoples.Num() - 2];
这行代码缺少三元运算符的后半部分(: 分支),正确写法应该是判断数组元素数量是否足够,否则赋值为nullptr:
APeople* PreviousPerson = (Peoples.Num() >= 2) ? Peoples[Peoples.Num() - 2] : nullptr;
错误的赋值逻辑会导致后续if (PreviousPerson && ...)判断失效,队列角色的跟随关系初始化异常。
2. 前端角色销毁后的空指针访问与逻辑错误
当前端角色被销毁后,遍历队列时直接访问CurrentPerson->PersonToFollow->LastLocation会触发空指针异常(因为被销毁角色的指针已无效),导致代码执行中断,队列无法移动。同时,未更新后续角色的PersonToFollow关系——原第二个角色的跟随目标已被销毁,需要将其设置为无跟随目标,后续角色则需要重新绑定新的前序角色。
3. 遍历与元素移除的顺序错误
在遍历队列更新位置之前就执行GameMode->Peoples.Remove(this),会导致遍历过程中访问到已失效的元素,同时后续角色的跟随关系未及时更新,队列逻辑混乱。
4. 新生成角色的初始化逻辑缺失
新生成的角色未正确绑定队列的最后一个角色作为跟随目标,导致其默认移动到原第一个角色的位置,而非队列尾部。
修复后的代码实现
1. 修正队列初始化代码
APeople* LastPerson = Peoples.Last(); // 修正三元运算符,确保数组元素足够时才获取前序角色 APeople* PreviousPerson = (Peoples.Num() >= 2) ? Peoples[Peoples.Num() - 2] : nullptr; if (PreviousPerson && LastPerson) { LastPerson->PersonToFollow = PreviousPerson; // 计算与前序角色的间隔位置 LastPerson->TargetLocation = FVector( PreviousPerson->TargetLocation.X, PreviousPerson->TargetLocation.Y - LastPerson->Separation, PreviousPerson->TargetLocation.Z); LastPerson->LastLocation = LastPerson->TargetLocation; PeopleController->MoveUp(LastPerson); }
2. 修正前端角色销毁后的处理逻辑
// 先记录被销毁角色的索引,避免遍历中修改数组 int32 DestroyedIndex = GameMode->Peoples.Find(this); if (DestroyedIndex == INDEX_NONE) return; // 从后往前遍历,更新后续角色的跟随关系与目标位置 for (int32 i = GameMode->Peoples.Num() - 1; i >= 0; i--) { APeople* CurrentPerson = GameMode->Peoples[i]; if (!CurrentPerson) continue; APeopleAIController* Controller = Cast<APeopleAIController>(CurrentPerson->GetController()); if (!Controller) continue; CurrentPerson->LastLocation = CurrentPerson->GetActorLocation(); // 更新跟随目标:如果当前角色的跟随目标是被销毁的角色,重新绑定前序角色 if (CurrentPerson->PersonToFollow == this) { if (i > 0) { // 绑定新的前序角色 CurrentPerson->PersonToFollow = GameMode->Peoples[i - 1]; CurrentPerson->TargetLocation = CurrentPerson->PersonToFollow->LastLocation; } else { // 新的队列前端,无跟随目标,可设置默认移动逻辑或保持原地 CurrentPerson->PersonToFollow = nullptr; // 这里可以根据需求设置前端角色的目标位置 } } else if (CurrentPerson->PersonToFollow) { // 正常跟随前序角色的最新位置 CurrentPerson->TargetLocation = CurrentPerson->PersonToFollow->LastLocation; } Controller->MoveUp(CurrentPerson); } // 移除被销毁的角色 GameMode->Peoples.Remove(this); // 生成新角色并添加到队列尾部 if (GameMode->Spawner) { APeople* NewPerson = GameMode->SpawnPerson(Location, Rotation); if (NewPerson && GameMode->Peoples.Num() > 0) { // 绑定队列最后一个角色作为跟随目标 APeople* LastInQueue = GameMode->Peoples.Last(); NewPerson->PersonToFollow = LastInQueue; NewPerson->TargetLocation = FVector( LastInQueue->TargetLocation.X, LastInQueue->TargetLocation.Y - NewPerson->Separation, LastInQueue->TargetLocation.Z); NewPerson->LastLocation = NewPerson->TargetLocation; APeopleAIController* NewController = Cast<APeopleAIController>(NewPerson->GetController()); if (NewController) { NewController->MoveUp(NewPerson); } GameMode->Peoples.Add(NewPerson); } }
关键修复点说明
- 修复初始化代码的语法错误,确保跟随关系正确绑定。
- 前端角色销毁时从后往前遍历队列,避免遍历过程中数组元素变动导致的逻辑错误。
- 处理空指针情况,更新角色的跟随目标,避免无效访问。
- 新生成角色时主动绑定队列尾部角色,设置正确的目标位置,避免移动到原前端位置。
内容的提问来源于stack exchange,提问作者Shady Shade
相关产品推荐
相关产品推荐

