UE_GAS笔记

1.ASC及其初始化

声明成员变量 AbilitySystemComponent

UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "GAS|Abilities")
	class UASC* AbilitySystemComponent;

构造函数

  • ASC一般在OwnerActor的构建函数中创建并且需要明确标记为Replicated. 这必须在C++中完成.
AbilitySystemComponent = CreateDefaultSubobject<UASC>(TEXT("AbilitySystem"));
AbilitySystemComponent->SetIsReplicated(true);

设置ASC同步模式

AbilitySystemComponent->SetReplicationMode(EGameplayEffectReplicationMode::Full);
同步模式何时使用描述
Full单人所有GameplayEffect都同步到客户端.
Mixed多人, 玩家控制的ActorGameplayEffect只同步到其所属客户端, 只有GameplayTagGameplayCue同步到所有客户端.
Minimal多人, AI控制的ActorGameplayEffect从不同步到任何客户端, 只有GameplayTagGameplayCue同步到所有客户端.
  • 由此可见,如果想要在客户端拿到GE的信息,必须将ASC的复制模式设置为Full

重载GetAbilitySystemComponent()函数

  • 该接口有一个必须重写的函数, UAbilitySystemComponent* GetAbilitySystemComponent() const, 其返回一个指向ASC的指针, ASC通过寻找该接口函数来和系统内部进行交互.

    //.h
    virtual UAbilitySystemComponent* GetAbilitySystemComponent() const override;
    
    //.cpp
    UAbilitySystemComponent* Character::GetAbilitySystemComponent() const
    {
    	return AbilitySystemComponent;
    }
    
  • 初始化ASC

    	//ASC在服务端和客户端上均需初始化
    	//void UASC_honkai_rts::InitAbilityActorInfo(AActor *InOwnerActor, AActor *InAvatarActor)
    	AbilitySystemComponent->InitAbilityActorInfo(this, this);
    

2.AS

创建和初始化AS

  • 派生自UAttributeSet,在OwnerActor的构造函数中创建AttributeSet会自动注册到其ASC. 这必须在C++中完成.
  • FGameplayAttributeData拥有两个值BaseValue,CurrentValue
    • GE_DurationPolicy
    • 当GE的延时策略为instant时,永久性的修改BaseValue持续(Has Duration)无限(Infinite)可以修改CurrentValue.
  • 当GE为周期(Periodic)时,视为instant,永久修改BaseValue

监听AS改变

  • image-20230125142657706

定义AS

  • Attribute只能使用C++在AttributeSet头文件中定义.

    • 建议把下面这个宏块加到每个AttributeSet头文件的顶部, 其会自动为每个Attribute生成getter和setter函数.

    • #define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \
      	GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
      	GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
      	GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
      	GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)
      

举例

  • 在AS中声明FGameplayAttributeData变量

    • UPROPERTY(BlueprintReadOnly, Category = "Health", ReplicatedUsing = OnRep_Health)
      FGameplayAttributeData Health;
      ATTRIBUTE_ACCESSORS(UGDAttributeSetBase, Health)
      
  • 在头文件中定义OnRep函数:

    • UFUNCTION()
      virtual void OnRep_Health(const FGameplayAttributeData& OldHealth);
      
  • 用预测系统(Prediction System)使用的GAMEPLAYATTRIBUTE_REPNOTIFY宏填充OnRep函数:

    • void UGDAttributeSetBase::OnRep_Health(const FGameplayAttributeData& OldHealth)
      {
      	GAMEPLAYATTRIBUTE_REPNOTIFY(UGDAttributeSetBase, Health, OldHealth);
      }
      
  • Attribute需要添加到GetLifetimeReplicatedProps:

    • void UGDAttributeSetBase::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
      {
      	Super::GetLifetimeReplicatedProps(OutLifetimeProps);
          //REPTNOTIFY_Always用于设置OnRep函数在客户端值已经与服务端同步的值相同的情况下触发(因为有预测), 默认设置下, 客户端值与服务端同步的值相同时, OnRep函数是不会触发的.
      	DOREPLIFETIME_CONDITION_NOTIFY(UGDAttributeSetBase, Health, COND_None, REPNOTIFY_Always);
      }
      
  • 建议使用instant的GE来初始化AS

