Gas系统笔记

Build.cs

  • showdebug abilitysystem 调试信息
1
2
3
4
5
6
7
8
9
10
11
12
13
using UnrealBuildTool;

public class MyMVCtest : ModuleRules
{
public MyMVCtest(ReadOnlyTargetRules Target) : base(Target)
{
PCHUsage = PCHUsageMode.UseExplicitOrSharedPCHs;

PublicDependencyModuleNames.AddRange(new string[] { "Core", "CoreUObject", "Engine", "InputCore","EnhancedInput", "GameplayAbilities" });

PrivateDependencyModuleNames.AddRange(new string[] { "GameplayTags", "GameplayTasks", "NavigationSystem", "Niagara", "AIModule" });
}
}
  1. Gameplay Ability (GA)

    • GA代表游戏中的技能或能力,是玩家或NPC可以执行的动作。
    • GA通常由一个或多个Ability Task(任务)组成,这些任务定义了技能的具体行为和效果。
  2. Gameplay Effect (GE)

    • GE描述了一个游戏效果,例如治疗、伤害、加攻、减速等。
    • GE可以修改玩家属性、添加其他GE、修改玩家身上的Tag或给玩家某个Cue效果。
    • GE的配置包括时效性参数(如执行时长和周期)、属性修改、修改条件、Tag属性和后处理等。
  3. Gameplay Tag (Tag)

    • Tag用于标记状态和类别,可以用来表示一个游戏对象的特性、状态、行为等信息。
    • 例如,可以用”Character.Type.Enemy”和”Character.Type.Boss”等Tag来描述敌人角色,用”Character.State.Jump”和”Character.State.Swimming”等Tag来表明对象在跳跃或游泳。
  4. Gameplay Cue (GC)

    • GC负责播放客户端表现,如特效、音效、动画、材质效果和后处理等。
    • GC可以通过DS(Data-Driven)端发起,广播到客户端,也可以直接在客户端触发。
  5. AttributeSet(属性集)

    • AttributeSet定义了角色属性,如攻击力、防御力、血量等。
    • AttributeSet是GAS系统中用于存储和管理角色属性的核心组件。
  6. Ability System Component (ASC)

    • ASC是GAS系统的管理组件,负责管理GAS模块对外接口,以及上述提到的GA、Task、GE、Tag、GC和AttributeSet等。
    • ASC提供了用于激活技能、管理游戏效果和标记等功能的接口。

官方Tga

1
2
3
4
5
6
7
8
9
10
11
//头文件
namespace FairyTag
{
UE_DECLARE_GAMEPLAY_TAG_EXTERN(Movement_Mode_Walking);
}

//源文件
namespace FairyTag
{
UE_DEFINE_GAMEPLAY_TAG_COMMENT(Movement_Mode_Walking, "Movement.Mode.Walking", "Default Character movement tag");
}

AttributeSet 属性配置

