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

游戏队列系统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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 05:57:40