AS主要重载函数

  • PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue)AttributeSet中的主要函数之一, 其在修改发生前响应Attribute的CurrentValue变化, 其是通过引用参数NewValue限制(Clamp)CurrentValue即将进行的修改的理想位置.
    • 这个时间点为:对Attribute的修改已经发生, 但是还没有被同步回客户端,客户端只会收到函数作用后的值.
  • PostGameplayEffectExecute(const FGameplayEffectModCallbackData & Data)仅在即刻(Instant)GameplayEffectAttribute的BaseValue修改之后触发, 当GameplayEffect对其修改时, 这就是一个处理更多Attribute操作的有效位置.
    • 例如用于AS变动的连带效应,比如伤害值作用于护盾值,当护盾值不足以抵消伤害时,便作用于生命值。
  • OnAttributeAggregatorCreated(const FGameplayAttribute& Attribute, FAggregator* NewAggregator)会在Aggregator为集合中的某个Attribute创建时触发

3.Gameplay Effects

定义GE

关于其中出现的Require Tags和Ignore Tags的更好的理解方法:把它理解为一个布尔判断器,Require为And,Ignore为Not,只有Require中的Tag全部存在,Ignore中的Tag没有一个存在时,判断通过,才可执行。

在GE中所说的parent即被应用此GE的ASC组件

  • GE是Ability修改其自身和其他AS和GameplayTag的容器, 其可以立即修改Attribute(像伤害或治疗)或应用长期的状态buff/debuff(像移动速度加速或眩晕). UGameplayEffect只是一个定义单一游戏效果的数据类, 不应该在其中添加额外的逻辑.

DurationPolicy延时策略

  • GE_DurationPolicy

  • 类型GameplayCue事件何时使用
    即刻(Instant)ExecuteAttribute中BaseValue立即进行的永久性修改. 其不会应用GameplayTag, 哪怕是一帧.
    持续(Duration)Add & RemoveAttribute中CurrentValue的临时修改和当GameplayEffect终止或手动移除时, 应用将要被移除的GameplayTag. 持续时间是在UGameplayEffect类/蓝图中明确的.
    无限(Infinite)Add & RemoveAttribute中CurrentValue的临时修改和当GameplayEffect移除时, 应用将要被移除的GameplayTag. 该类型自身永不终止且必须由某个Ability或ASC手动移除.
  • 持续(Duration)无限(Infinite)GE可以选择应用周期性的Effect, 其每过X秒(由周期定义)就应用一次ModifierExecution, 当周期性的Effect修改Attribute的BaseValue和执行GameplayCue时就被视为即刻(Instant)GameplayEffect