创建AttributeSet 类

  • 创建继承自AttributeSet的C++类,玩家和怪物的属性都在这里进行声明配置,如生命值魔法值等

    • 头文件
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    // Fill out your copyright notice in the Description page of Project Settings.

    #pragma once

    #include "CoreMinimal.h"
    #include "AttributeSet.h"
    #include "AbilitySystemComponent.h"
    #include "AuraAttributeSet.generated.h"


    DECLARE_DELEGATE_RetVal(FGameplayAttribute, FAttributeSignature);
    // 属性访问器
    #define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \
    GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
    GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
    GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
    GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)

    // 特殊属性
    USTRUCT()
    struct FEffectProperties
    {
    GENERATED_BODY()
    FEffectProperties(){};

    FGameplayEffectContextHandle EffectContextHandle;

    UPROPERTY()
    UAbilitySystemComponent* SourceASC = nullptr;

    UPROPERTY()
    AActor* SourceAvatarActor = nullptr;

    UPROPERTY()
    AController* SourceController = nullptr;

    UPROPERTY()
    ACharacter* SourceCharacter = nullptr;

    UPROPERTY()
    UAbilitySystemComponent* TargetASC = nullptr;

    UPROPERTY()
    AActor* TargetAvatarActor = nullptr;

    UPROPERTY()
    AController* TargetController = nullptr;

    UPROPERTY()
    ACharacter* TargetCharacter = nullptr;
    };

    template<class T>
    using TStaticFuncPtr = typename TBaseStaticDelegateInstance<T, FDefaultDelegateUserPolicy>::FFuncPtr;

    UCLASS()
    class AURADEMO_API UAuraAttributeSet : public UAttributeSet
    {
    GENERATED_BODY()
    public:
    // 构造函数
    UAuraAttributeSet();

    //复制属性
    virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
    //预处理属性,改变前调用
    virtual void PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) override;
    //后处理属性,改变后调用
    virtual void PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data) override;

    /*
    * Primary Attributes
    */
    UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Strength, Category = "Primary Attributes")
    FGameplayAttributeData Strength;
    ATTRIBUTE_ACCESSORS(UAuraAttributeSet, Strength);

    UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Intelligence, Category = "Primary Attributes")
    FGameplayAttributeData Intelligence;
    ATTRIBUTE_ACCESSORS(UAuraAttributeSet, Intelligence);

    UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Resilience, Category = "Primary Attributes")
    FGameplayAttributeData Resilience;
    ATTRIBUTE_ACCESSORS(UAuraAttributeSet, Resilience);

    UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Vigor, Category = "Primary Attributes")
    FGameplayAttributeData Vigor;
    ATTRIBUTE_ACCESSORS(UAuraAttributeSet, Vigor);


    /*
    * Secondary Attributes
    */
    UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Armor, Category = "Secondary Attributes")
    FGameplayAttributeData Armor;
    ATTRIBUTE_ACCESSORS(UAuraAttributeSet, Armor);

    UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_ArmorPenetration, Category = "Secondary Attributes")
    FGameplayAttributeData ArmorPenetration;
    ATTRIBUTE_ACCESSORS(UAuraAttributeSet, ArmorPenetration);

    UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_BlockChance, Category = "Secondary Attributes")
    FGameplayAttributeData BlockChance;
    ATTRIBUTE_ACCESSORS(UAuraAttributeSet, BlockChance);

    UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_CriticalHitChance, Category = "Secondary Attributes")
    FGameplayAttributeData CriticalHitChance;
    ATTRIBUTE_ACCESSORS(UAuraAttributeSet, CriticalHitChance);

    UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_CriticalHitDamage, Category = "Secondary Attributes")
    FGameplayAttributeData CriticalHitDamage;
    ATTRIBUTE_ACCESSORS(UAuraAttributeSet, CriticalHitDamage);

    UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_CriticalHitResistance, Category = "Secondary Attributes")
    FGameplayAttributeData CriticalHitResistance;
    ATTRIBUTE_ACCESSORS(UAuraAttributeSet, CriticalHitResistance);

    UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_HealthRegeneration, Category = "Secondary Attributes")
    FGameplayAttributeData HealthRegeneration;
    ATTRIBUTE_ACCESSORS(UAuraAttributeSet, HealthRegeneration);

    UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_ManaRegeneration, Category = "Secondary Attributes")
    FGameplayAttributeData ManaRegeneration;
    ATTRIBUTE_ACCESSORS(UAuraAttributeSet, ManaRegeneration);

    UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_MaxHealth, Category = "Vital Attributes")
    FGameplayAttributeData MaxHealth;
    ATTRIBUTE_ACCESSORS(UAuraAttributeSet, MaxHealth);

    UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_MaxMana, Category = "Vital Attributes")
    FGameplayAttributeData MaxMana;
    ATTRIBUTE_ACCESSORS(UAuraAttributeSet, MaxMana);



    /*
    * Resistance Attributes
    */
    UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_FireResistance, Category = "Resistance Attributes")
    FGameplayAttributeData FireResistance;
    ATTRIBUTE_ACCESSORS(UAuraAttributeSet, FireResistance);

    UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_LightningResistance, Category = "Resistance Attributes")
    FGameplayAttributeData LightningResistance;
    ATTRIBUTE_ACCESSORS(UAuraAttributeSet, LightningResistance);

    UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_ArcaneResistance, Category = "Resistance Attributes")
    FGameplayAttributeData ArcaneResistance;
    ATTRIBUTE_ACCESSORS(UAuraAttributeSet, ArcaneResistance);

    UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_PhysicalResistance, Category = "Resistance Attributes")
    FGameplayAttributeData PhysicalResistance;
    ATTRIBUTE_ACCESSORS(UAuraAttributeSet, PhysicalResistance);


    /*
    * Vital Attributes
    */
    UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Health, Category = "Vital Attributes")
    FGameplayAttributeData Health;
    ATTRIBUTE_ACCESSORS(UAuraAttributeSet, Health);

    UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Mana, Category = "Vital Attributes")
    FGameplayAttributeData Mana;
    ATTRIBUTE_ACCESSORS(UAuraAttributeSet, Mana);

    /*
    * Meta Attributes
    */
    UPROPERTY(BlueprintReadOnly, Category = "Meta Attributes")
    FGameplayAttributeData IncomingDamage;
    ATTRIBUTE_ACCESSORS(UAuraAttributeSet, IncomingDamage);

    UPROPERTY(BlueprintReadOnly, Category = "Meta Attributes")
    FGameplayAttributeData IncomingXP;
    ATTRIBUTE_ACCESSORS(UAuraAttributeSet, IncomingXP);

    UFUNCTION()
    void OnRep_Health(const FGameplayAttributeData& OldHealth) const;

    UFUNCTION()
    void OnRep_Mana(const FGameplayAttributeData& OldMana) const;

    UFUNCTION()
    void OnRep_Strength(const FGameplayAttributeData& OldStrength) const;

    UFUNCTION()
    void OnRep_Intelligence(const FGameplayAttributeData& OldIntelligence) const;

    UFUNCTION()
    void OnRep_Resilience(const FGameplayAttributeData& OldResilience) const;

    UFUNCTION()
    void OnRep_Vigor(const FGameplayAttributeData& OldVigor) const;

    UFUNCTION()
    void OnRep_Armor(const FGameplayAttributeData& OldArmor) const;

    UFUNCTION()
    void OnRep_ArmorPenetration(const FGameplayAttributeData& OldArmorPenetration) const;

    UFUNCTION()
    void OnRep_BlockChance(const FGameplayAttributeData& OldBlockChance) const;

    UFUNCTION()
    void OnRep_CriticalHitChance(const FGameplayAttributeData& OldCriticalHitChance) const;

    UFUNCTION()
    void OnRep_CriticalHitDamage(const FGameplayAttributeData& OldCriticalHitDamage) const;

    UFUNCTION()
    void OnRep_CriticalHitResistance(const FGameplayAttributeData& OldCriticalHitResistance) const;

    UFUNCTION()
    void OnRep_HealthRegeneration(const FGameplayAttributeData& OldHealthRegeneration) const;

    UFUNCTION()
    void OnRep_ManaRegeneration(const FGameplayAttributeData& OldManaRegeneration) const;

    UFUNCTION()
    void OnRep_MaxHealth(const FGameplayAttributeData& OldMaxHealth) const;

    UFUNCTION()
    void OnRep_MaxMana(const FGameplayAttributeData& OldMaxMana) const;

    UFUNCTION()
    void OnRep_FireResistance(const FGameplayAttributeData& OldFireResistance) const;

    UFUNCTION()
    void OnRep_LightningResistance(const FGameplayAttributeData& OldLightningResistance) const;

    UFUNCTION()
    void OnRep_ArcaneResistance(const FGameplayAttributeData& OldArcaneResistance) const;

    UFUNCTION()
    void OnRep_PhysicalResistance(const FGameplayAttributeData& OldPhysicalResistance) const;

    private:
    // 设置效果属性
    void SetEffectProperties(const FGameplayEffectModCallbackData& Data, FEffectProperties& Props) const;
    public:
    //标签委托字典
    // TMap<FGameplayTag, FAttributeSignature> TagsToAttributes;
    //TMap<FGameplayTag, FGameplayAttribute(*)()> TagsToAttributes;
    TMap<FGameplayTag, TStaticFuncPtr<FGameplayAttribute()>> TagsToAttributes;

    };

    • 源文件
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
    110
    111
    112
    113
    114
    115
    116
    117
    118
    119
    120
    121
    122
    123
    124
    125
    126
    127
    128
    129
    130
    131
    132
    133
    134
    135
    136
    137
    138
    139
    140
    141
    142
    143
    144
    145
    146
    147
    148
    149
    150
    151
    152
    153
    154
    155
    156
    157
    158
    159
    160
    161
    162
    163
    164
    165
    166
    167
    168
    169
    170
    171
    172
    173
    174
    175
    176
    177
    178
    179
    180
    181
    182
    183
    184
    185
    186
    187
    188
    189
    190
    191
    192
    193
    194
    195
    196
    197
    198
    199
    200
    201
    202
    203
    204
    205
    206
    207
    208
    209
    210
    211
    212
    213
    214
    215
    216
    217
    218
    219
    220
    221
    222
    223
    224
    225
    226
    227
    228
    229
    230
    231
    232
    233
    234
    235
    236
    237
    238
    239
    240
    241
    242
    243
    244
    245
    246
    247
    248
    249
    250
    251
    252
    253
    254
    // Fill out your copyright notice in the Description page of Project Settings.


    #include "AbilitySystem/AuraAttributeSet.h"
    #include "AbilitySystemBlueprintLibrary.h"
    #include "GameplayEffectExtension.h"
    #include "AbilitySystem/GameplayTags/AuraGameplayTags.h"
    #include "GameFramework/Character.h"
    #include "Net/UnrealNetwork.h"
    #include "UI/WidgetController/AttributeMenuWidgetController.h"
    //GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, Health, OldHealth);
    UAuraAttributeSet::UAuraAttributeSet()
    {
    //获取标签结构体
    const FAuraGameplayTags& GameplayTags = FAuraGameplayTags::Get();

    /* Primary Attributes */
    TagsToAttributes.Add(GameplayTags.Attributes_Primary_Strength, GetStrengthAttribute);
    TagsToAttributes.Add(GameplayTags.Attributes_Primary_Intelligence, GetIntelligenceAttribute);
    TagsToAttributes.Add(GameplayTags.Attributes_Primary_Resilience, GetResilienceAttribute);
    TagsToAttributes.Add(GameplayTags.Attributes_Primary_Vigor, GetVigorAttribute);

    /* Secondary Attributes */
    TagsToAttributes.Add(GameplayTags.Attributes_Secondary_Armor, GetArmorAttribute);
    TagsToAttributes.Add(GameplayTags.Attributes_Secondary_ArmorPenetration, GetArmorPenetrationAttribute);
    TagsToAttributes.Add(GameplayTags.Attributes_Secondary_BlockChance, GetBlockChanceAttribute);
    TagsToAttributes.Add(GameplayTags.Attributes_Secondary_CriticalHitChance, GetCriticalHitChanceAttribute);
    TagsToAttributes.Add(GameplayTags.Attributes_Secondary_CriticalHitResistance, GetCriticalHitResistanceAttribute);
    TagsToAttributes.Add(GameplayTags.Attributes_Secondary_CriticalHitDamage, GetCriticalHitDamageAttribute);
    TagsToAttributes.Add(GameplayTags.Attributes_Secondary_HealthRegeneration, GetHealthRegenerationAttribute);
    TagsToAttributes.Add(GameplayTags.Attributes_Secondary_ManaRegeneration, GetManaRegenerationAttribute);
    TagsToAttributes.Add(GameplayTags.Attributes_Secondary_MaxHealth, GetMaxHealthAttribute);
    TagsToAttributes.Add(GameplayTags.Attributes_Secondary_MaxMana, GetMaxManaAttribute);

    /* Resistance Attributes */
    // TagsToAttributes.Add(GameplayTags.Attributes_Resistance_Arcane, GetArcaneResistanceAttribute);
    // TagsToAttributes.Add(GameplayTags.Attributes_Resistance_Fire, GetFireResistanceAttribute);
    // TagsToAttributes.Add(GameplayTags.Attributes_Resistance_Lightning, GetLightningResistanceAttribute);
    // TagsToAttributes.Add(GameplayTags.Attributes_Resistance_Physical, GetPhysicalResistanceAttribute);

    }

    void UAuraAttributeSet::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
    {
    Super::GetLifetimeReplicatedProps(OutLifetimeProps);

    // Primary Attributes

    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, Strength, COND_None, REPNOTIFY_Always);
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, Intelligence, COND_None, REPNOTIFY_Always);
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, Resilience, COND_None, REPNOTIFY_Always);
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, Vigor, COND_None, REPNOTIFY_Always);

    // Secondary Attributes

    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, Armor, COND_None, REPNOTIFY_Always);
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, ArmorPenetration, COND_None, REPNOTIFY_Always);
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, BlockChance, COND_None, REPNOTIFY_Always);
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, CriticalHitChance, COND_None, REPNOTIFY_Always);
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, CriticalHitDamage, COND_None, REPNOTIFY_Always);
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, CriticalHitResistance, COND_None, REPNOTIFY_Always);
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, HealthRegeneration, COND_None, REPNOTIFY_Always);
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, ManaRegeneration, COND_None, REPNOTIFY_Always);
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, MaxHealth, COND_None, REPNOTIFY_Always);
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, MaxMana, COND_None, REPNOTIFY_Always);

    // Resistance Attributes

    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, FireResistance, COND_None, REPNOTIFY_Always);
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, LightningResistance, COND_None, REPNOTIFY_Always);
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, ArcaneResistance, COND_None, REPNOTIFY_Always);
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, PhysicalResistance, COND_None, REPNOTIFY_Always);

    // Vital Attributes

    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, Health, COND_None, REPNOTIFY_Always);
    DOREPLIFETIME_CONDITION_NOTIFY(UAuraAttributeSet, Mana, COND_None, REPNOTIFY_Always);
    }

    //属性改变前调用,限制最大值
    void UAuraAttributeSet::PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue)
    {
    Super::PreAttributeChange(Attribute, NewValue);
    if(Attribute == GetHealthAttribute())
    {
    NewValue = FMath::Clamp(NewValue, 0.f, GetMaxHealth());
    }
    if(Attribute == GetManaAttribute())
    {
    NewValue = FMath::Clamp(NewValue, 0.f, GetMaxMana());
    }
    }
    //属性改变后调用,用于限制属性最大值
    void UAuraAttributeSet::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
    {
    Super::PostGameplayEffectExecute(Data);
    FEffectProperties Props;
    SetEffectProperties(Data, Props);

    // if(Props.TargetCharacter->Implements<UCombatInterface>() && ICombatInterface::Execute_IsDead(Props.TargetCharacter)) return;

    if (Data.EvaluatedData.Attribute == GetHealthAttribute())
    {
    SetHealth(FMath::Clamp(GetHealth(), 0.f, GetMaxHealth()));
    }
    if (Data.EvaluatedData.Attribute == GetManaAttribute())
    {
    SetMana(FMath::Clamp(GetMana(), 0.f, GetMaxMana()));
    }
    }

    //设置效果属性,在属性集类改变属性后调用
    void UAuraAttributeSet::SetEffectProperties(const FGameplayEffectModCallbackData& Data, FEffectProperties& Props) const
    {
    //结构体设置效果上下文
    Props.EffectContextHandle = Data.EffectSpec.GetContext();
    //结构体设置能力系统组件
    Props.SourceASC = Props.EffectContextHandle.GetOriginalInstigatorAbilitySystemComponent();

    //如果能力组件有效和角色有效
    if (IsValid(Props.SourceASC) && Props.SourceASC->AbilityActorInfo.IsValid() && Props.SourceASC->AbilityActorInfo->AvatarActor.IsValid())
    {
    Props.SourceAvatarActor = Props.SourceASC->AbilityActorInfo->AvatarActor.Get();
    Props.SourceController = Props.SourceASC->AbilityActorInfo->PlayerController.Get();

    // 如果角色无效,则从角色中获取
    if (Props.SourceController == nullptr && Props.SourceAvatarActor != nullptr)
    {
    if (const APawn* Pawn = Cast<APawn>(Props.SourceAvatarActor))
    {
    Props.SourceController = Pawn->GetController();
    }
    }
    // 如果角色有效,则从角色中获取
    if (Props.SourceController)
    {
    Props.SourceCharacter = Cast<ACharacter>(Props.SourceController->GetPawn());
    }
    }

    //如果目标有效和角色有效
    if (Data.Target.AbilityActorInfo.IsValid() && Data.Target.AbilityActorInfo->AvatarActor.IsValid())
    {
    Props.TargetAvatarActor = Data.Target.AbilityActorInfo->AvatarActor.Get();
    Props.TargetController = Data.Target.AbilityActorInfo->PlayerController.Get();
    Props.TargetCharacter = Cast<ACharacter>(Props.TargetAvatarActor);
    Props.TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(Props.TargetAvatarActor);
    }
    }


    void UAuraAttributeSet::OnRep_Health(const FGameplayAttributeData& OldHealth) const
    {
    GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, Health, OldHealth);
    }

    void UAuraAttributeSet::OnRep_Mana(const FGameplayAttributeData& OldMana) const
    {
    GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, Mana, OldMana);
    }

    void UAuraAttributeSet::OnRep_Strength(const FGameplayAttributeData& OldStrength) const
    {
    GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, Strength, OldStrength);
    }

    void UAuraAttributeSet::OnRep_Intelligence(const FGameplayAttributeData& OldIntelligence) const
    {
    GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, Intelligence, OldIntelligence);
    }

    void UAuraAttributeSet::OnRep_Resilience(const FGameplayAttributeData& OldResilience) const
    {
    GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, Resilience, OldResilience);
    }

    void UAuraAttributeSet::OnRep_Vigor(const FGameplayAttributeData& OldVigor) const
    {
    GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, Vigor, OldVigor);
    }

    void UAuraAttributeSet::OnRep_Armor(const FGameplayAttributeData& OldArmor) const
    {
    GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, Armor, OldArmor);
    }

    void UAuraAttributeSet::OnRep_ArmorPenetration(const FGameplayAttributeData& OldArmorPenetration) const
    {
    GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, ArmorPenetration, OldArmorPenetration);
    }

    void UAuraAttributeSet::OnRep_BlockChance(const FGameplayAttributeData& OldBlockChance) const
    {
    GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, BlockChance, OldBlockChance);
    }

    void UAuraAttributeSet::OnRep_CriticalHitChance(const FGameplayAttributeData& OldCriticalHitChance) const
    {
    GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, CriticalHitChance, OldCriticalHitChance);
    }

    void UAuraAttributeSet::OnRep_CriticalHitDamage(const FGameplayAttributeData& OldCriticalHitDamage) const
    {
    GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, CriticalHitDamage, OldCriticalHitDamage);
    }

    void UAuraAttributeSet::OnRep_CriticalHitResistance(const FGameplayAttributeData& OldCriticalHitResistance) const
    {
    GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, CriticalHitResistance, OldCriticalHitResistance);
    }

    void UAuraAttributeSet::OnRep_HealthRegeneration(const FGameplayAttributeData& OldHealthRegeneration) const
    {
    GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, HealthRegeneration, OldHealthRegeneration);
    }

    void UAuraAttributeSet::OnRep_ManaRegeneration(const FGameplayAttributeData& OldManaRegeneration) const
    {
    GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, ManaRegeneration, OldManaRegeneration);
    }

    void UAuraAttributeSet::OnRep_MaxHealth(const FGameplayAttributeData& OldMaxHealth) const
    {
    GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, MaxHealth, OldMaxHealth);
    }

    void UAuraAttributeSet::OnRep_MaxMana(const FGameplayAttributeData& OldMaxMana) const
    {
    GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, MaxMana, OldMaxMana);
    }

    void UAuraAttributeSet::OnRep_FireResistance(const FGameplayAttributeData& OldFireResistance) const
    {
    GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, FireResistance, OldFireResistance);
    }

    void UAuraAttributeSet::OnRep_LightningResistance(const FGameplayAttributeData& OldLightningResistance) const
    {
    GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, LightningResistance, OldLightningResistance);
    }

    void UAuraAttributeSet::OnRep_ArcaneResistance(const FGameplayAttributeData& OldArcaneResistance) const
    {
    GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, ArcaneResistance, OldArcaneResistance);
    }

    void UAuraAttributeSet::OnRep_PhysicalResistance(const FGameplayAttributeData& OldPhysicalResistance) const
    {
    GAMEPLAYATTRIBUTE_REPNOTIFY(UAuraAttributeSet, PhysicalResistance, OldPhysicalResistance);
    }




