能力组合:GA 是动作事务,不是交互物基类

自动关联目录:能力组合:GA 是动作事务,不是交互物基类

核心判断:Gameplay Ability 适合表达角色发起的、有激活条件、消耗、冷却、取消和预测窗口的动作事务;交互物的空间发现、长期状态、占用、持久化和大规模索引应由组件与服务负责。把场景里每个交互物都做成 GA,只是把 Actor 膨胀换成 ASC 与 Ability Spec 膨胀。

一、业务冲突:玩法需要统一能力,又不能让统一框架吞掉所有状态

战斗、武器、移动技能和部分交互都具有相似流程:输入、检查条件、扣除资源、播放动作、命中、取消、冷却、DS 结算和客户端反馈。GA 能复用这些机制。但宝箱是否开启、座位被谁占用、任务节点进度、可拾取物空间索引和跨世界持久数据,并不是一次 Ability 的生命周期。

业务真正需要的是“能力组合”,不是“所有行为继承同一个重基类”。

二、实际实现:正确的复用与边界泄漏同时存在

现有实践中,主动/被动能力通过 ASC 授予,并保存 AbilitySpecHandle;属性变化用 Gameplay Effect Handle 管理。装备实例保留来源物品身份,装备时由 Ability Set 一次授予能力,卸装时用已记录 Handles 成对撤销,并只允许 Authority 修改。这是 GA 与领域组件协作的正确例子。

另一类跟随能力由组件维护领域关系,再按状态动态 grant/clear 若干 Ability;句柄避免了重复授予,但可用性仍在服务器 Tick 中持续查询。自定义 Cost 已能读取体力或物品耐久,不过某些异常来源走了 fail-open,说明“接入了 Cost 扩展”不等于权威资源一定安全。

交互框架本身仍使用轻量组件和服务管理范围、优先级、对象状态与互斥,而没有给每个场景物件挂 ASC。这一选择应被明确成架构规则。

flowchart LR
    I[输入/AI 意图] --> S[交互与目标服务]
    S --> P{动作是否需要<br/>预测/消耗/冷却/取消?}
    P -->|是| A[角色 ASC 上的 GA]
    P -->|否| C[轻量命令处理器]
    A --> D[领域组件/共享服务提交状态]
    C --> D
    D --> N[权威快照/事件]
    N --> V[动画 UI 音频 特效]

三、值得保留:Handle 成对管理把授予变成可撤销资源

装备条目记录来源实例和 Granted Handles,使“为什么拥有此能力”可追溯,卸装能精确撤销,不必按 Class 猜测。Authority Guard、Fast Array 脏标记、Gameplay Effect 和 Gameplay Cue 也分别承担权威修改、增量状态与表现反馈,职责较清楚。

Cost、Cooldown、Gameplay Tag、Ability Task 和 Prediction Key 是 GAS 的真正价值。它们特别适合角色中心、短生命周期、需要被打断或预测的动作,而不是用来替代库存、目标注册表和世界对象状态机。

四、结构性缺陷:动态 grant 可能变成高频状态同步手段

若组件每帧扫描附近目标,再通过 grant/clear 表达按钮是否可用,会产生 Spec 变更、输入槽更新、复制和实例生命周期成本。更合适的是稳定授予少量动作 Ability,用 Tag/条件查询决定能否激活,并由事件更新候选目标。

把 GA 放到每个交互 Actor 上还有 UE 所有权问题:客户端通常不拥有场景 Actor,无法沿标准 Owned Actor RPC/预测链发起能力;为每物体创建 ASC 又会增加属性聚合、Tag 容器、Spec 和复制负担。自定义 Cost 若缺数据仍返回成功,则会把错误配置变成免费施放,权威扣费必须 fail-closed。

五、目标设计:以动作复杂度决定是否进入 GAS

世界服务先产生已验证 Target Handle;角色上的稳定 Ability 接收 TargetData,使用 GAS 处理 Commit、Cost、Cooldown、Cancel 和预测,真正的库存、装备、目标或任务状态仍提交给领域服务。纯开关、一次性领取等无预测需求的动作可直接走轻量 DS Command Handler。

ExecutionPath Choose(ActionDefinition a)
{
    if (a.needsPrediction || a.hasCost || a.hasCooldown ||
        a.isInterruptible || a.composesEffects)
        return CharacterAbility;
    return LightweightCommand;
}

AbilityResult CommitAbility(ActorInfo owner, TargetHandle target)
{
    if (!target.IsCurrent() || !CheckCost(owner) || !CheckTags(owner))
        return FailClosed;
    ScopedPrediction prediction(owner);
    DomainCommit result = Services.Execute(owner.id, target);
    return result.ok ? CommitCostAndCooldown() : RollbackPrediction();
}

无状态动作优先 Non-Instanced;确需保存每角色执行状态时用 Instanced Per Actor;只有执行间必须并发隔离时才承担 Per Execution 成本。

六、决策规则:抽象边界按所有权与生命周期划分

能力或状态首选承载原因
消耗、冷却、Buff、可取消技能GA/GE/TagGAS 已提供权威、预测与组合语义
装备授予的一组动作Equipment Instance + Ability Set来源可追溯,Handles 可成对撤销
空间发现与目标排序World/Player Interaction Service与 Ability 实例无关,需规模化查询
对象占用与持久状态DS Domain Component/Service生命周期长于一次 Ability
简单幂等开关Typed Command Handler无需承担 ASC/Spec 成本
视听反馈Gameplay Cue 或 Presentation Event不成为权威状态源

GA 是好工具,但“场景里全是 GA”不是统一,而是边界缺失。更成熟的问题不是能否用 GA 实现,而是这段状态是否属于角色动作事务;只有答案为是,GAS 的复杂度才有回报。