Modifier修改器

  • GameplayEffect通过Modifier和Execution修改Attribute

    • GE_Modifiers

      • Modifier可以修改Attribute并且是唯一可以预测性修改Attribute的方法. 一个GameplayEffect可以有0个或多个Modifier, 每个Modifier通过某个指定的操作只能修改一个Attribute.

        • ModifierOp:对属性的数值操作

        • GE_ModifierOp

        • 操作描述备注
          AddModifier指定的Attribute加上计算结果. 使用负数以实现减法操作.
          MultiplyModifier指定的Attribute乘以计算结果.对于基于百分比的修改, 确保使用Multiply操作以使其在加法操作之后.
          DivideModifier指定的Attribute除以计算结果.
          Override使用计算结果覆盖Modifier指定的Attribute.OverrideModifier会优先覆盖最后应用的Modifier得出的最终值.
      • 有四种类型的Modifier: ScalableFloat, AttributeBased, CustomCalculationClass, 和 SetByCaller, 它们全都生成一些浮点数, 用于之后基于各自的操作修改指定ModifierAttribute.

        • ModifierMagnitude:修改器的具体数值

        • GE_ModifierMagnitude

        • Modifier类型描述
          Scalable FloatFScalableFloat结构体可以指向某个横向为变量, 纵向为等级的Data Table, Scalable Float会以Ability的当前等级自动读取指定Data Table的某行值(或者在GameplayEffectSpec中重写的不同等级), 该值还可以进一步被系数处理, 如果没有指定Data Table/Row, 那么就会将其视为1, 因此该系数就可以在所有等级都硬编码为一个值.
          Attribute BasedAttribute Based Modifier将Source(GameplayEffectSpec的创建者)或Target(GameplayEffectSpec的接收者)上的CurrentValue或BaseValue视为Backing Attribute, 可以使用系数和Pre与Post系数和来修改它. Snapshotting意味着当GameplayEffectSpec创建时捕获该Attribute, 而No Snapshotting意味着当GameplayEffectSpec应用时捕获该Attribute.
          Custom Calculation ClassCustom Calculation Class为复杂的Modifier提供了最大的灵活性, 该Modifier使用了ModifierMagnitudeCalculation类, 且可以使用系数和Pre与Post系数和来处理浮点值结果.
          Set By CallerSetByCallerModifier是运行时由Ability或GameplayEffectSpec的创建者于GameplayEffect之外设置的值, 例如, 如果你想让伤害值随玩家蓄力技能的长短而变化, 那么就需要使用SetByCaller. SetByCaller本质上是存于GameplayEffectSpec中的TMap<FGameplayTag, float>, Modifier只是告知Aggregator去寻找与提供的GameplayTag相关联的SetByCaller值. Modifier使用的SetByCaller只能使用该概念的GameplayTag形式, FName形式在此处不适用. 如果Modifier被设置为SetByCaller, 但是带有正确GameplayTagSetByCallerGameplayEffectSpec中不存在, 那么游戏会抛出一个运行时错误并返回0, 这可能在Divide操作中造成问题. 参阅SetByCallers获取更多关于如何使用SetByCaller的信息.
        • Scalable Float Magnitude:根据值采样曲线值。

      • Gameplay Tags

        • GE_ModifierGameplayTags

        • 源(Source)ASC和目标(Target)ASC的标签都被GameplayEffect所捕获,

          • GameplayEffectSpec创建时, 源(Source)ASC的标签被捕获.
          • 当执行Effect时, 目标(Target)ASC的标签被捕获.
          • 当确定无限(Infinite)持续(Duration)Effect的Modifier是否满足条件可以被应用(也就是聚合器条件(Aggregator Qualify))并且过滤器已经设置时, 被捕获的标签就会和过滤器进行比对.

Immunity免疫

  • GameplayEffect可以基于GameplayTag实现免疫, 有效阻止其他GameplayEffect应用. 尽管免疫可以由Application Tag Requirements等方式有效地实现, 但是使用该系统可以在GameplayEffect被免疫阻止时提供UAbilitySystemComponent::OnImmunityBlockGameplayEffectDelegate委托(Delegate).
    • GE_Immunity
    • GrantedApplicationImmunityTags会检查源(Source)ASC(包括源Ability的AbilityTag, 如果有的话)是否包含特定的标签, 这是一种基于确定Character或源(Source)的标签对其所有GameplayEffect提供免疫的方法.
    • Granted Application Immunity Query会检查传入的GameplayEffectSpec是否与其查询条件相匹配, 从而阻止或允许其应用.比之GrantedApplicationImmunityTags功能更为强大,但是速度更慢.

Stacking叠层/堆栈

  • GE_Stacking

  • 堆栈类型描述
    Aggregate by Source目标(Target)上的每个源(Source)ASC都有一个单独的堆栈实例, 每个源(Source)可以应用堆栈中的X个GameplayEffect.
    Aggregate by Target目标(Target)上只有一个堆栈实例而不管源(Source)如何, 每个源(Source)都可以在共享堆栈限制(Shared Stack Limit)内应用堆栈.
  • Stack Duration Refresh Policy 堆栈时长刷新策略,每当有任意一个堆叠成功应用时该效果的持续时间就会被刷新.

  • Stack Period Reset Policy 堆栈周期复位策略,任意成功应用的堆叠中,任何向下个tick的

  • Stack Expiration Policy 堆栈结束策略说明
    Clear Entire Stack
    清除整个堆栈
    当GE终止时,清除整个堆栈
    Remove single stack and refresh duration
    删除单个堆栈并刷新持续时间
    当前堆栈数量减一,刷新持续时间,该GE不是被重新应用,只是继续存在,少了个堆栈
    Refresh Duration
    刷新时间
    GE的持续时间被刷新,这本质上使得GE的持续效果时无限的,可以通过OnStackCountChange手动处理堆栈递减回调