源码说明

  • 头文件

    1
    `#include "AbilitySystemComponent.h"`组件头文件,需要使用AbilitySystemComponent类必须加载该头文件
  • 宏定义用于自动生成类属性的访问器方法

    命名规范:确保宏中的方法名称符合项目的命名规范。
    线程安全:如果属性在多线程环境中使用,考虑添加必要的同步机制。
    性能优化:对于频繁访问的属性,可以考虑使用内联函数以提高性能。
    通过这种方式,可以大大简化属性访问器的编写,提高代码的可维护性和一致性。

1
2
3
4
5
6
//ATTRIBUTE_ACCESSORS 宏定义用于自动生成类属性的访问器方法
#define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \ //生成一个获取属性的方法,通常返回属性的引用或值
GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \ //生成一个获取属性值的方法,通常返回属性的值
GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \ //生成一个设置属性值的方法,通常接受一个参数并更新属性的值。
GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName) //生成一个初始化属性值的方法,通常用于在构造函数或其他初始化方法中设置属性的初始值

​ 假设我们有一个类 Character,并且希望为属性 Health 生成访问器方法,可以这样使用宏:

1
2
3
4
5
6
7
8
9
class Character
{
public:
// 使用宏生成访问器方法
ATTRIBUTE_ACCESSORS(Character, Health)

private:
float Health;
};

​ 展开后的代码
​ 宏展开后,生成的代码可能类似于以下内容:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
class Character
{
public:
// 获取属性的方法
float& GetHealth() { return Health; }
const float& GetHealth() const { return Health; }

// 获取属性值的方法
float GetHealthValue() const { return Health; }

// 设置属性值的方法
void SetHealthValue(float NewValue) { Health = NewValue; }

// 初始化属性值的方法
void InitHealthValue(float InitialValue) { Health = InitialValue; }

private:
float Health;
};

在玩家类中初始化

  • 因为玩家角色在游戏中死亡会被销毁释放,属性也会跟着被释放掉,为了避免这种情况,我们需要将玩家属性和玩家分开,我们可以通过PlayerState类配置玩家的属性,玩家再从PlayerState类里获取属性,这样即使玩家被释放了复活后依旧可以从这里获取属性

  • 新建一个继承自PlayerState的类StestPlayerState

  • StestPlayerState源码如下

    • 头文件
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    #pragma once

    #include "CoreMinimal.h"
    #include "AbilitySystemInterface.h"
    #include "GameFramework/PlayerState.h"
    #include "StestPlayerState.generated.h"

    //前向声明
    class UAbilitySystemComponent;
    class UAttributeSet;
    UCLASS()
    class GASDEMO_API AStestPlayerState : public APlayerState,public IAbilitySystemInterface
    {
    GENERATED_BODY()
    public:
    AStestPlayerState();
    //重写组件虚函数
    virtual UAbilitySystemComponent* GetAbilitySystemComponent() const override;
    //AttributeSet,属于AbilitySystemComponent
    UAttributeSet* GetAttributeSet() const { return AttributeSet; }
    protected:

    UPROPERTY()
    //指向UAbilitySystemComponent的智能指针,用于管理玩家的能力和效果。
    TObjectPtr<UAbilitySystemComponent> AbilitySystemComponent;

    UPROPERTY()
    //指向UAttributeSet的智能指针,用于存储玩家的属性值,如生命值、魔法值等
    TObjectPtr<UAttributeSet> AttributeSet;
    };
    • 源文件
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    #include "Player/StestPlayerState.h"
    #include "AbilitySystem/AuraAbilitySystemComponent.h"
    #include "AbilitySystem/AuraAttributeSet.h"

    AStestPlayerState::AStestPlayerState()
    {
    //创建能力组件
    AbilitySystemComponent = CreateDefaultSubobject<UAuraAbilitySystemComponent>("AbilitySystemComponent");
    AbilitySystemComponent->SetIsReplicated(true);
    AbilitySystemComponent->SetReplicationMode(EGameplayEffectReplicationMode::Mixed);
    AttributeSet = CreateDefaultSubobject<UAuraAttributeSet>("AttributeSet");

    //这段C++代码是Unreal Engine中的一部分,用于设置一个玩家状态(AStestPlayerState)的网络更新频率
    NetUpdateFrequency=100.f;
    }
    //接口继承的方法,返回AbilitySystemComponent
    UAbilitySystemComponent* AStestPlayerState::GetAbilitySystemComponent() const
    {
    return AbilitySystemComponent;
    }
  • 角色基类源码如下,因为怪物和玩家都有能力组件,所以创建一个角色基类,玩家和怪物都继承自这个类,他们都有能力组件,不过初始化需要分开在子类中初始化,因为玩家的属性是分离的,怪物的不是。注:记得前向声明

    • 头文件
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    #pragma once

    #include "CoreMinimal.h"
    #include "GameFramework/Character.h"
    #include "AbilitySystemInterface.h"
    #include "AuraCharacterBase.generated.h"

    class UAbilitySystemComponent;
    class UAttributeSet;

    UCLASS()
    class AURADEMO_API AAuraCharacterBase : public ACharacter,public IAbilitySystemInterface
    {
    GENERATED_BODY()

    public:
    AAuraCharacterBase();

    virtual UAbilitySystemComponent* GetAbilitySystemComponent() const override;
    UAttributeSet* GetAttributeSet() const { return AttributeSet; };

    protected:
    virtual void BeginPlay() override;

    //玩家能力组件AbilitySystemComponent
    UPROPERTY()
    TObjectPtr<UAbilitySystemComponent> AbilitySystemComponent;
    //玩家属性组件AttributeSet
    UPROPERTY()
    TObjectPtr<UAttributeSet> AttributeSet;
    };
    • 源文件
    1
    2
    3
    4
    UAbilitySystemComponent* AAuraCharacterBase::GetAbilitySystemComponent() const
    {
    return AbilitySystemComponent;
    }
  • 玩家源码,继承自角色基类

    • 头文件
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    #pragma once

    #include "CoreMinimal.h"
    #include "AuraCharacterBase.h"
    #include "AuraCharacter.generated.h"

    UCLASS()
    class AURADEMO_API AAuraCharacter : public AAuraCharacterBase
    {
    GENERATED_BODY()
    public:
    virtual void PossessedBy(AController* NewController) override;
    //网络同步相关
    virtual void OnRep_PlayerState() override;
    private:
    void InitAbilityActorInfo();

    };
    • 源文件
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    #include "Character/AuraCharacter.h"
    #include "AbilitySystem/AuraAbilitySystemComponent.h"
    #include "Player/AuraPlayerState.h"

    void AAuraCharacter::PossessedBy(AController* NewController)
    {
    Super::PossessedBy(NewController);
    InitAbilityActorInfo();
    }

    void AAuraCharacter::OnRep_PlayerState()
    {
    Super::OnRep_PlayerState();
    InitAbilityActorInfo();
    }

    void AAuraCharacter::InitAbilityActorInfo()
    {
    //获取玩家状态单例
    AAuraPlayerState* AuraPlayerState = GetPlayerState<AAuraPlayerState>();
    check(AuraPlayerState);

    // 这行代码的作用是初始化 AbilitySystemComponent 的 Actor 信息。
    // 具体来说,它将 AuraPlayerState 和 当前对象 (this) 作为参数传递给 InitAbilityActorInfo 方法。
    AuraPlayerState->GetAbilitySystemComponent()->InitAbilityActorInfo(AuraPlayerState, this); //如果是怪物则AuraPlayerState改为this

    Cast<UAuraAbilitySystemComponent>(AuraPlayerState->GetAbilitySystemComponent())->AbilityActorInfoSet();//绑定委托,未实现

    //将玩玩家的属性和能力设置为玩家状态单例的属性和能力
    AbilitySystemComponent = AuraPlayerState->GetAbilitySystemComponent();
    AttributeSet = AuraPlayerState->GetAttributeSet();
    }

初始化方法

Intstats 在能力组件中通过数据表格初始化

在AttributeSet中构造函数初始化:适用于静态初始化,通常在类定义时使用。

1
2
3
4
5
6
7
    UMyAttributeSet::UMyAttributeSet()
{
InitHealth(100.f);
InitMaxHealth(100.f);
InitMana(50.f);
InitMaxMana(50.f);
}

InitFromStruct 方法:适用于从结构体中初始化属性。自定义

1
2
3
4
5
6
7
void UMyAttributeSet::InitFromStruct(const FGameplayAttributeData& Data)
{
Health = Data.Health;
MaxHealth = Data.MaxHealth;
Mana = Data.Mana;
MaxMana = Data.MaxMana;
}

PostGameplayEffectExecute 方法:适用于在应用游戏效果时动态更新属性。

