问题根源分析
核心原因:UGameplayDebuggerLocalController 不是 Actor,它是一个 UObject
通过代码分析,我发现了关键问题:
-
UGameplayDebuggerLocalController是UObject,不是AActorUCLASS(NotBlueprintable, NotBlueprintType, noteditinlinenew, hidedropdown, Transient) class UGameplayDebuggerLocalController : public UObject -
它没有位置(Location)属性
UObject没有SetActorLocation()或任何位置相关的方法- 它只是一个逻辑控制器,负责输入处理和UI绘制
-
真正有位置的是
AGameplayDebuggerCategoryReplicatorclass 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 的代码,我发现:
-
构造函数中没有设置跟随逻辑
AGameplayDebuggerCategoryReplicator::AGameplayDebuggerCategoryReplicator(const FObjectInitializer& ObjectInitializer) { PrimaryActorTick.bCanEverTick = true; // ... 但没有设置位置更新逻辑 } -
BeginPlay 中设置了位置为隐藏
void AGameplayDebuggerCategoryReplicator::BeginPlay() { SetActorHiddenInGame(!bIsLocal); // 只是隐藏,没有设置位置 } -
Tick 中只收集数据,不更新位置
void AGameplayDebuggerCategoryReplicator::TickActor(...) { if (OwnerPC) { CollectCategoryData(); // 只收集数据,不更新位置 } }
为什么远距离时会失效?
结合之前的分析,问题链条是:
- Replicator 不跟随玩家移动 → 停留在原地
- 玩家移动到远处 → Replicator 距离玩家太远
- 网络剔除机制触发 →
bAlwaysRelevant = false(默认值) - Replicator 变得不可见 →
IsValid(Replicator)返回false - PlayerData 被清空 →
GetLocalController()返回nullptr - GDT 失效 ❌
解决方案
方案 1:让 Replicator 跟随玩家移动(推荐)
修改 AGameplayDebuggerCategoryReplicator::TickActor(),添加位置更新逻辑:### 方案 2:设置 bAlwaysRelevant(之前已提供)
如之前讨论的,在 FGameplayDebuggerCategory_ChestPVE 中设置 Replicator 的网络属性。
问题本质
UGameplayDebuggerLocalController 没有跟着玩家移动的原因:
-
设计上:
UGameplayDebuggerLocalController是UObject,不是AActor,它没有位置属性 -
架构上:它只是一个逻辑控制器,负责:
- 输入处理(按键绑定)
- UI 绘制(Canvas 渲染)
- 与 Replicator 通信
-
真正有位置的是
AGameplayDebuggerCategoryReplicator,但它也没有实现跟随玩家的逻辑
为什么远距离会失效?
玩家移动 → Replicator 停留原地 → 距离过远 → 网络剔除 → PlayerData 清空 → GDT 失效
推荐解决方案组合
方案 A:修改引擎层(治本)
- 在
AGameplayDebuggerCategoryReplicator::TickActor()中添加跟随玩家的逻辑 - 让 Replicator 始终在玩家附近
方案 B:修改业务层(治标)
- 在
FGameplayDebuggerCategory_ChestPVE中设置bAlwaysRelevant = true - 避免网络剔除
最佳实践:两者结合
- 使用方案 A 让 Replicator 跟随玩家(更符合设计意图)
- 同时使用方案 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 没有跟着玩家移动,以及如何解决这个问题!