Period周期

  • Periodic Inhibition Policy 周期抑制策略

  • GE_Period

  • Never Reset 不重置周期计时将继续,不抑制
    Reset Period 重置间隔重置周期,下次执行将发生在抑制解除后的一个完整周期内
    Excute and Reset Period 执行和重置周期立即执行,重置周期

Expiration 终止

  • GE_Expiration

  • Premature Expiration Effect Classes
    过早终止应用的效果类
    该GE提前终止时将会应用的GE(强制移除forced removal,清除标签clear Tags等)只适用于有持续时间的GE
    Routine Expiration Effect Classes
    常规终止时应用的效果类
    此GE通过其持续时间自然终止时应用的GE,只适用于有持续时间的GE

Application应用

  • Chance To Apply To Target 应用至target的概率该GE应用于目标角色的概率(0为从不,1为总是)
    Application Requirement 应用的需要

Overflow溢出

  • Overflow Effects当一个堆栈效果通过其他尝试应用一个堆栈数量溢出其记数时应用的GE
    Deny Overflow Application如果为true,在堆栈记数满时进行的堆栈尝试将失败,导致持续时间和context不被刷新
    clear stack on overflow如果为true,溢出时该GE的整个堆栈将被清除

Cues 显示

  • Require Modifier Success to Trigger Cues 需要修改器成功触发GC若为true,只有当GE修改器成功应用时(无论是modifier还是execution),GC才会触发
    suppress stacking cues 阻止堆栈时触发GC若为true,GC只会在堆栈GE的首个实例中被触发
    Gameplay Cues该GE触发非模拟反应时响应的GC,如声音,粒子效果等
    UI Data该GE的UI表示的数据,这应该包括文本,图标等内容,server-only构件中不可用

Tags标签

  • combined Tags 组合标签我继承的标签和我添加的被我移除的减标签
    Added除了我的parent的标签之外我所拥有的标签
    Removed如果我的parent拥有这些标签,就应该删除
  • Gameplay Effect Asset Tag GE资产的标签该GE所拥有的标签,不给予actor
    Granted Tags 授予标签这些标签将应用于我所应用的actor
    Granted Blocked Ability Tags 授予锁定能力标签这些锁定的能力标签将应用于我所应用的actor
    Ongoing Tag Requirements 持续应用该GE的标签要求一旦应用,这些标签将用于确定GE是打开还是关闭。
    一个GE可以关闭,什么都不做,但是任然被应用
    Application Tag Requirements 应用该GE的标签要求该GE应用到目标的标签要求,这是应用时的通过/失败。如果失败,表示该GE应用失败
    Removal Tag Requirements 拆除该GE的标签要求如果满足这些标签要求将会移除该GE,也会防止GE应用
    Remove Gameplay Effect Query 删除GE查询在一个GE的应用中,任何与此查询匹配的激活的GE都将被删除。
    功能更加强大,但稍慢于Remove Gameplay Effects with Tags
    Remove Gameplay Effects with Tags
    删除带有标签的GE

Granted Abilities

  • Removal Policy 移除策略

    • Cancel Ability Immediately 立即取消能力激活的能力会被立即取消并移除
      Remove Ability on End激活的能力允许完成,然后被移除
      Do Nothing当授予的GE被移除时,授予的能力将被单独保留

应用GameplayEffect

  • GE可以被GA和ASC中的多个函数应用, 其通常是ApplyGameplayEffectTo的形式, 不同的函数本质上都是最终在目标上调用UAbilitySystemComponent::ApplyGameplayEffectSpecToSelf()的方便函数.

  • 为了在GameplayAbility之外应用GameplayEffect, 例如对于某个投掷物, 你就需要获取到目标的ASC并使用它的函数之一来ApplyGameplayEffectToSelf.

移除GameplayEffect