1
2
3
4
5
6
7
8
9
10
11
void UMyAttributeSet::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
{
Super::PostGameplayEffectExecute(Data);

// 根据游戏效果的数据来更新属性
if (Data.EvaluatedData.Attribute == GetHealthAttribute())
{
SetHealth(FMath::Clamp(Data.EvaluatedData.Value, 0.0f, GetMaxHealth()));
}
}

OnRep_ 函数:适用于在网络复制属性后进行初始化或更新。

1
2
3
4
5
6
7
8
9
UPROPERTY(Replicated, BlueprintReadWrite, Category = "Attributes")
float Health;

void UMyAttributeSet::OnRep_Health()
{
// 在属性网络复制后进行初始化或更新
// 例如,触发事件或更新 UI
}

API

虚函数

虚函数 说明
virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; 获取需要在网络上传输的属性
virtual void PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) override; 在属性值变化前调用的回调函数
virtual void PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data) override; 在游戏效果执行后调用的回调函数

属性函数

函数 说明
OnRep 属性变化回调
Clamp 限制最大值NewValue = FMath::Clamp(NewValue, 0.f, GetMaxHealth());

MVC

  • 数据层
  • Widget 主要函数(设置控制器),(设置控制器时发出蓝图事件)是要控件都继承该类
  • HUD:,初始化控制层,拥有控制层实例,并提供获取控制层的方法

控制层

  • 继承自UObject 在HUD创建实例
  • 拥有玩家控制器,玩家状态,玩家能力组件,玩家属性集(用结构体获取这些对象)
  • 拥有两个虚函数,在HUD里调用,分别为初始化属性和绑定属性回调,还有匿名通知捡起物品
  • Widget从HUD获取控制层,当Widget获取到控制层时会发出事件给自己

派生子类Overlay

  • 负责更新血量和通知捡到物品

派生子类Attrib

  • 用了函数库,可以全局获取到控制层

  • 负责同步属性面板

Widget代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "AuraUserWidget.generated.h"

// 用户界面基类
UCLASS()
class AURADEMO_API UAuraUserWidget : public UUserWidget
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable)
void SetWidgetController(UObject* InWidgetController);

UPROPERTY(BlueprintReadOnly)
TObjectPtr<UObject> WidgetController;
protected:
//事件
UFUNCTION(BlueprintImplementableEvent)
void WidgetControllerSet();
};

1
2
3
4
5
6
7
8
9
10
11
12
13
// Fill out your copyright notice in the Description page of Project Settings.


#include "UI/Widget/AuraUserWidget.h"

void UAuraUserWidget::SetWidgetController(UObject* InWidgetController)
{
// 将传入的Widget控制器对象赋值给类成员变量WidgetController
WidgetController = InWidgetController;
// 调用WidgetControllerSet函数,通知已经设置了Widget控制器对象
WidgetControllerSet();
}

HUD代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/HUD.h"
#include "UI/Widget/AuraUserWidget.h"
#include "UI/WidgetController/AuraWidgetController.h"
#include "AuraHUD.generated.h"

class UOverlayWidgetController;
class UAuraUserWidget;
class UAttributeSet;
struct FWidgetControllerParame;

//玩家HUD,负责创建覆盖控件和绑定控制器
UCLASS(Blueprintable, BlueprintType)
class AURADEMO_API AAuraHUD : public AHUD
{
GENERATED_BODY()
public:
//覆盖控件
UPROPERTY()
TObjectPtr<UAuraUserWidget> OverlayWidget;

//通过结构体创建或者获取控制器
UOverlayWidgetController *GetOverlayWidgetController(const FWidgetControllerParame& WCParams);

// 初始化控制器数据
UFUNCTION(BlueprintCallable)
void InitOverlay(APlayerController* PC, APlayerState* PS, UAbilitySystemComponent* ASC, UAttributeSet* AS);
private:
//覆盖控件类引用
UPROPERTY(EditAnywhere)
TSubclassOf<UAuraUserWidget> OverlayWidgetClass;

//控制器实例指针
UPROPERTY()
TObjectPtr<UOverlayWidgetController> OverlayWidgetController;

//控制器类引用
UPROPERTY(EditAnywhere)
TSubclassOf<UOverlayWidgetController> OverlayWidgetControllerClass;



public:
//*面板属性**//
UAttributeMenuWidgetController* GetAttributeMenuWidgetController(const FWidgetControllerParame& WCParams);
UPROPERTY()
TObjectPtr<UAttributeMenuWidgetController> AttributeMenuWidgetController;
UPROPERTY(EditAnywhere)
TSubclassOf<UAttributeMenuWidgetController> AttributeMenuWidgetControllerClass;


};

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// Fill out your copyright notice in the Description page of Project Settings.


#include "UI/HUD/AuraHUD.h"

#include "UI/WidgetController/AttributeMenuWidgetController.h"
#include "UI/WidgetController/OverlayWidgetController.h"


UOverlayWidgetController* AAuraHUD::GetOverlayWidgetController(const FWidgetControllerParame& WCParams)
{
if(OverlayWidgetController == nullptr)
{
OverlayWidgetController = NewObject<UOverlayWidgetController>(this, OverlayWidgetControllerClass);

// 设置参数
OverlayWidgetController->SetWidgetControllerParams(WCParams);
// 绑定回调
OverlayWidgetController->BindCallbacksToDependencies();
}
return OverlayWidgetController;
}

void AAuraHUD::InitOverlay(APlayerController* PC, APlayerState* PS, UAbilitySystemComponent* ASC, UAttributeSet* AS)
{
//判断控制器类类引用和状态UI类引用是否有效
checkf(OverlayWidgetClass, TEXT("OverlayWidgetClass is nullptr"))
checkf(OverlayWidgetControllerClass, TEXT("OverlayWidgetControllerClass is nullptr"))

//创建覆盖控件
UUserWidget * Widget = CreateWidget<UUserWidget>(GetWorld(), OverlayWidgetClass);
OverlayWidget= Cast<UAuraUserWidget>(Widget);

//创建结构体并将参数构造
const FWidgetControllerParame FWidgetControllerParame = {PC, PS, ASC, AS};
//获取OverlayWidgetController
UOverlayWidgetController * WidgetController = GetOverlayWidgetController(FWidgetControllerParame);

//设置覆盖控件的控制器,发出事件
OverlayWidget->SetWidgetController(WidgetController); //设置用户控件的控制层
WidgetController->BroadcastInitialValues(); //初始化广播的值,在所以UI绑定后调用一次

//添加到视口
Widget->AddToViewport();
}

UAttributeMenuWidgetController* AAuraHUD::GetAttributeMenuWidgetController(const FWidgetControllerParame& WCParams)
{
if(AttributeMenuWidgetController == nullptr)
{
AttributeMenuWidgetController = NewObject<UAttributeMenuWidgetController>(this, AttributeMenuWidgetControllerClass);
AttributeMenuWidgetController->SetWidgetControllerParams(WCParams);
AttributeMenuWidgetController->BindCallbacksToDependencies(); //绑定监听数值变化
}
return AttributeMenuWidgetController;
}

控制层代码

基类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "AuraWidgetController.generated.h"

class UAttributeSet;
class UAbilitySystemComponent;
class UAbilitySystemComponent;

//存储玩家控制器、玩家状态、能力组件、属性集的结构体
USTRUCT(BlueprintType)
struct FWidgetControllerParame
{
GENERATED_BODY()

FWidgetControllerParame(){};
FWidgetControllerParame(APlayerController* PC, APlayerState* PS, UAbilitySystemComponent* InAbiliASCtySystemComponent, UAttributeSet* AS)
: PlayerController(PC), PlayerState(PS), AbilitySystemComponent(InAbiliASCtySystemComponent), AttributeSet(AS)
{
}

UPROPERTY(EditAnywhere, BlueprintReadWrite)
TObjectPtr<APlayerController> PlayerController=nullptr;

UPROPERTY(EditAnywhere, BlueprintReadWrite)
TObjectPtr<APlayerState> PlayerState=nullptr;

UPROPERTY(EditAnywhere, BlueprintReadWrite)
TObjectPtr<UAbilitySystemComponent> AbilitySystemComponent=nullptr;

UPROPERTY(EditAnywhere, BlueprintReadWrite)
TObjectPtr<UAttributeSet> AttributeSet=nullptr;

};



//控制器基类
UCLASS()
class AURADEMO_API UAuraWidgetController : public UObject
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintCallable)
void SetWidgetControllerParams(const FWidgetControllerParame& WCParams);

// 初始化属性(在HUD调用)
virtual void BroadcastInitialValues();
// 绑定回调(在HUD调用)
virtual void BindCallbacksToDependencies();
protected:

/*获取对象数据*/
//获取玩家控制器
UPROPERTY(BlueprintReadOnly, Category="WidgetController")
TObjectPtr<APlayerController> PlayerController;

//获取玩家状态
UPROPERTY(BlueprintReadOnly, Category="WidgetController")
TObjectPtr<APlayerState> PlayerState;

//获取能力组件
UPROPERTY(BlueprintReadOnly, Category="WidgetController")
TObjectPtr<UAbilitySystemComponent> AbilitySystemComponent;

//获取属性集
UPROPERTY(BlueprintReadOnly, Category="WidgetController")
TObjectPtr<UAttributeSet> AttributeSet;
public:


};

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// Fill out your copyright notice in the Description page of Project Settings.


#include "UI/WidgetController/AuraWidgetController.h"

void UAuraWidgetController::SetWidgetControllerParams(const FWidgetControllerParame& WCParams)
{
PlayerController = WCParams.PlayerController;
PlayerState = WCParams.PlayerState;
AbilitySystemComponent = WCParams.AbilitySystemComponent;
AttributeSet = WCParams.AttributeSet;
}

void UAuraWidgetController::BroadcastInitialValues()
{
}

void UAuraWidgetController::BindCallbacksToDependencies()
{
}

生命值/魔法值子类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameplayTagContainer.h"
#include "UI/WidgetController/AuraWidgetController.h"
#include "OverlayWidgetController.generated.h"


//根据传入的表格和Tag返回查找到的数据,表格类型不确定,所以使用T来表示,在使用此函数时,需要指定对应类型
template<typename T>
T* GetDataTableRowByTag(UDataTable* DataTable, const FGameplayTag& Tag);

template <typename T>
T* GetDataTableRowByTag(UDataTable* DataTable, const FGameplayTag& Tag)
{
T* Row = DataTable->FindRow<T>(Tag.GetTagName(), TEXT(""));
return Row;
}

//捡到物品的结构
USTRUCT(BlueprintType)
struct FUIWidgetRow : public FTableRowBase
{
GENERATED_BODY();

UPROPERTY(EditAnywhere, BlueprintReadOnly)
FGameplayTag MessageTag = FGameplayTag();

UPROPERTY(EditAnywhere, BlueprintReadOnly)
FText Message = FText();

UPROPERTY(EditAnywhere, BlueprintReadOnly)
TSubclassOf<class UAuraUserWidget> MessageWidget;

UPROPERTY(EditAnywhere, BlueprintReadOnly)
UTexture2D* Image = nullptr;
};

