Gameplay Targeting System 性能、调试与维护
Gameplay Targeting System 性能、调试与维护
本文是 Gameplay Targeting System 系列 的第五篇,整理实际开发中怎么把这套系统跑得稳。
1. 新增使用场景的标准流程
1.1 给新角色加近战锁敌
- 挂组件:C++ 角色里在构造或
BeginPlay加UMeleeTargetingComponent;纯蓝图角色直接挂BP_MeleeTargetingComponent。 - 建 Preset:以现有的玩家近战 Preset 为模板复制,按角色调整(半径、过滤条件等)。命名
DA_TargetingPreset_<角色>_MeleeTarget。 - 绑定:组件的 Details 里把
Targeting Preset Find Target Actors设到新 Preset。 - 额外角度过滤(可选):项目里通常会在组件中再做一道前向夹角过滤(
FilteringTargetsByForwardAngle),蓝图可调用对应函数。
1.2 给新投射物加一次性命中
- 找/新建对应的飞行物资产(
PA_SpellFlight_*)。 - 以 DataAssets 模板 B 为底建新 Preset,命名
DA_TargetingPreset_<角色>_<技能>_Hit。 - 在飞行物资产的
Projectile Definition → One Time Targeting Preset字段里设上新 Preset。 - PIE 中开
bDebug验证扫描范围、检查命中数量。
1.3 给新技能加目标查找
- 以 DataAssets 模板 D 为底建 Preset。
- 在 GAS 能力蓝图里拖
Perform Targeting RequestAbilityTask,接On Target Ready后续逻辑。 - SourceContext:
SourceActor = 自己;如果是召唤物释放的技能,InstigatorActor要指向玩家。
2. 自定义任务模板(CDU/工具模板)
2.1 C++ 过滤任务(推荐继承框架层基类)
#pragma once
#include "CoreMinimal.h"
#include "Targeting/Filter/FW_TargetingFilterTask_BasicFilterTemplate.h"
#include "TargetingFilterTask_YourFilter.generated.h"
UCLASS(Blueprintable, EditInlineNew)
class GAME_API UTargetingFilterTask_YourFilter
: public UFW_TargetingFilterTask_BasicFilterTemplate
{
GENERATED_BODY()
protected:
// 返回 true = 保留目标;false = 过滤掉
virtual bool ShouldRetainTarget(
const FTargetingRequestHandle& Handle,
const FTargetingDefaultResultData& TargetData) const override;
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Your Filter")
float YourParam = 100.f;
};
bool UTargetingFilterTask_YourFilter::ShouldRetainTarget(
const FTargetingRequestHandle& Handle,
const FTargetingDefaultResultData& TargetData) const
{
AActor* Target = TargetData.HitResult.GetActor();
if (!Target) return false;
// TODO: 实现具体过滤逻辑
return true;
}
记得在模块的 Build.cs 里确认 TargetingSystem 已加入依赖。
2.2 纯蓝图自定义 Task
- Content Browser → 右键 → Blueprint Class。
- 父类按需要选择:
- 选择 →
SimpleTargetingSelectionTask - 过滤 →
SimpleTargetingFilterTask - 排序 →
SimpleTargetingSortTask
- 选择 →
- 实现对应事件:
SelectTargets/ShouldRemoveTarget/GetScoreForTarget。 - 命名:
BT_Selection_XXX/BT_Filter_XXX/BT_Sort_XXX,保存到统一的"BP/Targeting" 目录便于检索。
3. 性能监控
3.1 性能预算参考
下面是一个 ARPG 项目里实测出来的"舒服区间",作为参考阈值。各项目可按目标平台收紧。
| 场景 | 调用频率 | 期望耗时 | 红线 |
|---|---|---|---|
| 近战锁敌更新 | 每 0.1s | < 0.1ms | 0.3ms |
| 投射物一次性命中 | 单次 | < 0.2ms | 0.5ms |
| 摄像机锁定验证 | 每 0.2s | < 0.2ms | 0.5ms |
| 奥义观众查找 | 单次 | < 0.5ms | 1ms |
3.2 优化策略
减少候选目标数量
- AOE 半径不要给的过大;先精确再补。
CollisionObjectTypes用最具体的(如[Pawn]);不要默认就拉上WorldDynamic。- 开
bIgnoreSourceActor/bIgnoreInstigatorActor去掉无效目标。
降低过滤开销
- 把最便宜的过滤放最前面(ActorClass、Distance),让候选集尽早缩小。
- 视线障碍过滤是最贵的,放最后;可以先用
RecentlyRendered之类的廉价过滤兜一道。
异步执行
- Boss 行为决策这种非关键路径全部走
StartAsyncTargetingRequest。 - 不要在 Tick 里直接同步请求(除非间隔够长,或者业务上必须同帧拿结果)。
轮询频率自适应
- 近战目标组件的更新间隔默认 0.1s 已经够紧;玩家没目标时可以掉到 0.3s。
- 配合 Significance / LOD 预算:远离玩家的角色降低轮询频率。
3.3 Significance 集成示意
如果项目里用了某种 Significance / LOD 预算系统来管 Tick 频率,目标组件可以响应重要性变化主动放慢:
void UMeleeTargetingComponent::OnSignificanceChanged(float SignificanceValue)
{
if (SignificanceValue < 0.5f)
{
UpdateTargetActorInterval = 0.5f; // 低重要性,慢一点
}
else
{
UpdateTargetActorInterval = 0.1f;
}
}
4. 调试工具
4.1 控制台命令
| 命令 | 说明 |
|---|---|
Targeting.Debug 1 | 开启 TargetingSystem 调试绘制 |
Targeting.Debug 0 | 关闭 |
ShowFlag.TargetingDebug 1 | 显示目标系统 HUD 信息 |
4.2 日志类别
在 DefaultEngine.ini 里:
[Core.Log]
LogTargetingSystem=Verbose ; 引擎原生日志
LogFWTargeting=Verbose ; 框架层扩展日志(如果项目有)
打开后能看到:每次请求执行了哪些任务、每个过滤任务踢掉了多少目标、Handle 的创建和释放时机。
4.3 任务自带的调试开关
UFW_TargetingFilterTask_TraceObstacle::bDebug = true会画 Source→Target 的检测路径,绿色未被挡、红色被挡。- 框架层的子系统一般提供
GetFilteredOutResults(Handle),能列出每个目标在哪个过滤任务被踢掉,用于调试 Preset。
if (UFWTargetingSubsystem* FWTS = Cast<UFWTargetingSubsystem>(
UTargetingSubsystem::Get(GetWorld())))
{
const FFW_Targeting_FilteredOutData* FilteredData =
FWTS->GetFilteredOutResults(TargetingHandle);
if (FilteredData)
{
for (const FTargetingFilteredOutData& Item : FilteredData->FilteredOutDataArray)
{
UE_LOG(LogGameTargeting, Log,
TEXT("Filtered out: %s by tasks: %s"),
*Item.HitResult.GetActor()->GetName(),
*FString::Join(Item.FilterTaskNames, TEXT(", ")));
}
}
}
5. 已知问题与限制
5.1 插件状态:Experimental
GameplayTargetingSystem 在引擎里仍标记为 Experimental,Epic 可能在后续版本里改动 API。建议项目内通过一层"框架层"封装隔离风险——这样升引擎时改一处就够了,而不是全工程改。
5.2 异步 Trace 帧延迟
异步 Trace 依赖物理线程,至少 1 帧延迟。需要即时反馈(格挡判定、QTE)的场景必须用同步执行。
5.3 网络复制
UTargetingSubsystem 是 UGameInstanceSubsystem,Server 和 Client 各自独立运行,目标查找结果不会自动同步。建议在 Server 端执行目标查找,通过 RPC 把结果发到 Client。
5.4 FScalableFloat 等级缩放
UTargetingSelectionTask_Trace 的 DefaultTraceLength 等使用 FScalableFloat,需要等级缩放时通过 CurveTable 配置。框架层的 TraceExt 通过 IFrameworkTargetingSourceInterface 提供了运行时动态传值的方案,比 CurveTable 灵活,参考 CPP.md。
6. 版本升级注意事项
6.1 升引擎(UE 5.x → 5.y)
- 确认
GameplayTargetingSystem插件仍在Engine/Plugins/Experimental/。 - 重点检查
TargetingSubsystem.h、MakeTargetRequestHandle、ExecuteTargetingRequestWithHandle的签名变化。 - 检查
FTargetingRequestHandle结构是否变。 - 跑一遍全量集成测试,验证所有 Preset 还能跑出正确结果。
6.2 升框架层
- 检查所有
UFW_Targeting*类的父类与接口变化。 - 检查
IFrameworkTargetingSourceInterface接口方法签名。 - 检查"被过滤目标"的数据结构(如
FFW_Targeting_FilteredOutData)。
7. 代码审查清单
新增使用 GameplayTargetingSystem 的代码,过 CR 时应当确认:
8. 跳过的清理项
源文档中有几条属于内部项目状态(如"Build.cs 中 TargetingSystem 被添加了两次需要清理"),这类只对原项目的 CR 有意义、不具技术泛化价值,在本系列里不收录。