0
点赞
收藏
分享

微信扫一扫

# 第8章---实现属性菜单相关UI搭建及功能实现

盖码范 03-07 15:30 阅读 2
ue5c++游戏

文件结构

Source

  • Private

    • AbilitySystem
      • Data
        • AttributeInfo.cpp
      • ModMagCalc
        • MMC_MaxHealth.cpp
        • MMC_MaxMana.cpp
      • RPGAbilitySystemComponent.cpp
      • RPGAbilitySystemLibrary.cpp
      • RPGAttributeSet.cpp
    • 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
    • RPGAssetManager.cpp
    • RPGGameplayTags.cpp
  • Public

    • AbilitySystem

      • Data
        • AttributeInfo.h
      • ModMagCalc
        • MMC_MaxHealth.h
        • MMC_MaxMana.h
      • RPGAbilitySystemComponent.h
      • RPGAbilitySystemLibrary.h
      • RPGAttributeSet.h
    • 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
    • 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"));
}
举报

相关推荐

0 条评论