UGameplayDebuggerLocalController为什么没有跟着玩家一起移动

问题根源分析

核心原因:UGameplayDebuggerLocalController 不是 Actor,它是一个 UObject

通过代码分析,我发现了关键问题:

  1. UGameplayDebuggerLocalControllerUObject,不是 AActor

    UCLASS(NotBlueprintable, NotBlueprintType, noteditinlinenew, hidedropdown, Transient)
    class UGameplayDebuggerLocalController : public UObject
  2. 它没有位置(Location)属性

    • UObject 没有 SetActorLocation() 或任何位置相关的方法
    • 它只是一个逻辑控制器,负责输入处理和UI绘制
  3. 真正有位置的是 AGameplayDebuggerCategoryReplicator

    class AGameplayDebuggerCategoryReplicator : public AActor
    • 这是一个 Actor,有位置属性
    • 但它也没有实现跟随玩家的逻辑

架构设计

让我用图表说明 GDT 的架构:

graph TD
    A[APlayerController] --> B[AGameplayDebuggerPlayerManager]
    B --> C[UGameplayDebuggerLocalController<br/>UObject - 无位置]
    B --> D[AGameplayDebuggerCategoryReplicator<br/>AActor - 有位置但不移动]
    C --> |引用| D
    D --> E[Categories]
    D --> F[Extensions]
    C --> |绘制UI| G[Canvas]

为什么 Replicator 不跟随玩家移动?

查看 AGameplayDebuggerCategoryReplicator 的代码,我发现:

  1. 构造函数中没有设置跟随逻辑

    AGameplayDebuggerCategoryReplicator::AGameplayDebuggerCategoryReplicator(const FObjectInitializer& ObjectInitializer)
    {
        PrimaryActorTick.bCanEverTick = true;
        // ... 但没有设置位置更新逻辑
    }
  2. BeginPlay 中设置了位置为隐藏

    void AGameplayDebuggerCategoryReplicator::BeginPlay()
    {
        SetActorHiddenInGame(!bIsLocal);  // 只是隐藏,没有设置位置
    }
  3. Tick 中只收集数据,不更新位置

    void AGameplayDebuggerCategoryReplicator::TickActor(...)
    {
        if (OwnerPC)
        {
            CollectCategoryData();  // 只收集数据,不更新位置
        }
    }

为什么远距离时会失效?

结合之前的分析,问题链条是:

  1. Replicator 不跟随玩家移动 → 停留在原地
  2. 玩家移动到远处 → Replicator 距离玩家太远
  3. 网络剔除机制触发bAlwaysRelevant = false(默认值)
  4. Replicator 变得不可见IsValid(Replicator) 返回 false
  5. PlayerData 被清空GetLocalController() 返回 nullptr
  6. GDT 失效

解决方案

方案 1:让 Replicator 跟随玩家移动(推荐)

修改 AGameplayDebuggerCategoryReplicator::TickActor(),添加位置更新逻辑:### 方案 2:设置 bAlwaysRelevant(之前已提供)

如之前讨论的,在 FGameplayDebuggerCategory_ChestPVE 中设置 Replicator 的网络属性。

问题本质

UGameplayDebuggerLocalController 没有跟着玩家移动的原因:

  1. 设计上UGameplayDebuggerLocalControllerUObject,不是 AActor,它没有位置属性

  2. 架构上:它只是一个逻辑控制器,负责:

    • 输入处理(按键绑定)
    • UI 绘制(Canvas 渲染)
    • 与 Replicator 通信
  3. 真正有位置的是 AGameplayDebuggerCategoryReplicator,但它也没有实现跟随玩家的逻辑

为什么远距离会失效?

玩家移动 → Replicator 停留原地 → 距离过远 → 网络剔除 → PlayerData 清空 → GDT 失效

推荐解决方案组合

方案 A:修改引擎层(治本)

  • AGameplayDebuggerCategoryReplicator::TickActor() 中添加跟随玩家的逻辑
  • 让 Replicator 始终在玩家附近

方案 B:修改业务层(治标)

  • FGameplayDebuggerCategory_ChestPVE 中设置 bAlwaysRelevant = true
  • 避免网络剔除

最佳实践:两者结合

  1. 使用方案 A 让 Replicator 跟随玩家(更符合设计意图)
  2. 同时使用方案 B 作为保险(防止极端情况)

代码对比

对象 类型 有位置 会移动 作用
UGameplayDebuggerLocalController UObject 输入处理、UI绘制
AGameplayDebuggerCategoryReplicator AActor ❌(需修改) 数据复制、Category管理
APlayerController AActor 玩家控制器

验证方法

修改后,您可以通过以下方式验证:

// 在控制台输入
DisplayAll GameplayDebuggerCategoryReplicator Location

// 或者在代码中添加日志
UE_LOG(LogTemp, Log, TEXT("Replicator Location: %s, Player Location: %s"), 
    *GetActorLocation().ToString(), 
    *OwnerPC->GetPawn()->GetActorLocation().ToString());

希望这个详细的解释能帮助您理解为什么 UGameplayDebuggerLocalController 没有跟着玩家移动,以及如何解决这个问题!