struct FOnAttributeChangeData;
//生命值改变时发出通知
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnHealtChangedSignature, float, NewHealt);
//最大生命值改变时发出通知
// DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnMaxHealtChangedSignature,float , NewMaxHealt);
// DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnManaChangedSignature, float, NewMana);
// DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnMaxManaChangedSignature,float , NewMaxMana);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnAttributeChangedSignature, float, NewAttribute);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FMessageWidgetRowSignature, FUIWidgetRow, Row);

// 覆盖层控制器子类
UCLASS(Blueprintable,BlueprintType)
class AURADEMO_API UOverlayWidgetController : public UAuraWidgetController
{
GENERATED_BODY()

public:
//当属性改变时发出通知
virtual void BroadcastInitialValues() override;
//当属性改变时绑定回调
virtual void BindCallbacksToDependencies() override;

//事件:生命值改变时发出
UPROPERTY(BlueprintAssignable, Category = "GAS|Attributes")
FOnHealtChangedSignature OnHealtChanged;

//事件:声明最大值改变时发出
UPROPERTY(BlueprintAssignable, Category = "GAS|Attributes")
FOnAttributeChangedSignature OnMaxHealtChanged;

UPROPERTY(BlueprintAssignable, Category = "GAS|Attributes")
FOnAttributeChangedSignature OnManaChanged;

UPROPERTY(BlueprintAssignable, Category = "GAS|Attributes")
FOnAttributeChangedSignature OnMaxManaChanged;

UPROPERTY(BlueprintAssignable, Category="GAS|Messages")
FMessageWidgetRowSignature MessageWidgetRowDelegate;

//EditDefaultsOnly 说明此属性可以通过属性窗口编辑,但只能在原型上进行。
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Widget Data")
TObjectPtr<UDataTable> MessageWidgetDataTable;

protected:
// 生命值改变时发出
void HealthChanged(const FOnAttributeChangeData& Data) const;
// 最大生命值改变时发出
void MaxHealthChanged(const FOnAttributeChangeData& Data) const;

void ManaChanged(const FOnAttributeChangeData& Data) const;
void MaxManaChanged(const FOnAttributeChangeData& Data) const;

};

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
// Fill out your copyright notice in the Description page of Project Settings.


#include "UI/WidgetController/OverlayWidgetController.h"

#include "AbilitySystem/AuraAbilitySystemComponent.h"
#include "AbilitySystem/AuraAttributeSet.h"

/*初始化属性时发出通知*/
void UOverlayWidgetController::BroadcastInitialValues()
{
Super::BroadcastInitialValues();
const UAuraAttributeSet* AuraAttributeSet = CastChecked<UAuraAttributeSet>(AttributeSet);
OnHealtChanged.Broadcast(AuraAttributeSet->GetHealth());
OnMaxHealtChanged.Broadcast(AuraAttributeSet->GetMaxHealth());
OnManaChanged.Broadcast(AuraAttributeSet->GetMana());
OnMaxManaChanged.Broadcast(AuraAttributeSet->GetMaxMana());

}

/*绑定属性回调*/
void UOverlayWidgetController::BindCallbacksToDependencies()
{
Super::BindCallbacksToDependencies();
const UAuraAttributeSet* AuraAttributeSet = CastChecked<UAuraAttributeSet>(AttributeSet);



//绑定生命值回调
AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(
AuraAttributeSet->GetHealthAttribute()).AddUObject(this, &UOverlayWidgetController::HealthChanged);
//绑定最大生命值回调
AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(
AuraAttributeSet->GetMaxHealthAttribute()).AddUObject(this, &UOverlayWidgetController::MaxHealthChanged);
//绑定法力值回调
AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(
AuraAttributeSet->GetManaAttribute()).AddUObject(this, &UOverlayWidgetController::ManaChanged);
//绑定最大法力值回调
AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(
AuraAttributeSet->GetMaxManaAttribute()).AddUObject(this, &UOverlayWidgetController::MaxManaChanged);


//匿名函数调用
// AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(AuraAttributeSet->GetHealthAttribute()
// ).AddLambda([this](const FOnAttributeChangeData& Data){OnHealtChanged.Broadcast(Data.NewValue);});

//AddLambda 绑定匿名函数(效果添加Tag时触发)
Cast<UAuraAbilitySystemComponent>(AbilitySystemComponent)->EffectAssetTags.AddLambda(
[this](const FGameplayTagContainer& AssetTags) //中括号添加this是为了保证内部能够获取类的对象
{
for(const FGameplayTag& Tag : AssetTags)
{

// const FString Msg = FString::Printf(TEXT("添加标签: %s"), *Tag.ToString()); //获取Asset Tag
// GEngine->AddOnScreenDebugMessage(-1, 8.f, FColor::Cyan, Msg); //打印到屏幕上 -1 不会被覆盖
//对标签进行检测,如果不是信息标签,将无法进行广播
FGameplayTag MessageTag = FGameplayTag::RequestGameplayTag(FName("Message"));
// "A.1".MatchesTag("A") will return True, "A".MatchesTag("A.1") will return False

if(Tag.MatchesTag(MessageTag))
{
const FString Msg = FString::Printf(TEXT("添加标签: %s"), *Tag.ToString()); //获取Asset Tag
GEngine->AddOnScreenDebugMessage(-1, 8.f, FColor::Cyan, Msg);

FUIWidgetRow* Row = GetDataTableRowByTag<FUIWidgetRow>(MessageWidgetDataTable, Tag);
MessageWidgetRowDelegate.Broadcast(*Row); //前面加*取消指针引用
}
}
}
);

}


/*当属性改变时发出通知*/
void UOverlayWidgetController::HealthChanged(const FOnAttributeChangeData& Data) const
{
OnHealtChanged.Broadcast(Data.NewValue);
}

void UOverlayWidgetController::MaxHealthChanged(const FOnAttributeChangeData& Data) const
{
OnMaxHealtChanged.Broadcast(Data.NewValue);
}

void UOverlayWidgetController::ManaChanged(const FOnAttributeChangeData& Data) const
{
OnManaChanged.Broadcast(Data.NewValue);
}

void UOverlayWidgetController::MaxManaChanged(const FOnAttributeChangeData& Data) const
{
OnMaxManaChanged.Broadcast(Data.NewValue);
}

属性集

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "AttributeSet.h"
#include "UI/WidgetController/AuraWidgetController.h"
#include "AttributeMenuWidgetController.generated.h"

class UAbilityInfo;
struct FAttributeInfo;
struct FGameplayTag;
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FAttibuteInfoSignature, const FAttributeInfo&, Info);

//广播属性用的控制层
UCLASS(Blueprintable, BlueprintType)
class AURADEMO_API UAttributeMenuWidgetController : public UAuraWidgetController
{
GENERATED_BODY()
public:

UFUNCTION(BlueprintCallable)
virtual void BroadcastInitialValues() override; //广播初始值
virtual void BindCallbacksToDependencies() override; //绑定数值变动后回调广播


UPROPERTY(BlueprintAssignable, Category="GAS|Attributes")//设置BlueprintAssignable可以在蓝图作为委托绑定监听
FAttibuteInfoSignature AttributeInfoDelegate;

protected:

UPROPERTY(EditDefaultsOnly)//EditDefaultsOnly只能在UE面板编辑
TObjectPtr<UAbilityInfo> AttributeInfo;

private:
void BroadcastAttributeInfo(const FGameplayTag& AttributeTag, const FGameplayAttribute& Attribute) const;
};

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
// Fill out your copyright notice in the Description page of Project Settings.


#include "UI/WidgetController/AttributeMenuWidgetController.h"

#include "AbilitySystem/AuraAbilitySystemComponent.h"
#include "AbilitySystem/AuraAttributeSet.h"
#include "AbilitySystem/Data/AbilityInfo.h"
#include "Player/AuraPlayerState.h"

void UAttributeMenuWidgetController::BindCallbacksToDependencies()
{
Super::BindCallbacksToDependencies();
const UAuraAttributeSet* AS = Cast<UAuraAttributeSet>(AttributeSet);
check(AttributeInfo);

for (auto& Pair : AS->TagsToAttributes)
{
AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(Pair.Value()).AddLambda(
[this,Pair,AS](const FOnAttributeChangeData& Data)
{
//BroadcastAttributeInfo(Pair.Key,Pair.Value());
FAttributeInfo Info = AttributeInfo->FindAttributeInfoForTag(Pair.Key);
Info.AttributeValue = Pair.Value().GetNumericValue(AS);
AttributeInfoDelegate.Broadcast(Info);
}
);
}
}

void UAttributeMenuWidgetController::BroadcastInitialValues()
{
const UAuraAttributeSet* AS = Cast<UAuraAttributeSet>(AttributeSet);
check(AttributeInfo);

// for (auto& Pair : AS->TagsToAttributes)
// {
// FAttributeInfo Info = AttributeInfo->FindAttributeInfoForTag(Pair.Key);
// FGameplayAttribute Attr = Pair.Value.Execute();
// Info.AttributeValue = Attr.GetNumericValue(AS);
// AttributeInfoDelegate.Broadcast(Info);
// }

for (auto& Pair : AS->TagsToAttributes)
{
FAttributeInfo Info = AttributeInfo->FindAttributeInfoForTag(Pair.Key);
Info.AttributeValue = Pair.Value().GetNumericValue(AS);
AttributeInfoDelegate.Broadcast(Info);
//BroadcastAttributeInfo(Pair.Key,Pair.Value());
}


}

void UAttributeMenuWidgetController::BroadcastAttributeInfo(const FGameplayTag& AttributeTag,
const FGameplayAttribute& Attribute) const
{
FAttributeInfo Info = AttributeInfo->FindAttributeInfoForTag(AttributeTag);
Info.AttributeValue = Attribute.GetNumericValue(AttributeSet);
AttributeInfoDelegate.Broadcast(Info);
}

// void UAttributeMenuWidgetController::BroadcastAttributeInfo(const FGameplayTag& AttributeTag, const FGameplayAttribute& Attribute) const
// {
// FAttributeInfo Info = AttributeInfo->FindAttributeInfoForTag(AttributeTag);
// Info.AttributeValue = Attribute.GetNumericValue(AttributeSet);
// AttributeInfoDelegate.Broadcast(Info);
// }

控制层函数库代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "AuraAbilitySystemLibrary.generated.h"

class UAttributeMenuWidgetController;
class UOverlayWidgetController;

UCLASS()
class AURADEMO_API UAuraAbilitySystemLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
////获取生命值控制层
UFUNCTION(BlueprintPure, Category="MyAbilitySystemLibrary|WidgetController")
static UOverlayWidgetController* GetOverlayWidgetController(const UObject* WorldContextObject);

//获取属性集控制层
UFUNCTION(BlueprintPure, Category="MyAbilitySystemLibrary|WidgetController")
static UAttributeMenuWidgetController* GetAttributeMenuWidgetController(const UObject* WorldContextObject);
};

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// Fill out your copyright notice in the Description page of Project Settings.


#include "AbilitySystem/AuraAbilitySystemLibrary.h"

#include "Kismet/GameplayStatics.h"
#include "Player/AuraPlayerState.h"
#include "UI/HUD/AuraHUD.h"

