文件结构
Source
-
Private
- AbilitySystem
- Data
- AttributeInfo.cpp
- ModMagCalc
- MMC_MaxHealth.cpp
- MMC_MaxMana.cpp
- RPGAbilitySystemComponent.cpp
- RPGAbilitySystemLibrary.cpp
- RPGAttributeSet.cpp
- Data
- Character
- PGGameCharacterBase.cpp
- RPGGameEnemy.cpp
- RPGGamePlayerCharacter.cpp
- Game
- RPGGameModeBase.cpp
- Interaction
- EnemyInterface.cpp
- CombatInterface.cpp
- Player
- RPGPlayerController.cpp
- RPGPlayerState.cpp
- Actor
- RPGEffectActor.cpp
- UI
- HUD
- RPGHUD.cpp
- WidgetController
- OverlayWidgetController.cpp
- AttributeMenuWidgetController.cpp
- RPGWidgetController.cpp
- Widgets
- RPGUserWidget.cpp
- HUD
- RPGAssetManager.cpp
- RPGGameplayTags.cpp
- AbilitySystem
-
Public
-
AbilitySystem
- Data
- AttributeInfo.h
- ModMagCalc
- MMC_MaxHealth.h
- MMC_MaxMana.h
- RPGAbilitySystemComponent.h
- RPGAbilitySystemLibrary.h
- RPGAttributeSet.h
- Data
-
Character
- RPGGameCharacterBase.h
- RPGGameEnemy.h
- RPGGamePlayerCharacter.h
-
Game
- RPGGameModeBase.h
-
Interaction
- EnemyInterface.h
- CombatInterface.h
-
Player
- RPGPlayerController.h
- RPGPlayerState.h
-
Actor
- RPGEffectActor.h
-
UI
- HUD
- RPGHUD.h
- WidgetController
- OverlayWidgetController.h
- AttributeMenuWidgetController.h
- RPGWidgetController.h
- Widgets
- RPGUserWidget.h
- HUD
-
RPGAssetManager.h
-
RPGGameplayTags.h
-
文件概述
AttributeInfo
.h文件
// Copyright KimiLiu
#pragma once
#include "CoreMinimal.h"
#include "GameplayTagContainer.h"
#include "Engine/DataAsset.h"
#include "AttributeInfo.generated.h"
USTRUCT(BlueprintType)
struct FRPGAttributeInfo
{
GENERATED_BODY()
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
FGameplayTag AttributeTag = FGameplayTag();
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
FText AttributeName = FText();
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
FText AttributeDescription = FText();
UPROPERTY(BlueprintReadOnly)
float AttributeValue = 0.f;
};
/**
* 继承自DataAsset
*/
UCLASS()
class AURA_API UAttributeInfo : public UDataAsset
{
GENERATED_BODY()
public:
// 给GameplayTag找到与这个GameplayTag相关的信息
FRPGAttributeInfo FindAttributeInfoForTag(const FGameplayTag& AttributeTag, bool bLogNotFound = false);
// AttributeInfo队列,在蓝图内填写,不需要在C++内填写
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
TArray<FRPGAttributeInfo> AttributeInformation;
};
.cpp文件
// Copyright KimiLiu
#include "AbilitySytstem/Data/AttributeInfo.h"
FRPGAttributeInfo UAttributeInfo::FindAttributeInfoForTag(const FGameplayTag& AttributeTag, bool bLogNotFound)
{
for (const FRPGAttributeInfo& Info : AttributeInformation)
{
if (Info.AttributeTag.MatchesTag(AttributeTag))
{
return Info;
}
}
if (bLogNotFound)
{
UE_LOG(LogTemp, Error,
TEXT("Can't find Info for AttributeTag [%s] on AttributeInfo [%s]."),*AttributeTag.ToString(), *GetNameSafe(this) );
}
return FRPGAttributeInfo();
}
RPGAbilitySystemLibrary
.h文件
// Copyright KimiLiu
#pragma once
#include "CoreMinimal.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "RPGAbilitySystemLibrary.generated.h"
class UAttributeMenuWidgetController;
class UOverlayWidgetController;
/**
* Blueprint Function Library
* 给蓝图以及C++调用
*/
UCLASS()
class AURA_API URPGAbilitySystemLibrary : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
// 获取OverlayWidgetController
UFUNCTION(BlueprintPure, Category="RPGAbilitySystemLibrary|WidgetController")
static UOverlayWidgetController* GetOverlayWidgetController(const UObject* WorldContextObject);
// 获取AttributeWidgetController
UFUNCTION(BlueprintPure, Category="RPGAbilitySystemLibrary|WidgetController")
static UAttributeMenuWidgetController* GetAttributeWidgetController(const UObject* WorldContextObject);
};
.cpp文件
// Copyright KimiLiu
#include "AbilitySytstem/RPGAbilitySystemLibrary.h"
#include "Kismet/GameplayStatics.h"
#include "Player/RPGPlayerState.h"
#include "UI/HUD/RPGHUD.h"
#include "UI/WidgetController/RPGWidgetController.h"
UOverlayWidgetController* URPGAbilitySystemLibrary::GetOverlayWidgetController(const UObject* WorldContextObject)
{
if (APlayerController*PC = UGameplayStatics::GetPlayerController(WorldContextObject, 0))
{
if (ARPGHUD* RPGHUD = Cast<ARPGHUD>(PC->GetHUD()))
{
ARPGPlayerState* PS = PC->GetPlayerState<ARPGPlayerState>();
UAbilitySystemComponent* ASC = PS->GetAbilitySystemComponent();
UAttributeSet* AS = PS->GetAttributeSet();
const FWidgetControllerParams WidgetControllerParams(PC, PS, ASC, AS);
return RPGHUD->GetOverlayWidgetController(WidgetControllerParams);
}
}
return nullptr;
}
UAttributeMenuWidgetController* URPGAbilitySystemLibrary::GetAttributeWidgetController(const UObject* WorldContextObject)
{
if (APlayerController* PC = UGameplayStatics::GetPlayerController(WorldContextObject, 0))
{
if (ARPGHUD* RPGHUD = Cast<ARPGHUD>(PC->GetHUD()))
{
ARPGPlayerState* PS = PC->GetPlayerState<ARPGPlayerState>();
UAbilitySystemComponent* ASC = PS->GetAbilitySystemComponent();
UAttributeSet* AS = PS->GetAttributeSet();
const FWidgetControllerParams WidgetControllerParams(PC, PS, ASC, AS);
return RPGHUD->GetAttributeMenuWidgetController(WidgetControllerParams);
}
}
return nullptr;
}
RPGAttributeSet
.h文件
// Copyright KimiLiu
#pragma once
#include "CoreMinimal.h"
#include "AbilitySystemComponent.h"
#include "AttributeSet.h"
#include "RPGAttributeSet.generated.h"
#define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)
// 逻辑处理数据结构,在这个结构中能够获取目标ASC以及源头ASC,以及目标对象,源头对象,目标控制器,源头控制器
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;
};
// 模板定义
// typedef TBaseStaticDelegateInstance<FGameplayAttribute(), FDefaultDelegateUserPolicy>::FFuncPtr FAttributeFuncPtr;
template <class T>
using TStaticFuncPtr = typename TBaseStaticDelegateInstance<T, FDefaultDelegateUserPolicy>::FFuncPtr;
/**
* AS拥有预测功能(Prediction)能够让多人游戏的客户端在拥有更少的延迟。客户端能够立刻改变自己维护的AS,然后通知服务端,由服务端判定这个更
* 改是否合法,如果不合法,则服务端拒绝更改AS并通知客户端回滚AS
*/
UCLASS()
class AURA_API URPGAttributeSet : public UAttributeSet
{
GENERATED_BODY()
public:
URPGAttributeSet();
//复制变量时必须重写的函数,用于注册需要复制的变量
virtual void GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const override;
//在属性被更改前调用,不用来处理逻辑,只用来限制值大小
virtual void PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) override;
//在属性被更改后调用,用来处理逻辑
virtual void PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data) override;
// 模板定义使用,定义一个Map,将Tag与方法指针配对,该方法指针指向的是一个静态函数,该静态函数需要在FGameplayAttribute类内
TMap<FGameplayTag, TStaticFuncPtr<FGameplayAttribute()>> TagsToAttributes;
//TMap<FGameplayTag, FGameplayAttribute(*)()> TagsToAttributes;
/**
* 创建AS属性步骤:
* 1. 声明FGameplayAttributeData类型变量
* 2. 用UPROPERTY()宏修饰
* 3. 如果是多人游戏,需要在宏内声明: ReplicatedUsing = OnRep_属性名,同时声明一个UFUNCTION()方法OnRep_属性名()。当服务端的该属性
* 值变化时,OnRep_属性名()将会被调用,我们在这个函数内处理变化事件
* 4. 实现OnRep_属性名()函数,在函数内调用GAMEPLAYATTRIBUTE_REPNOTIFY(URPGAttributeSet, 属性名, 旧属性值)宏,用来保存旧值用于
* 服务端通知客户端进行回滚
* 5. 重写GetLifetimeReplicatedProps()函数,在该函数内注册属性
* 6. 使用ATTRIBUTE_ACCESSORS()宏来初始化value_getter, property_getter, value_setter, initter
*/
/*
* Primary Attributes
*/
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Strength, Category="Primary Attribute")
FGameplayAttributeData Strength;
ATTRIBUTE_ACCESSORS(URPGAttributeSet, Strength);
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Intelligence, Category="Primary Attribute")
FGameplayAttributeData Intelligence;
ATTRIBUTE_ACCESSORS(URPGAttributeSet, Intelligence);
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Resilience, Category="Primary Attribute")
FGameplayAttributeData Resilience;
ATTRIBUTE_ACCESSORS(URPGAttributeSet, Resilience);
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Vigor, Category="Primary Attribute")
FGameplayAttributeData Vigor;
ATTRIBUTE_ACCESSORS(URPGAttributeSet, Vigor);
/*
* Secondary Attributes
*/
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Armor, Category="Secondary Attribute")
FGameplayAttributeData Armor;
ATTRIBUTE_ACCESSORS(URPGAttributeSet, Armor);
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_ArmorPenetration, Category="Secondary Attribute")
FGameplayAttributeData ArmorPenetration;
ATTRIBUTE_ACCESSORS(URPGAttributeSet, ArmorPenetration);
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_BlockChance, Category="Secondary Attribute")
FGameplayAttributeData BlockChance;
ATTRIBUTE_ACCESSORS(URPGAttributeSet, BlockChance);
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_CriticalHitChance, Category="Secondary Attribute")
FGameplayAttributeData CriticalHitChance;
ATTRIBUTE_ACCESSORS(URPGAttributeSet, CriticalHitChance);
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_CriticalHitDamage, Category="Secondary Attribute")
FGameplayAttributeData CriticalHitDamage;
ATTRIBUTE_ACCESSORS(URPGAttributeSet, CriticalHitDamage);
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_CriticalHitResistance, Category="Secondary Attribute")
FGameplayAttributeData CriticalHitResistance;
ATTRIBUTE_ACCESSORS(URPGAttributeSet, CriticalHitResistance);
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_HealthRegeneration, Category="Secondary Attribute")
FGameplayAttributeData HealthRegeneration;
ATTRIBUTE_ACCESSORS(URPGAttributeSet, HealthRegeneration);
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_ManaRegeneration, Category="Secondary Attribute")
FGameplayAttributeData ManaRegeneration;
ATTRIBUTE_ACCESSORS(URPGAttributeSet, ManaRegeneration);
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_MaxHealth, Category="Vital Attribute")
FGameplayAttributeData MaxHealth;
ATTRIBUTE_ACCESSORS(URPGAttributeSet, MaxHealth);
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Mana, Category="Vital Attribute")
FGameplayAttributeData MaxMana;
ATTRIBUTE_ACCESSORS(URPGAttributeSet, MaxMana);
/*
* Vital Attributes
*/
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Health, Category="Vital Attribute")
FGameplayAttributeData Health;
ATTRIBUTE_ACCESSORS(URPGAttributeSet, Health);
UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Mana, Category="Vital Attribute")
FGameplayAttributeData Mana;
ATTRIBUTE_ACCESSORS(URPGAttributeSet, Mana);
UFUNCTION()
void OnRep_Health(const FGameplayAttributeData& OldHealth) const;
UFUNCTION()
void OnRep_MaxHealth(const FGameplayAttributeData& OldMaxHealth) const ;
UFUNCTION()
void OnRep_Mana(const FGameplayAttributeData& OldMana) const;
UFUNCTION()
void OnRep_MaxMana(const FGameplayAttributeData& OldMaxMana) 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& OldRegeneration) const;
private:
//设置FEffectProperties类数据,Props内有很多信息,参照上面的结构体声明
void SetEffectProperties(const FGameplayEffectModCallbackData& Data, FEffectProperties& Props) const;
};
.cpp文件
// Copyright KimiLiu
#include "AbilitySytstem/RPGAttributeSet.h"
#include "AbilitySystemBlueprintLibrary.h"
#include "Net/UnrealNetwork.h"
#include "GameplayEffectExtension.h"
#include "GameFramework/Character.h"
#include "RPGGameplayTags.h"
URPGAttributeSet::URPGAttributeSet()
{
const FRPGGameplayTags& GameplayTags = FRPGGameplayTags::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_CriticalHitDamage, GetCriticalHitDamageAttribute);
TagsToAttributes.Add(GameplayTags.Attributes_Secondary_CriticalHitResistance, GetCriticalHitResistanceAttribute);
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);
}
void URPGAttributeSet::GetLifetimeReplicatedProps(TArray<FLifetimeProperty>& OutLifetimeProps) const
{
Super::GetLifetimeReplicatedProps(OutLifetimeProps);
// 注册需要复制的属性Health,没有复制条件,不论复制的结果是否等于客户端原有结果,都进行复制调用
// Primary Attributes
DOREPLIFETIME_CONDITION_NOTIFY(URPGAttributeSet, Strength, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(URPGAttributeSet, Intelligence, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(URPGAttributeSet, Resilience, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(URPGAttributeSet, Vigor, COND_None, REPNOTIFY_Always);
// Secondary Attributes
DOREPLIFETIME_CONDITION_NOTIFY(URPGAttributeSet, Armor, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(URPGAttributeSet, ArmorPenetration, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(URPGAttributeSet, BlockChance, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(URPGAttributeSet, CriticalHitChance, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(URPGAttributeSet, CriticalHitDamage, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(URPGAttributeSet, CriticalHitResistance, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(URPGAttributeSet, HealthRegeneration, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(URPGAttributeSet, ManaRegeneration, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(URPGAttributeSet, MaxHealth, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(URPGAttributeSet, MaxMana, COND_None, REPNOTIFY_Always);
// Vital Attributes
DOREPLIFETIME_CONDITION_NOTIFY(URPGAttributeSet, Health, COND_None, REPNOTIFY_Always);
DOREPLIFETIME_CONDITION_NOTIFY(URPGAttributeSet, Mana, COND_None, REPNOTIFY_Always);
}
// 此处的Clamp只能更改CurrentValue,不能更改BaseValue,因此还需要在Post函数中做一次Clamp
void URPGAttributeSet::PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue)
{
Super::PreAttributeChange(Attribute, NewValue);
if (Attribute == GetHealthAttribute())
{
NewValue = FMath::Clamp(NewValue, 0.f, GetMaxHealth());
}
if (Attribute == GetMaxHealthAttribute())
{
}
if (Attribute == GetManaAttribute())
{
NewValue = FMath::Clamp(NewValue, 0.f, GetMaxMana());
}
if (Attribute == GetMaxManaAttribute())
{
}
}
void URPGAttributeSet::SetEffectProperties(const FGameplayEffectModCallbackData& Data, FEffectProperties& Props) const
{
// Source = causer of the effect, Target = target of the effect (owner of this AS)
// 拿到源头的上下文,上下文内拥有指向ASC的指针
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();
// 若ASC组件没有控制器,则从逻辑拥有者那里获取控制器
if (Props.SourceController == nullptr && Props.SourceAvatarActor != nullptr)
{
// Source有可能没有Controller
if (const APawn* Pawn = Cast<APawn>(Props.SourceAvatarActor))
{
Props.SourceAvatarActor = Pawn->GetController();
}
}
// 获取来源角色
if (Props.SourceController)
{
Props.SourceCharacter = Cast<ACharacter>(Props.SourceController->GetPawn());
}
}
// 拿到目标Actor
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);
}
}
// Data 很强大,我们可以从中拿到任何我们想拿到的东西,但是得注意是否是空指针,需要做判断
void URPGAttributeSet::PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data)
{
Super::PostGameplayEffectExecute(Data);
// Source = causer of the effect, Target = target of the effect (owner of this AS)
FEffectProperties Props;
SetEffectProperties(Data, Props);
// 可以用Prps来取到我们想要的值,处理大部分逻辑
if (Data.EvaluatedData.Attribute == GetHealthAttribute())
{
SetHealth(FMath::Clamp(GetHealth(), 0.f, GetMaxHealth()));
GEngine->AddOnScreenDebugMessage(1, 3.f, FColor::Red, FString::Printf(TEXT("Health: %f"), GetHealth()));
}
if (Data.EvaluatedData.Attribute == GetManaAttribute())
{
SetMana(FMath::Clamp(GetMana(), 0.f, GetMaxMana()));
GEngine->AddOnScreenDebugMessage(1, 3.f, FColor::Blue, FString::Printf(TEXT("Mana: %f"), GetMana()));
}
}
void URPGAttributeSet::OnRep_Health(const FGameplayAttributeData& OldHealth) const
{
// 当Health属性被调用,此函数被调用,传入OldHealth作为旧值,该旧值将会被保存以免服务端通知客户端该属性需要回滚
GAMEPLAYATTRIBUTE_REPNOTIFY(URPGAttributeSet, Health, OldHealth);
}
void URPGAttributeSet::OnRep_MaxHealth(const FGameplayAttributeData& OldMaxHealth) const
{
GAMEPLAYATTRIBUTE_REPNOTIFY(URPGAttributeSet, Health, OldMaxHealth);
}
void URPGAttributeSet::OnRep_Mana(const FGameplayAttributeData& OldMana) const
{
GAMEPLAYATTRIBUTE_REPNOTIFY(URPGAttributeSet, Mana, OldMana);
}
void URPGAttributeSet::OnRep_MaxMana(const FGameplayAttributeData& OldMaxMana) const
{
GAMEPLAYATTRIBUTE_REPNOTIFY(URPGAttributeSet, MaxMana, OldMaxMana);
}
void URPGAttributeSet::OnRep_Strength(const FGameplayAttributeData& OldStrength) const
{
GAMEPLAYATTRIBUTE_REPNOTIFY(URPGAttributeSet, Strength, OldStrength);
}
void URPGAttributeSet::OnRep_Intelligence(const FGameplayAttributeData& OldIntelligence) const
{
GAMEPLAYATTRIBUTE_REPNOTIFY(URPGAttributeSet, Intelligence, OldIntelligence);
}
void URPGAttributeSet::OnRep_Resilience(const FGameplayAttributeData& OldResilience) const
{
GAMEPLAYATTRIBUTE_REPNOTIFY(URPGAttributeSet, Resilience, OldResilience);
}
void URPGAttributeSet::OnRep_Vigor(const FGameplayAttributeData& OldVigor) const
{
GAMEPLAYATTRIBUTE_REPNOTIFY(URPGAttributeSet, Vigor, OldVigor);
}
void URPGAttributeSet::OnRep_Armor(const FGameplayAttributeData& OldArmor) const
{
GAMEPLAYATTRIBUTE_REPNOTIFY(URPGAttributeSet, Armor, OldArmor);
}
void URPGAttributeSet::OnRep_ArmorPenetration(const FGameplayAttributeData& OldArmorPenetration) const
{
GAMEPLAYATTRIBUTE_REPNOTIFY(URPGAttributeSet, ArmorPenetration, OldArmorPenetration);
}
void URPGAttributeSet::OnRep_BlockChance(const FGameplayAttributeData& OldBlockChance) const
{
GAMEPLAYATTRIBUTE_REPNOTIFY(URPGAttributeSet, BlockChance, OldBlockChance);
}
void URPGAttributeSet::OnRep_CriticalHitChance(const FGameplayAttributeData& OldCriticalHitChance) const
{
GAMEPLAYATTRIBUTE_REPNOTIFY(URPGAttributeSet, CriticalHitChance, OldCriticalHitChance);
}
void URPGAttributeSet::OnRep_CriticalHitDamage(const FGameplayAttributeData& OldCriticalHitDamage) const
{
GAMEPLAYATTRIBUTE_REPNOTIFY(URPGAttributeSet, CriticalHitDamage, OldCriticalHitDamage);
}
void URPGAttributeSet::OnRep_CriticalHitResistance(const FGameplayAttributeData& OldCriticalHitResistance) const
{
GAMEPLAYATTRIBUTE_REPNOTIFY(URPGAttributeSet, CriticalHitResistance, OldCriticalHitResistance);
}
void URPGAttributeSet::OnRep_HealthRegeneration(const FGameplayAttributeData& OldHealthRegeneration) const
{
GAMEPLAYATTRIBUTE_REPNOTIFY(URPGAttributeSet, HealthRegeneration, OldHealthRegeneration);
}
void URPGAttributeSet::OnRep_ManaRegeneration(const FGameplayAttributeData& OldManaRegeneration) const
{
GAMEPLAYATTRIBUTE_REPNOTIFY(URPGAttributeSet, ManaRegeneration, OldManaRegeneration);
}
AttributeMenuWidgetController
.h文件
// Copyright KimiLiu
#pragma once
#include "CoreMinimal.h"
#include "AbilitySytstem/Data/AttributeInfo.h"
#include "UI/WidgetController/RPGWidgetController.h"
#include "AttributeMenuWidgetController.generated.h"
struct FGameplayAttribute;
struct FRPGAttributeInfo;
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FAttributeInfoSignature, const FRPGAttributeInfo&, Info);
/**
*
*/
UCLASS(BlueprintType, Blueprintable)
class AURA_API UAttributeMenuWidgetController : public URPGWidgetController
{
GENERATED_BODY()
public:
virtual void BroadcastInitialValues() override;
virtual void BindCallbacksToDependences() override;
// 委托,用来通知UI进行数据更新
UPROPERTY(BlueprintAssignable, Category="GAS|Attributes")
FAttributeInfoSignature AttributeInfoDelegate;
protected:
// AttributeInfo 即我们的数据资产DataAsset,由蓝图实现
UPROPERTY(EditDefaultsOnly)
TObjectPtr<UAttributeInfo> AttributeInfo;
private:
// 广播给对应的Widget进行信息更新
void BroadcastAttributeInfo(const FGameplayTag& AttributeTag, const FGameplayAttribute& Attribute) const;
};
.cpp文件
// Copyright KimiLiu
#include "UI/WidgetController/AttributeMenuWidgetController.h"
#include "AbilitySytstem/RPGAttributeSet.h"
void UAttributeMenuWidgetController::BroadcastInitialValues()
{
URPGAttributeSet* AS = Cast<URPGAttributeSet>(AttributeSet);
check(AttributeInfo);
for (auto& Pair : AS->TagsToAttributes)
{
BroadcastAttributeInfo(Pair.Key, Pair.Value());
}
}
void UAttributeMenuWidgetController::BindCallbacksToDependences()
{
URPGAttributeSet* AS = Cast<URPGAttributeSet>(AttributeSet);
for (auto& Pair : AS->TagsToAttributes)
{
AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate(Pair.Value()).AddLambda(
[this, Pair](const FOnAttributeChangeData& Data)
{
BroadcastAttributeInfo(Pair.Key, Pair.Value());
}
);
}
}
void UAttributeMenuWidgetController::BroadcastAttributeInfo(const FGameplayTag& AttributeTag,
const FGameplayAttribute& Attribute) const
{
FRPGAttributeInfo Info = AttributeInfo->FindAttributeInfoForTag(AttributeTag);
Info.AttributeValue = Attribute.GetNumericValue(AttributeSet);
AttributeInfoDelegate.Broadcast(Info);
}
RPGAssetManager
.h文件
// Copyright KimiLiu
#pragma once
#include "CoreMinimal.h"
#include "Engine/AssetManager.h"
#include "RPGAssetManager.generated.h"
/**
* 单例!!!整个项目只有这一个实例,可以随便调用Get()函数,拿到的一定是这一个manager
*/
UCLASS()
class AURA_API URPGAssetManager : public UAssetManager
{
GENERATED_BODY()
public:
static URPGAssetManager& Get();
protected:
//系统调用
virtual void StartInitialLoading() override;
};
.cpp文件
// Copyright KimiLiu
#include "RPGAssetManager.h"
#include "RPGGameplayTags.h"
URPGAssetManager& URPGAssetManager::Get()
{
check(GEngine);
URPGAssetManager* RPGAssetManager = Cast<URPGAssetManager>(GEngine->AssetManager);
return *RPGAssetManager;
}
void URPGAssetManager::StartInitialLoading()
{
Super::StartInitialLoading();
// 初始化项目Tag
FRPGGameplayTags::InitializeNativeGameplayTags();
}
RPGGameplayTags
.h文件
// Copyright KimiLiu
#pragma once
#include "CoreMinimal.h"
#include "GameplayTagContainer.h"
/**
* RPGGameplayTags
* 单例模式!!!!!
* 包含本地游戏标签的单例
*/
struct FRPGGameplayTags
{
public:
// 获取该单例
static const FRPGGameplayTags& Get() {return GameplayTags;};
// 注册GameplayTag
static void InitializeNativeGameplayTags();
// ~Begin Primary GameplayTag
FGameplayTag Attributes_Primary_Strength;
FGameplayTag Attributes_Primary_Intelligence;
FGameplayTag Attributes_Primary_Resilience;
FGameplayTag Attributes_Primary_Vigor;
// ~Begin Secondary GameplayTag
FGameplayTag Attributes_Secondary_MaxHealth;
FGameplayTag Attributes_Secondary_MaxMana;
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;
protected:
private:
static FRPGGameplayTags GameplayTags;
};
.cpp文件
// Copyright KimiLiu
#include "RPGGameplayTags.h"
#include "GameplayTagsManager.h"
FRPGGameplayTags FRPGGameplayTags::GameplayTags;
// C++增加GameplayTag的方法
void FRPGGameplayTags::InitializeNativeGameplayTags()
{
/*
* 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("Ignored 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"));
}