Gas系统笔记

Gas系统笔记
凝雨Build.cs
- showdebug abilitysystem 调试信息
1 | using UnrealBuildTool; |
Gameplay Ability (GA)
- GA代表游戏中的技能或能力,是玩家或NPC可以执行的动作。
- GA通常由一个或多个Ability Task(任务)组成,这些任务定义了技能的具体行为和效果。
Gameplay Effect (GE)
:
- GE描述了一个游戏效果,例如治疗、伤害、加攻、减速等。
- GE可以修改玩家属性、添加其他GE、修改玩家身上的Tag或给玩家某个Cue效果。
- GE的配置包括时效性参数(如执行时长和周期)、属性修改、修改条件、Tag属性和后处理等。
Gameplay Tag (Tag)
:
- Tag用于标记状态和类别,可以用来表示一个游戏对象的特性、状态、行为等信息。
- 例如,可以用”Character.Type.Enemy”和”Character.Type.Boss”等Tag来描述敌人角色,用”Character.State.Jump”和”Character.State.Swimming”等Tag来表明对象在跳跃或游泳。
Gameplay Cue (GC)
:
- GC负责播放客户端表现,如特效、音效、动画、材质效果和后处理等。
- GC可以通过DS(Data-Driven)端发起,广播到客户端,也可以直接在客户端触发。
AttributeSet(属性集)
:
- AttributeSet定义了角色属性,如攻击力、防御力、血量等。
- AttributeSet是GAS系统中用于存储和管理角色属性的核心组件。
Ability System Component (ASC)
:
- ASC是GAS系统的管理组件,负责管理GAS模块对外接口,以及上述提到的GA、Task、GE、Tag、GC和AttributeSet等。
- ASC提供了用于激活技能、管理游戏效果和标记等功能的接口。
官方Tga
1 | //头文件 |
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.
DECLARE_DELEGATE_RetVal(FGameplayAttribute, FAttributeSignature);
// 属性访问器
// 特殊属性
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.
//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
`
宏定义用于自动生成类属性的访问器方法
命名规范:确保宏中的方法名称符合项目的命名规范。
线程安全:如果属性在多线程环境中使用,考虑添加必要的同步机制。
性能优化:对于频繁访问的属性,可以考虑使用内联函数以提高性能。
通过这种方式,可以大大简化属性访问器的编写,提高代码的可维护性和一致性。
1 | //ATTRIBUTE_ACCESSORS 宏定义用于自动生成类属性的访问器方法 |
假设我们有一个类 Character,并且希望为属性 Health 生成访问器方法,可以这样使用宏:
1 | class Character |
展开后的代码
宏展开后,生成的代码可能类似于以下内容:
1 | class Character |
在玩家类中初始化
因为玩家角色在游戏中死亡会被销毁释放,属性也会跟着被释放掉,为了避免这种情况,我们需要将玩家属性和玩家分开,我们可以通过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
//前向声明
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
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
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
4UAbilitySystemComponent* AAuraCharacterBase::GetAbilitySystemComponent() const
{
return AbilitySystemComponent;
}玩家源码,继承自角色基类
- 头文件
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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
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 | UMyAttributeSet::UMyAttributeSet() |
InitFromStruct 方法:适用于从结构体中初始化属性。自定义
1 | void UMyAttributeSet::InitFromStruct(const FGameplayAttributeData& Data) |
PostGameplayEffectExecute 方法:适用于在应用游戏效果时动态更新属性。
1 | void UMyAttributeSet::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data) |
OnRep_ 函数:适用于在网络复制属性后进行初始化或更新。
1 | UPROPERTY(Replicated, BlueprintReadWrite, Category = "Attributes") |
API
虚函数
| 虚函数 | 说明 |
|---|---|
| virtual void GetLifetimeReplicatedProps(TArray |
获取需要在网络上传输的属性 |
| 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 | // Fill out your copyright notice in the Description page of Project Settings. |
1 | // Fill out your copyright notice in the Description page of Project Settings. |
HUD代码
1 | // Fill out your copyright notice in the Description page of Project Settings. |
1 | // Fill out your copyright notice in the Description page of Project Settings. |
控制层代码
基类
1 | // Fill out your copyright notice in the Description page of Project Settings. |
1 | // Fill out your copyright notice in the Description page of Project Settings. |
生命值/魔法值子类
1 | // Fill out your copyright notice in the Description page of Project Settings. |
1 | // Fill out your copyright notice in the Description page of Project Settings. |
属性集
1 | // Fill out your copyright notice in the Description page of Project Settings. |
1 | // Fill out your copyright notice in the Description page of Project Settings. |
控制层函数库代码
1 | // Fill out your copyright notice in the Description page of Project Settings. |
1 | // Fill out your copyright notice in the Description page of Project Settings. |
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:叠加效果时,每次都会更新周期时间 PeriodNever Refresh: 即使叠加效果,也不会刷新。 |
| Stack Expiration Policy | Clear Entire Stack:Duration结束时清楚所有层数Remove Single Stack And Refresh Duration:Duration结束时减少一层,然后重新经历一个Duration,一直持续到层数减为0Refresh Duration:Duration结束时再次刷新Duration,这相当于无限Duration,可以通过调用 |
| 属性Overflow | |
|---|---|
| OverflowEffects | 超过StackLimitCount数量的Effect被Apply时将会调用该OverflowEffects,可以设置多个 |
| DenyOverflowApplication | 对应于StackDurationRefreshPolicy,如果为True则多余的Apply不会刷新Duration |
| ClearStackOnOverflow | 当DenyOverflowApplication为True是才有效,当Overflow时是否直接删除所有层数 |
叠加触发
1 | UFUNCTION(BlueprintCallable) |
1 | void AAuraCtestCharacter::ApplyEffectToTarget(AActor* TargetActor, TSubclassOf<UGameplayEffect> GameplayEffectClass) |
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效果类修改数值里设置,效果为覆盖
- 首先,玩家角色的等级需要创建在PlayerState里面,如果玩家角色Actor被销毁掉,等级信息也能够被保存下来
1 | UPROPERTY(VisibleAnywhere, ReplicatedUsing=OnRep_Level) |
1 | UFUNCTION() |
1 | void APlayerStateBase::OnRep_Level(int32 OldLevel) |
1 | //服务器同步 |
1 | //等级获取函数,声明在玩家状态里 |
1 | //DOREPLIFETIME |
1 | //敌人等级 |
- 创建接口,用于获取等级的虚函数
1 | virtual int32 GetPlayerLevel(); |
1 | int32 ICombatInterface::GetPlayerLevel() |
- 玩家继承接口并实现`GetPlayerLevel()
1 | virtual int32 GetPlayerLevel() override; |
1 | int32 AHeroCharacter::GetPlayerLevel() |
- 敌人实现
1 | int32 AEnemyBase::GetPlayerLevel() |
用于根据等级配置生命值和魔法值最大值
1 | // Fill out your copyright notice in the Description page of Project Settings. |
1 | // Fill out your copyright notice in the Description page of Project Settings. |
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.
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 | // Fill out your copyright notice in the Description page of Project Settings. |
1 | // Fill out your copyright notice in the Description page of Project Settings. |
1 | // Fill out your copyright notice in the Description page of Project Settings. |
1 | // Fill out your copyright notice in the Description page of Project Settings. |
声明
TAGS 声明
1 | UPROPERTY(EditDefaultsOnly) |
AI行为树
需要蓝图类:AI控制器,行为树,黑板,任务
添加导航区域
创建AI控制器
打开角色蓝图选择AI控制器
创建行为树
AI控制器执行行为树(开始执行非循环)
行为树添加序列执行
添加计时
添加移动至
添加倒计时
创建黑板(声明变量的)比如向量
创建任务(负责写逻辑)比如获取玩家位置,将黑板值设置为向量
UE开发测试
角色移动
- 基础第三人称蓝图设置
- 角色移动节点:旋转朝向移动打开
- 弹簧臂组件:pawn控制旋转打开
- 玩家关闭使用控制器旋转yaw
- 增强输入
- 引入控制器调用事件,判断控制器,添加增强输入,添加输入映射上下文
- 移动:获取控制器旋转,获取向前向量,添加移动输入
- 鼠标:添加pawn输入,添加PAW输入
模型资产
- 玩家
- 怪物
- 武器:剑,刀,枪—
- 子弹
- 树
- 草
能力系统
- 能力组件添加函数,用于通过数组学习技能
- 玩家组件添加能力数组属性,用于 设置玩家要学习的技能
配置增强输入
+ 创建DataAsset类,文件夹input,然后创建资产文件给控制器(控制器需要声明)
1 |
|
1 |
|
- 增强输入系统基类,项目设置:默认组件输入
1 |
|
1 |
|
创建技能基类
1 |
|
添加输入Tag,可以换其他方法
1 | FGameplayTag InputTag_LMB; //鼠标左键 |
1 | void FMyGameplayTags::InitializeInputGameplayTags() |
控制器调用
1 | UPROPERTY(EditDefaultsOnly, Category="Input") |
1 | void AAuraPlayerController::AbilityInputTagPressed(FGameplayTag InputTag) |
能力组件
1 | //技能 |
1 | void UAuraAbilitySystemComponent::AddCharacterAbilities(const TArray<TSubclassOf<UGameplayAbility>>& StartupAbilities) |