//获取生命值控制层
UOverlayWidgetController* UAuraAbilitySystemLibrary::GetOverlayWidgetController(const UObject* WorldContextObject)
{
//获取到playerController, 需要传入一个世界空间上下文的对象,用于得到对应世界中的PC列表,0为本地使用的PC
if(APlayerController* PC = UGameplayStatics::GetPlayerController(WorldContextObject, 0))
{
//从PC获取到HUD,我们就可以从HUD获得对应的Controller
if(AAuraHUD* HUD = Cast<AAuraHUD>(PC->GetHUD()))
{
AAuraPlayerState* PS = PC->GetPlayerState<AAuraPlayerState>();
UAbilitySystemComponent* ASC = PS->GetAbilitySystemComponent();
UAttributeSet* AS = PS->GetAttributeSet();
const FWidgetControllerParame WidgetControllerParams(PC, PS, ASC, AS);
return HUD->GetOverlayWidgetController(WidgetControllerParams);
}
}
return nullptr;
}

//获取属性集控制层
UAttributeMenuWidgetController* UAuraAbilitySystemLibrary::GetAttributeMenuWidgetController(const UObject* WorldContextObject)
{
//获取到playerController, 需要传入一个世界空间上下文的对象,用于得到对应世界中的PC列表,0为本地使用的PC
if(APlayerController* PC = UGameplayStatics::GetPlayerController(WorldContextObject, 0))
{
//从PC获取到HUD,我们就可以从HUD获得对应的Controller
if(AAuraHUD* HUD = Cast<AAuraHUD>(PC->GetHUD()))
{
AAuraPlayerState* PS = PC->GetPlayerState<AAuraPlayerState>();
UAbilitySystemComponent* ASC = PS->GetAbilitySystemComponent();
UAttributeSet* AS = PS->GetAttributeSet();
const FWidgetControllerParame WidgetControllerParams(PC, PS, ASC, AS);
return HUD->GetAttributeMenuWidgetController(WidgetControllerParams);
}
}
return nullptr;
}

GE 效果配置

配置

持续时间

属性名 描述
Insant 立即执行
Infinite 无限 比如泉水持续回血,记得添加移除事件,比如玩家离开泉水后不再执行效果 + Period 间隔时间
+ bExecutePeriodicEffectOnApplication 立即执行或者倒数再执行
+ PeriodicInhibitionPolicy
Has Duration 有时间

堆叠Stacking

属性 描述
Aggregate by Source 那么角色可以对每个目标叠加三层效果
Aggregate by Target 那么就是不管多少人对目标叠加了多少层效果,目标身上只能叠加三层效果
属性 描述
StackLimitCount 堆叠次数
Stack Duration Refresh Polic Refresh on Successfull Application: 叠加效果时,刷新持续时间,即使层数不增加也会更新。
Never Refresh: 即使叠加效果,也不会刷新。。
Stack Period Reset Policy Refresh on Successfull Application:叠加效果时,每次都会更新周期时间 Period
Never Refresh: 即使叠加效果,也不会刷新。
Stack Expiration Policy Clear Entire Stack:Duration结束时清楚所有层数
Remove Single Stack And Refresh Duration:Duration结束时减少一层,然后重新经历一个Duration,一直持续到层数减为0
Refresh Duration:Duration结束时再次刷新Duration,这相当于无限Duration,可以通过调用
属性Overflow
OverflowEffects 超过StackLimitCount数量的Effect被Apply时将会调用该OverflowEffects,可以设置多个
DenyOverflowApplication 对应于StackDurationRefreshPolicy,如果为True则多余的Apply不会刷新Duration
ClearStackOnOverflow 当DenyOverflowApplication为True是才有效,当Overflow时是否直接删除所有层数

叠加触发

1
2
UFUNCTION(BlueprintCallable) 
void ApplyEffectToTarget(AActor* TargetActor, TSubclassOf<UGameplayEffect> GameplayEffectClass);//给与目标添加GameplayEffect
1
2
3
4
5
6
7
8
9
10
11
12
13
void AAuraCtestCharacter::ApplyEffectToTarget(AActor* TargetActor, TSubclassOf<UGameplayEffect> GameplayEffectClass)
{
//获取角色能力组件
UAbilitySystemComponent* TargetASC = UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(TargetActor);
//生成游戏效果上下文
FGameplayEffectContextHandle EffectContextHandle = TargetASC->MakeEffectContext();
//设置游戏效果上下文的源对象
EffectContextHandle.AddSourceObject(this);
//生成游戏效果规格
const FGameplayEffectSpecHandle EffectSpecHandle = TargetASC->MakeOutgoingSpec(GameplayEffectClass, 1.f, EffectContextHandle);
//将游戏效果规格应用到目标对象上
TargetASC->ApplyGameplayEffectSpecToSelf(*EffectSpecHandle.Data.Get());
}

Gameplay Effect 游戏效果

  • GEComponents 这个组件主要是在GameplayEffect激活时,可以向目标添加的GameplayAbility

    名称 效果
    Abilities Gameplay Effect component 这个组件主要是在GameplayEffect激活时,可以向目标添加的GameplayAbility
    Addtional Effects Gameplay Effect Component 当此效果添加时或完成时,需要额外添加的效果。
    On Appliaciton Gameplay Effects 在添加此效果时,额外添加的效果
    On Complete Always 当此效果完成时,不管正常结束还是不正常结束时,添加的效果
    On Complete Normal 当此效果正常结束时,添加的额外的效果
    On Complete Prematurely 当此效果提前结束时,添加的额外的效果
    Asset Tags Gameplay Effect Component 在添加此GE时,需要额外处理的标签(添加 和 删除),这个标签将放置在GE上面,只是作为一个GE的标记
    Block Ability Tags Gameplay Component 添加或删除能够阻挡技能的Tags的组件,这些Tags会在GE运行时添加到Actor身上,用于阻挡其它拥有此Tag的GE或者GA的激活。
    Chance to Apply Gameplay Effect Component 当前GE应用到Actor身上的几率,0为百分之0几率,1为百分之百几率
    Custom Can Apply Gameplay Effect Component 自定义能够应用GE的组件,可以自定义条件来设置应用是否成功。
    Gameplay Effect UIData Text Only 用于配置GE的UI信息,这里只有一个简单的TEXT,有需要的可以派生UGameplayEffectUIData类去添加自己需要的数据信息
    Immunity Gameplay Effect Component 配置角色免疫其它GE的条件
    Remove Other Gameplay Effect Component 配置移除其它的GE,满足设置的标签或者资源满足条件的GE都会被移除掉
    Target Tag Requirements Gameplay Effect Component 根据目标的Tag设置当前的GE的状态
    Appliaction 为GE添加到目标身上时Tag的状态
    Ongoing 为GE激活时Tag的状态
    Removal 为GE被删除时Tag的状态
    Target Tags Gameplay Effect Component 添加此GE后,对Actor身上带有的Tag进行操作(添加或删除),这个会随着GE的添加修改,在GE失效时移除。非Instant使用

Gameplay Cues 游戏提示

Stackong 堆叠

  • Stack Duration Refresh Policy 叠加效果时,是否更新持续时间 Duration
    Refresh on Successfull Application: 叠加效果时,刷新持续时间,即使层数不增加也会更新。
    Never Refresh: 即使叠加效果,也不会刷新。

  • Stack Period Reset Policy 叠加效果时,是否更新周期时间 Period
    Refresh on Successfull Application:叠加效果时,每次都会更新周期时间 Period
    Never Refresh: 即使叠加效果,也不会刷新

  • Stack Expiration Policy

    Clear Entire Stack:Duration结束时清楚所有层数
    Remove Single Stack And Refresh Duration:Duration结束时减少一层,然后重新经历一个Duration,一直持续到层数减为0
    Refresh Duration:Duration结束时再次刷新Duration,这相当于无限Duration,可以通过调用

  • Overflow

    OverflowEffects:超过StackLimitCount数量的Effect被Apply时将会调用该OverflowEffects,可以设置多个
    DenyOverflowApplication:对应于StackDurationRefreshPolicy,如果为True则多余的Apply不会刷新Duration
    ClearStackOnOverflow:当DenyOverflowApplication为True是才有效,当Overflow时是否直接删除所有层数

GE-MMC

  • 通过等级更新玩家属性,MMC在GE效果类修改数值里设置,效果为覆盖
  1. 首先,玩家角色的等级需要创建在PlayerState里面,如果玩家角色Actor被销毁掉,等级信息也能够被保存下来
1
2
UPROPERTY(VisibleAnywhere, ReplicatedUsing=OnRep_Level)
int32 Level;
1
2
UFUNCTION()
void OnRep_Level(int32 OldLevel);
1
2
3
4
void APlayerStateBase::OnRep_Level(int32 OldLevel)
{
// GAMEPLAYATTRIBUTE_REPNOTIFY(UAttributeSetBase, Level, OldLevel);
}
1
2
//服务器同步
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
1
2
//等级获取函数,声明在玩家状态里
FORCEINLINE int32 GetPlayerLevel() const {return Level;}
1
2
3
4
5
6
7
8
9
10
11
12
//DOREPLIFETIME
//DOREPLIFETIME_CONDITION
//DOREPLIFETIME_CONDITION_NOTIFY
//它们三种是一次递进的,
//第一种就是基础的注册宏,在服务器变化时,会同步所有的客户端,
//第二种增加了CONDITION 也就是条件,条件的参数有多种,按需设置
void APlayerStateBase::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);

DOREPLIFETIME(APlayerStateBase, Level);
}
1
2
3
//敌人等级	
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Character Class Defaults")
int32 Level = 1;
  1. 创建接口,用于获取等级的虚函数
