UE5.8 Gameplay Ability System 专题系列

UE5.8 GAS 专题(七):GameplayCue 表现管线

解释 GameplayCue Tag、Cue Notify、Burst/Looping 表现、复制路径、Cue 参数和 PlayerState ASC 场景下的网络相关性问题。

总览

GameplayCue 的价值是把玩法逻辑和表现解耦。Ability 不应该知道火球命中播哪个 Niagara,GameplayEffect 不应该硬编码音效路径。逻辑只触发一个 GameplayCue.* Tag,表现层根据 Tag 决定如何播特效、音效、镜头和材质反馈。

本篇讲 Cue 的事件语义、Notify 类型、参数、复制路径和项目落地规范。

UE5.8 GAS 专题(七):GameplayCue 表现管线 配图
GameplayCue 把逻辑状态转换成表现事件,让 VFX、SFX 和相机反馈从 Ability/GE 中解耦。

源码依据

关键点来自 GAS README、GameplayEffectTypes.h 和 GameplayCue 相关源码。

Cue 参数类型是 FGameplayCueParameters,包含:

  • Magnitude。
  • EffectContext。
  • MatchedTag 和 OriginalTag。
  • SourceTags 和 TargetTags。
  • Location 和 Normal。
  • Instigator 和 EffectCauser。
  • SourceObject。
  • PhysicalMaterial。
  • EffectLevel 和 AbilityLevel。
  • AttachComponent。

Cue 事件枚举包括:

  • OnActive
  • WhileActive
  • Executed
  • Removed

README 里还说明 Burst 类 Cue 通过不可靠 RPC 复制,Looping 类 Cue 依赖复制变量维持状态。PlayerState 持有 ASC 时,要特别关注网络相关性和复制代理。

Cue Tag 命名

推荐把 Cue Tag 当表现 API:

Tag 语义
GameplayCue.Weapon.Rifle.Fire 步枪开火
GameplayCue.Weapon.Rifle.Hit.Flesh 步枪命中角色
GameplayCue.Spell.Fireball.Explode 火球爆炸
GameplayCue.Status.Burning.Loop 燃烧持续表现
GameplayCue.Shield.Break 护盾破裂

不要把具体资产名放进 Tag。Tag 表达语义,Notify 决定资产。

Static 还是 Actor

类型 生命周期 适合
UGameplayCueNotify_Static 无状态、一次执行 命中特效、爆炸、治疗闪光
UGameplayCueNotify_Actor 可持续、可附着、可结束 燃烧循环、护盾、光环、持续冰冻

Burst 表现优先 Static。持续表现用 Actor,因为它需要 OnActive 创建、WhileActive 保持、Removed 清理。

UCLASS()
class UGCN_HitSpark : public UGameplayCueNotify_Static
{
    GENERATED_BODY()

public:
    virtual bool OnExecute_Implementation(AActor* MyTarget, const FGameplayCueParameters& Parameters) const override
    {
        if (!MyTarget || !HitSystem)
        {
            return false;
        }

        const FVector SpawnLocation = Parameters.Location.IsNearlyZero()
            ? MyTarget->GetActorLocation()
            : Parameters.Location;

        UNiagaraFunctionLibrary::SpawnSystemAtLocation(
            MyTarget,
            HitSystem,
            SpawnLocation,
            Parameters.Normal.Rotation());

        return true;
    }

private:
    UPROPERTY(EditDefaultsOnly)
    TObjectPtr<UNiagaraSystem> HitSystem;
};

这段代码只做表现,不做伤害,不改属性,不决定命中是否有效。

Cue 从哪里触发

常见触发路径:

  1. GE 自带 GameplayCue。
  2. Ability 显式调用 ASC 的 Cue 接口。
  3. GameplayCue Notify 由 Active GE 的 Add/Remove 自动触发。

推荐优先让 GE 触发 Cue。比如伤害 GE 触发命中 Cue,燃烧 GE 触发燃烧循环 Cue。这样表现跟状态绑定,调试 Active GE 时也能看到 Cue 来源。

Ability 显式触发适合纯表现或不需要状态的瞬时反馈,比如本地开镜、蓄力提示。但要避免客户端随便触发会影响其他人的权威表现。

Cue 参数设计

Cue 参数应该带足表现需要的信息:

信息 来源
命中位置 TargetData HitResult 或 EffectContext
法线 HitResult Normal
伤害大小 Cue Magnitude 或 SetByCaller 映射
攻击者 Instigator
武器 SourceObject 或 EffectCauser
物理材质 HitResult PhysMaterial
元素类型 GameplayTag

不要让 Cue Notify 再去世界里查一遍“我到底命中了哪”。命中数据应该在 TargetData/EffectContext 里传下来。

复制与相关性

Cue 的网络问题常见于两类场景:

  • ASC 放在 PlayerState,远端客户端看不到 Cue。
  • Cue 由本地预测触发,服务器结果回来后重复或消失。

排查顺序:

  1. Cue Tag 是否在 GameplayCue 路径里。
  2. Cue Notify 资产是否被扫描到。
  3. GE 是否真的应用到了目标 ASC。
  4. Cue 是 Executed 还是 Active/Removed。
  5. 目标 Actor 对远端是否 relevant。
  6. PlayerState ASC 是否需要复制代理。
  7. 本地预测和服务器确认是否重复触发。

PlayerState ASC 很适合保存玩家长期状态,但表现通常附着在 Character 上。项目里要保证 Cue 参数里有正确的 Avatar 或 AttachComponent。

项目落地规范

建议建立 Cue 内容规则:

建议
路径 /Game/GameplayCues/...
命名 GCN_Weapon_Rifle_Hit_Flesh
Tag 与资产语义一致,不带具体 Niagara 名
数据 Location、Normal、Instigator、SourceObject 尽量齐全
权威 影响其他玩家的 Cue 由服务器状态触发
预测 本地预测 Cue 要能和服务器确认对账

GASToolsets 里的 GameplayCue 工具可以列出 Cue、查 Notify、创建 Cue Notify、找没有 Notify 的 Cue Tag。它很适合做内容检查,但创建或删除 Cue Tag 要走人工确认。

常见坑

  • Ability 里硬编码特效。 后期替换表现要改逻辑。
  • Cue Tag 没进扫描路径。 GE 触发了,Notify 找不到。
  • Static Cue 做持续表现。 没有生命周期,很难清理。
  • Cue 里做伤害。 Cue 是表现层,不应该改变玩法结果。
  • PlayerState ASC 远端不显示 Cue。 查网络相关性和复制代理。
  • 预测 Cue 重复。 本地预测和服务器确认要有去重或可接受的表现策略。

本篇结论:GameplayCue 是 GAS 的表现接口。逻辑发语义,表现资产响应语义。这个边界守住后,技能美术、音频、镜头和玩法代码才不会互相绑死。

源码路径索引

  • Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/AbilitySystemComponent.h
  • Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/AbilitySystemComponent.cpp
  • Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Private/AbilitySystemComponent_Abilities.cpp
  • Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/Abilities/GameplayAbility.h
  • Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/GameplayEffect.h
  • Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/AttributeSet.h
  • Engine/Plugins/Runtime/GameplayAbilities/Source/GameplayAbilities/Public/GameplayPrediction.h