Gameplay Targeting System 系统概览
Gameplay Targeting System 系统概览
这是一个系列笔记,整理 UE 的
GameplayTargetingSystem实验性插件在一个 ARPG 项目中的实际落地方式。系列其它篇见 Reference 一节。
1. 这套系统解决的问题
游戏里"找目标"的需求散落在各处:
- 投射物到达目标点时需要做一次扇形/球形扩散,找出爆炸范围内的敌人。
- 玩家近战时需要持续维护"当前锁定目标",跟随移动、过滤死人、躲过墙壁。
- 摄像机锁定要从锁定键按下的那一刻起,找一个"屏幕中心附近、视线没被遮挡、还活着的敌人"。
- 处决/奥义动画播放时,需要在周围找几个友方/敌方做 NPC 反应("观众")。
- Boss 在某些阶段会做"找最近的车辆/可吹飞物体/玩家方向预测"等决策。
这些场景的共同结构是:先用某种几何形状收集候选 → 一层层过滤 → 排序选出最优。GameplayTargetingSystem 就是把这套流程抽成数据驱动的框架:开发者写一个 UTargetingPreset 资产(一个有序的 Task 列表),运行时调用一次子系统就能拿到结果。
2. 插件结构
引擎自带,路径在 Engine/Plugins/Experimental/GameplayTargetingSystem/。模块依赖 GameplayTasks、GameplayAbilities、GameplayTags,可以和 GAS 深度集成。
模块对外暴露的核心目录:
GameplayTargetingSystem/Source/.../Public/
├── TargetingSystem/
│ ├── TargetingPreset.h # UTargetingPreset (DataAsset)
│ └── TargetingSubsystem.h # UTargetingSubsystem (主入口)
├── Types/
│ ├── TargetingSystemTypes.h # 核心数据结构
│ └── TargetingSystemDataStores.h # 全局数据存储模板
├── Tasks/
│ ├── TargetingTask.h
│ ├── TargetingSelectionTask_Trace.h
│ ├── TargetingSelectionTask_AOE.h
│ ├── TargetingSelectionTask_SourceActor.h
│ ├── SimpleTargetingSelectionTask.h
│ ├── TargetingFilterTask_BasicFilterTemplate.h
│ ├── TargetingFilterTask_ActorClass.h
│ ├── SimpleTargetingFilterTask.h
│ ├── TargetingSortTask_Base.h
│ ├── TargetingFilterTask_SortByDistance.h
│ ├── SimpleTargetingSortTask.h
│ └── CollisionQueryTaskData.h
├── AbilityTasks/AbilityTask_PerformTargeting.h
└── Async/AsyncAction_PerformTargeting.h
实际项目中通常会在插件之上再封装一层"框架层"(下文简称 Framework),用来:
- 给所有过滤任务一个统一的基类,加上
bInvert开关、被过滤目标记录、ShouldRetainTarget这种更"白名单"语义的覆盖点。 - 扩展几个项目里高频使用的任务:距离过滤、队伍态度过滤、Tag 查询过滤、视线障碍过滤、效用函数排序、相机追踪等。
- 加一个
IFrameworkTargetingSourceInterface接口,让飞行物之类的 Actor 可以在运行时动态向 Task 提供追踪参数,而不是死写在 DataAsset 里。
后续几篇博客里出现的 UFW_TargetingFilterTask_* / UFW_TargetingSelectionTask_* 都属于这一层,思路是通用的。
3. 完整类图
3.1 引擎原生类层次
3.2 项目框架层扩展(示意)
3.3 数据存储与句柄
整个系统是"按 Handle 寻址"的。每次发起请求都会拿到一个 FTargetingRequestHandle(本质是 uint32),所有数据存在一组以 Handle 为 Key 的全局 TSortedMap 里:
这种"句柄 + 旁挂数据"的设计带来两个特点:
- Task 自身是
Const的UObject,本身不存运行时数据,方便复用同一个UTargetingPreset实例发出大量并行请求。 - 必须显式
ReleaseTargetRequestHandle()或在请求里设置bReleaseOnCompletion = true,否则旁挂数据不会被清理,会慢慢泄漏。
4. 架构分层
整个系统从调用方到数据可以分成四层:
5. 典型使用场景拆解
下面把项目里"用了这个系统"的几种典型场景列一下,作为后面几篇笔记的索引。
5.1 投射物一次性目标查找
触发时机: 投射物到达指定位置或发生碰撞时,做一次 AOE/扫描查询。
使用方式: 同步执行(ExecuteTargetingRequestWithHandle),同帧拿结果。
配置入口: 投射物资产上挂一个 TSoftObjectPtr<UTargetingPreset> 字段,例如 OneTimeTargetingPreset。
典型 Preset: 扩展 Trace 任务(可按等级缩放)或 AOE,配视线障碍过滤。
5.2 近战锁敌系统(持续轮询)
触发时机: Tick 时按固定间隔执行,默认每 0.1 秒查一次。
使用方式: 框架层的 UFW_PlayerMeleeTargetingComponent 定时调用同步请求,把第一个结果设为 CurrentTargetActor。
典型 Preset:
- AOE 球形选择
- 队伍态度过滤(只保留敌方)
- 视线障碍过滤
- 前向夹角过滤(在 Component 中以 C++ 方式额外做一道,对应
FilteringTargetsByForwardAngle) - 效用函数排序(距离 + 角度综合打分)
5.3 摄像机锁定系统
触发时机: 玩家按下锁定键时执行一次"找目标";锁定状态下每 0.2 秒验证一次目标仍然有效。
使用方式: 蓝图里调用异步节点。
配置入口: 两个 UTargetingPreset 资产,一个负责"找最优锁定目标",另一个负责"验证当前目标是否还在范围/视线内"。
5.4 处决/奥义中的观众查找
用途: 必杀技和处决时希望周围的 NPC(友方或敌方)有视觉反应,所以需要在场景里挑几个最近的存活角色。
典型 Preset: AOE 选择(半径 800~1000 cm)→ ActorClass 过滤(只保留角色基类)→ 排除死亡 Tag → 按距离升序。
5.5 Boss 行为决策
用途: 某些 Boss 阶段需要做特殊决策——查找附近可吹飞的车辆、可跳上去的车辆、最近的鸟群控制器,或预测玩家速度方向选择冲刺目标。
每个具体行为各自挂一个 UTargetingPreset,由 Boss 的"目标组件"在合适时机异步调用。
6. 接下来读哪篇
| 主题 | 文档 |
|---|---|
数据资产(UTargetingPreset)与 Task 配置参数 | DataAssets.md |
| C++ API:子系统、句柄、自定义任务 | CPP.md |
| 蓝图使用:Subsystem / AbilityTask / AsyncAction | Blueprint.md |
| 性能预算、调试技巧、维护清单 | Maintenance.md |