1
virtual  int32 GetPlayerLevel();
1
2
3
4
int32 ICombatInterface::GetPlayerLevel()
{
return 0;
}
  • 玩家继承接口并实现`GetPlayerLevel()
1
virtual int32 GetPlayerLevel() override;
1
2
3
4
5
6
7
int32 AHeroCharacter::GetPlayerLevel()
{
const APlayerStateBase* PlayerStateBase = GetPlayerState<APlayerStateBase>();
check(PlayerStateBase); //检测是否有效,无限会暂停游戏
return PlayerStateBase->GetPlayerLevel();
}

  • 敌人实现
1
2
3
4
int32 AEnemyBase::GetPlayerLevel()
{
return Level;
}

用于根据等级配置生命值和魔法值最大值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "GameplayModMagnitudeCalculation.h"
#include "MMC_MaxHealth.generated.h"

//MMC类(用于通过蓝图或本机代码执行自定义玩法效果修改器计算)
UCLASS()
class AURADEMO_API UMMC_MaxHealth : public UGameplayModMagnitudeCalculation
{
GENERATED_BODY()
public:
//构造函数
UMMC_MaxHealth();
//重写自UGameplayModMagnitudeCalculation,返回计算后的数值
virtual float CalculateBaseMagnitude_Implementation(const FGameplayEffectSpec& Spec) const override;
private:
//捕获Vigor属性
FGameplayEffectAttributeCaptureDefinition VigorDef;
};

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// Fill out your copyright notice in the Description page of Project Settings.


#include "AbilitySystem/ModMagCalc/MMC_MaxHealth.h"

#include "AbilitySystem/AuraAttributeSet.h"
#include "Interface/CombatInterface.h"

UMMC_MaxHealth::UMMC_MaxHealth()
{
// 捕获属性
VigorDef.AttributeToCapture = UAuraAttributeSet::GetVigorAttribute(); //设置需要获取的属性对象
// 设置源对象 枚举选项,从哪里捕捉游戏效果的游戏属性
VigorDef.AttributeSource = EGameplayEffectAttributeCaptureSource::Target; //设置拾取对象为GE的应用目标
//快照模式:当 bSnapshot 设置为 true 时,表示在游戏效果应用时对目标对象的属性进行一次“快照”(即一次性捕获),并将该快照值用于整个游戏效果的持续期间。
//动态更新:当 bSnapshot 设置为 false 时,表示在游戏效果持续期间,属性值会根据目标对象的实际变化动态更新。
VigorDef.bSnapshot = false; //是否应该对属性进行快照

RelevantAttributesToCapture.Add(VigorDef); //添加到捕获属性数值,只有添加到列表,才会去获取属性值
}

float UMMC_MaxHealth::CalculateBaseMagnitude_Implementation(const FGameplayEffectSpec& Spec) const
{
// 从 source 和 target 获取 Tag
const FGameplayTagContainer* SourceTags = Spec.CapturedSourceTags.GetAggregatedTags();
const FGameplayTagContainer* TargetTags = Spec.CapturedTargetTags.GetAggregatedTags();

//聚合器评估中使用的数据,从调用者/游戏代码中传递
FAggregatorEvaluateParameters EvaluateParameters;
EvaluateParameters.SourceTags = SourceTags;
EvaluateParameters.TargetTags = TargetTags;

//获取体力值
float Vigor = 0.f;
//在CalculateMagnitude调用期间获取属性大小的方便方法
GetCapturedAttributeMagnitude(VigorDef, Spec, EvaluateParameters, Vigor);
Vigor = FMath::Max<float>(Vigor, 0.f);


// 从GE获取上下文再获取对象
ICombatInterface* CombatInterface = Cast<ICombatInterface>(Spec.GetContext().GetSourceObject());
//获取等级
const int32 Level = CombatInterface->GetPlayerLevel();

//计算最大血量
return 80.f + Vigor * 2.5f + Level * 10.f;
}

GAS系统组件事件和回调等

  • 添加TAG触发,返回TAG,用于处理捡到物品

  • 添加GE触发,用于刷新血量? AbilitySystemComponent里写

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    // Fill out your copyright notice in the Description page of Project Settings.


    #include "AbilitySystem/AuraAbilitySystemComponent.h"

    void UAuraAbilitySystemComponent::AbilityActorInfoSet()
    {
    //绑定委托? 当添加效果时调用
    OnGameplayEffectAppliedDelegateToSelf.AddUObject(this, &UAuraAbilitySystemComponent::ClientEffectApplied);
    }

    void UAuraAbilitySystemComponent::ClientEffectApplied_Implementation(UAbilitySystemComponent* AbilitySystemComponent,
    const FGameplayEffectSpec& EffectSpec, FActiveGameplayEffectHandle ActiveEffectHandle)
    {
    FGameplayTagContainer TagContainer;
    EffectSpec.GetAllAssetTags(TagContainer);

    //当添加效果时发送委托,参数为标签容器
    EffectAssetTags.Broadcast(TagContainer);
    }


GA 技能配置

Tag标签配置

  • Aura方案-结构体 UAssetManager在项目设置’’’资源管理器设置’
  • 通过结构体获取单例const FMyGameplayTags& GameplayTags = FMyGameplayTags::Get();
  • 副本:改增强输入系统单例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
// Fill out your copyright notice in the Description page of Project Settings.

// 版权归暮志未晚所有。

#pragma once

#include "CoreMinimal.h"
#include "GameplayTagContainer.h"

/**
* GameplayTags 标签 单例模式
* 内部包含原生的项目中使用的标签
*/

struct FAuraGameplayTags
{
public:
//静态函数,返回标签
static const FAuraGameplayTags& Get() { return GameplayTags; }
////用于初始化内部的Tag标签
static void InitializeNativeGameplayTags();

//初始化角色属性GameplayTags
static void InitializeAttributeGameplayTags();
//初始化输入GameplayTags
static void InitializeInputGameplayTags();
/*
* Primary Attributes
*/
FGameplayTag Attributes_Primary_Strength; //力量
FGameplayTag Attributes_Primary_Intelligence; //智力
FGameplayTag Attributes_Primary_Resilience; //韧性
FGameplayTag Attributes_Primary_Vigor; //体质

/*
* Secondary Attributes
*/
FGameplayTag Attributes_Secondary_Armor; //盔甲
FGameplayTag Attributes_Secondary_ArmorPenetration; //盔甲穿透
FGameplayTag Attributes_Secondary_BlockChance; //格挡
FGameplayTag Attributes_Secondary_CriticalHitChance; //暴击
FGameplayTag Attributes_Secondary_CriticalHitDamage; //暴击伤害
FGameplayTag Attributes_Secondary_CriticalHitResistance; //暴击抗性
FGameplayTag Attributes_Secondary_HealthRegeneration; //生命回复
FGameplayTag Attributes_Secondary_ManaRegeneration; //法力回复
FGameplayTag Attributes_Secondary_MaxHealth; //最大生命
FGameplayTag Attributes_Secondary_MaxMana; //最大法力

/*
*Input
*/
FGameplayTag InputTag_LMB; //鼠标左键
FGameplayTag InputTag_RMB; //鼠标右键
FGameplayTag InputTag_1; //1键
FGameplayTag InputTag_2; //2键
FGameplayTag InputTag_3; //3键
FGameplayTag InputTag_4; //4键

protected:

private:
//属性GameplayTags用于存储单例
static FAuraGameplayTags GameplayTags;

};

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
// Fill out your copyright notice in the Description page of Project Settings.


#include "AbilitySystem/GameplayTags/AuraGameplayTags.h"

#include "GameplayTagsManager.h"

FAuraGameplayTags FAuraGameplayTags::GameplayTags;

void FAuraGameplayTags::InitializeNativeGameplayTags()
{
InitializeAttributeGameplayTags();
InitializeInputGameplayTags();
}

void FAuraGameplayTags::InitializeAttributeGameplayTags()
{
/*
* Primary Attributes
*/
GameplayTags.Attributes_Primary_Strength = UGameplayTagsManager::Get().AddNativeGameplayTag(
FName("Attributes.Primary.Strength"),
FString("Increases physical damage")
);

GameplayTags.Attributes_Primary_Intelligence = UGameplayTagsManager::Get().AddNativeGameplayTag(
FName("Attributes.Primary.Intelligence"),
FString("Increases magical damage")
);

GameplayTags.Attributes_Primary_Resilience = UGameplayTagsManager::Get().AddNativeGameplayTag(
FName("Attributes.Primary.Resilience"),
FString("Increases Armor and Armor Penetration")
);

GameplayTags.Attributes_Primary_Vigor = UGameplayTagsManager::Get().AddNativeGameplayTag(
FName("Attributes.Primary.Vigor"),
FString("Increases Health")
);

/*
* Secondary Attributes
*/
GameplayTags.Attributes_Secondary_Armor = UGameplayTagsManager::Get().AddNativeGameplayTag(
FName("Attributes.Secondary.Armor"),
FString("Reduces damage taken, improves Block Chance")
);

GameplayTags.Attributes_Secondary_ArmorPenetration = UGameplayTagsManager::Get().AddNativeGameplayTag(
FName("Attributes.Secondary.ArmorPenetration"),
FString("Ignores Percentage of enemy Armor, increases Critical Hit Chance")
);

GameplayTags.Attributes_Secondary_BlockChance = UGameplayTagsManager::Get().AddNativeGameplayTag(
FName("Attributes.Secondary.BlockChance"),
FString("Chance to cut incoming damage in half")
);

GameplayTags.Attributes_Secondary_CriticalHitChance = UGameplayTagsManager::Get().AddNativeGameplayTag(
FName("Attributes.Secondary.CriticalHitChance"),
FString("Chance to double damage plus critical hit bonus")
);

GameplayTags.Attributes_Secondary_CriticalHitDamage = UGameplayTagsManager::Get().AddNativeGameplayTag(
FName("Attributes.Secondary.CriticalHitDamage"),
FString("Bonus damage added when a critical hit is scored")
);

GameplayTags.Attributes_Secondary_CriticalHitResistance = UGameplayTagsManager::Get().AddNativeGameplayTag(
FName("Attributes.Secondary.CriticalHitResistance"),
FString("Reduces Critical Hit Chance of attacking enemies")
);

GameplayTags.Attributes_Secondary_HealthRegeneration = UGameplayTagsManager::Get().AddNativeGameplayTag(
FName("Attributes.Secondary.HealthRegeneration"),
FString("Amount of Health regenerated every 1 second")
);

GameplayTags.Attributes_Secondary_ManaRegeneration = UGameplayTagsManager::Get().AddNativeGameplayTag(
FName("Attributes.Secondary.ManaRegeneration"),
FString("Amount of Mana regenerated every 1 second")
);

GameplayTags.Attributes_Secondary_MaxHealth = UGameplayTagsManager::Get().AddNativeGameplayTag(
FName("Attributes.Secondary.MaxHealth"),
FString("Maximum amount of Health obtainable")
);

GameplayTags.Attributes_Secondary_MaxMana = UGameplayTagsManager::Get().AddNativeGameplayTag(
FName("Attributes.Secondary.MaxMana"),
FString("Maximum amount of Mana obtainable")
);
}

void FAuraGameplayTags::InitializeInputGameplayTags()
{
/*
* Input Tags
*/
GameplayTags.InputTag_LMB = UGameplayTagsManager::Get()
.AddNativeGameplayTag(
FName("Attributes.InputTag.LMB"),
FString("鼠标左键")
);

GameplayTags.InputTag_RMB = UGameplayTagsManager::Get()
.AddNativeGameplayTag(
FName("Attributes.InputTag.RMB"),
FString("鼠标右键")
);

GameplayTags.InputTag_1 = UGameplayTagsManager::Get()
.AddNativeGameplayTag(
FName("Attributes.InputTag.1"),
FString("键盘1键")
);

GameplayTags.InputTag_2 = UGameplayTagsManager::Get()
.AddNativeGameplayTag(
FName("Attributes.InputTag.2"),
FString("键盘2键")
);

GameplayTags.InputTag_3 = UGameplayTagsManager::Get()
.AddNativeGameplayTag(
FName("Attributes.InputTag.3"),
FString("键盘3键")
);

GameplayTags.InputTag_4 = UGameplayTagsManager::Get()
.AddNativeGameplayTag(
FName("Attributes.InputTag.4"),
FString("键盘4键")
);
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "CoreMinimal.h"
#include "Engine/AssetManager.h"
#include "AuraAssetManager.generated.h"

/**
*
*/
UCLASS()
class AURADEMO_API UAuraAssetManager : public UAssetManager
{
GENERATED_BODY()
public:
//获取资源管理器
static UAuraAssetManager& Get();

virtual void StartInitialLoading() override;
};

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// Fill out your copyright notice in the Description page of Project Settings.


#include "AbilitySystem/GameplayTags/AuraAssetManager.h"
#include "AbilitySystem/GameplayTags/AuraGameplayTags.h"

UAuraAssetManager& UAuraAssetManager::Get()
{
check(GEngine);
UAuraAssetManager* MyAssetManager = Cast<UAuraAssetManager>(GEngine->AssetManager);
return *MyAssetManager;
}

void UAuraAssetManager::StartInitialLoading()
{
//初始化gameplay tags
FAuraGameplayTags::InitializeNativeGameplayTags();
}

声明

TAGS 声明

1
2
UPROPERTY(EditDefaultsOnly)
FGameplayTag PassiveSpellTag;

AI行为树

  • 需要蓝图类:AI控制器,行为树,黑板,任务

  • 添加导航区域

  • 创建AI控制器

  • 打开角色蓝图选择AI控制器

  • 创建行为树

  • AI控制器执行行为树(开始执行非循环)

  • 行为树添加序列执行

  • 添加计时

  • 添加移动至

  • 添加倒计时

  • 创建黑板(声明变量的)比如向量

  • 创建任务(负责写逻辑)比如获取玩家位置,将黑板值设置为向量

UE开发测试

角色移动

  • 基础第三人称蓝图设置
    • 角色移动节点:旋转朝向移动打开
    • 弹簧臂组件:pawn控制旋转打开
    • 玩家关闭使用控制器旋转yaw
  • 增强输入
    • 引入控制器调用事件,判断控制器,添加增强输入,添加输入映射上下文
    • 移动:获取控制器旋转,获取向前向量,添加移动输入
    • 鼠标:添加pawn输入,添加PAW输入

模型资产

  • 玩家
  • 怪物
  • 武器:剑,刀,枪—
  • 子弹

能力系统

  • 能力组件添加函数,用于通过数组学习技能
  • 玩家组件添加能力数组属性,用于 设置玩家要学习的技能

配置增强输入

+ 创建DataAsset类,文件夹input,然后创建资产文件给控制器(控制器需要声明)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#pragma once

#include "CoreMinimal.h"
#include "GameplayTagContainer.h"
#include "Engine/DataAsset.h"
#include "InputConfig.generated.h"

USTRUCT(BlueprintType)
struct FInputActionStruct
{
GENERATED_BODY()

UPROPERTY(EditDefaultsOnly)
const class UInputAction* InputAction = nullptr;

UPROPERTY(EditDefaultsOnly)
FGameplayTag InputTag = FGameplayTag();
};


UCLASS(BlueprintType,Blueprintable)
class AURADEMO_API UInputConfig : public UDataAsset
{
GENERATED_BODY()
public:
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
TArray<FInputActionStruct> AbilityInputActions;

const UInputAction* FindAbilityInputActionForTag(const FGameplayTag& InputTag, bool bLogNotFound = false) const;


};

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
#include "Input/InputConfig.h"

const UInputAction* UInputConfig::FindAbilityInputActionForTag(const FGameplayTag& InputTag, bool bLogNotFound) const
{
for(const FInputActionStruct& Action : AbilityInputActions)
{
if(Action.InputAction && Action.InputTag == InputTag)
{
return Action.InputAction;
}
}

if(bLogNotFound)
{
UE_LOG(LogTemp, Error, TEXT("无法从InputConfig[%s]中找到InputTag[%s]对应的技能InputAction"), *GetNameSafe(this), *InputTag.ToString());
}

return nullptr;
}

  • 增强输入系统基类,项目设置:默认组件输入
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#pragma once

#include "CoreMinimal.h"
#include "EnhancedInputComponent.h"
#include "InputConfig.h"
#include "InputComponentBase.generated.h"


UCLASS(ClassGroup=(Custom), meta=(BlueprintSpawnableComponent))
class AURADEMO_API UInputComponentBase : public UEnhancedInputComponent
{
GENERATED_BODY()
public:
template<class UserClass, typename PressedFuncType, typename ReleasedFuncType, typename HoldFuncType>
void BindAbilityAction(const UInputConfig* InputConfig, UserClass* Object, PressedFuncType PressedFunc, ReleasedFuncType ReleasedFunc, HoldFuncType HoldFunc);

};

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44



#include "Input/InputComponentBase.h"


// Sets default values for this component's properties
UInputComponentBase::UInputComponentBase()
{
// Set this component to be initialized when the game starts, and to be ticked every frame. You can turn these features
// off to improve performance if you don't need them.
PrimaryComponentTick.bCanEverTick = true;

}


template <class UserClass, typename PressedFuncType, typename ReleasedFuncType, typename HoldFuncType>
void UInputComponentBase::BindAbilityAction(const UInputConfig* InputConfig, UserClass* Object,
PressedFuncType PressedFunc, ReleasedFuncType ReleasedFunc, HoldFuncType HoldFunc)
{
check(InputConfig);

for(const FInputActionStruct& Action : InputConfig->AbilityInputActions)
{
if(Action.InputAction && Action.InputTag.IsValid())
{
if(PressedFunc)
{
BindAction(Action.InputAction, ETriggerEvent::Started, Object, PressedFunc, Action.InputTag);
}

if(HoldFunc)
{
BindAction(Action.InputAction, ETriggerEvent::Triggered, Object, HoldFunc, Action.InputTag);
}

if(ReleasedFunc)
{
BindAction(Action.InputAction, ETriggerEvent::Completed, Object, ReleasedFunc, Action.InputTag);
}
}
}
}

创建技能基类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#pragma once

#include "CoreMinimal.h"
#include "Abilities/GameplayAbility.h"
#include "GamePlayAbilityBase.generated.h"

UCLASS()
class AURADEMO_API UGamePlayAbilityBase : public UGameplayAbility
{
GENERATED_BODY()
public:
//技能输入Tag,通过这个tag触发对于技能
UPROPERTY(EditDefaultsOnly, Category="Input")
FGameplayTag StartupInputTag;
};

添加输入Tag,可以换其他方法

1
2
3
4
5
6
FGameplayTag InputTag_LMB; //鼠标左键
FGameplayTag InputTag_RMB; //鼠标右键
FGameplayTag InputTag_1; //1键
FGameplayTag InputTag_2; //2键
FGameplayTag InputTag_3; //3键
FGameplayTag InputTag_4; //4键
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
void FMyGameplayTags::InitializeInputGameplayTags()
{
GameplayTags.InputTag_LMB = UGameplayTagsManager::Get()
.AddNativeGameplayTag(
FName("Attributes.InputTag.LMB"),
FString("鼠标左键")
);

GameplayTags.InputTag_RMB = UGameplayTagsManager::Get()
.AddNativeGameplayTag(
FName("Attributes.InputTag.RMB"),
FString("鼠标右键")
);

GameplayTags.InputTag_1 = UGameplayTagsManager::Get()
.AddNativeGameplayTag(
FName("Attributes.InputTag.1"),
FString("键盘1键")
);

GameplayTags.InputTag_2 = UGameplayTagsManager::Get()
.AddNativeGameplayTag(
FName("Attributes.InputTag.2"),
FString("键盘2键")
);

GameplayTags.InputTag_3 = UGameplayTagsManager::Get()
.AddNativeGameplayTag(
FName("Attributes.InputTag.3"),
FString("键盘3键")
);

GameplayTags.InputTag_4 = UGameplayTagsManager::Get()
.AddNativeGameplayTag(
FName("Attributes.InputTag.4"),
FString("键盘4键")
);
}

控制器调用

1
2
3
4
5
6
7
8
9
10
11
UPROPERTY(EditDefaultsOnly, Category="Input")
TObjectPtr<UInputConfig> InputConfig;

void AbilityInputTagPressed(FGameplayTag InputTag);
void AbilityInputTagReleased(FGameplayTag InputTag);
void AbilityInputTagHold(FGameplayTag InputTag);

//获取能力组件,后期调用技能
UPROPERTY()
TObjectPtr<UAuraAbilitySystemComponent> AbilitySystemComponentBase;
UAuraAbilitySystemComponent* GetASC();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void AAuraPlayerController::AbilityInputTagPressed(FGameplayTag InputTag)
{
GEngine->AddOnScreenDebugMessage(1, 3.f, FColor::Red, *InputTag.ToString());
}

void AAuraPlayerController::AbilityInputTagReleased(FGameplayTag InputTag)
{
GEngine->AddOnScreenDebugMessage(2, 3.f, FColor::Blue, *InputTag.ToString());
if(GetASC() == nullptr) return;
GetASC()->AbilityInputTagReleased(InputTag);
}

void AAuraPlayerController::AbilityInputTagHold(FGameplayTag InputTag)
{
GEngine->AddOnScreenDebugMessage(3, 3.f, FColor::Yellow, *InputTag.ToString());
if(GetASC() == nullptr) return;
GetASC()->AbilityInputTagHold(InputTag);
}

//获取能力组件
UAuraAbilitySystemComponent* AAuraPlayerController::GetASC()
{
if(AbilitySystemComponentBase == nullptr)
{
AbilitySystemComponentBase = Cast<UAuraAbilitySystemComponent>(UAbilitySystemBlueprintLibrary::GetAbilitySystemComponent(GetPawn()));
}

return AbilitySystemComponentBase;
}

能力组件

1
2
3
4
5
6
7
8
//技能
//传入技能数组并学习
void AddCharacterAbilities(const TArray<TSubclassOf<UGameplayAbility>>& StartupAbilities);

//激活事件
void AbilityInputTagHold(const FGameplayTag& InputTag);
//取消事件
void AbilityInputTagReleased(const FGameplayTag& InputTag);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
void UAuraAbilitySystemComponent::AddCharacterAbilities(const TArray<TSubclassOf<UGameplayAbility>>& StartupAbilities)
{
for(const TSubclassOf<UGameplayAbility> AbilityClass : StartupAbilities)
{
FGameplayAbilitySpec AbilitySpec = FGameplayAbilitySpec(AbilityClass, 1);
if(const UGamePlayAbilityBase* AbilityBase = Cast<UGamePlayAbilityBase>(AbilitySpec.Ability))
{
AbilitySpec.DynamicAbilityTags.AddTag(AbilityBase->StartupInputTag);
GiveAbility(AbilitySpec); //只应用不激活
// GiveAbilityAndActivateOnce(AbilitySpec); //应用技能并激活一次
}
}
}

void UAuraAbilitySystemComponent::AbilityInputTagHold(const FGameplayTag& InputTag)
{
if(!InputTag.IsValid()) return;

for(auto AbilitySpec : GetActivatableAbilities())
{
if(AbilitySpec.DynamicAbilityTags.HasTagExact(InputTag))
{
AbilitySpecInputPressed(AbilitySpec);
if(!AbilitySpec.IsActive())
{
TryActivateAbility(AbilitySpec.Handle);
}
}
}
}

void UAuraAbilitySystemComponent::AbilityInputTagReleased(const FGameplayTag& InputTag)
{
if(!InputTag.IsValid()) return;

for(auto AbilitySpec : GetActivatableAbilities())
{
if(AbilitySpec.DynamicAbilityTags.HasTagExact(InputTag))
{
AbilitySpecInputReleased(AbilitySpec);
}
}
}