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

文件结构

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"));
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mfbz.cn/a/433574.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Nodejs 第五十章(lua的基本使用)

lua基本使用 全局变量局部变量 全局变量是在全局作用域中定义的变量&#xff0c;可以在脚本的任何地方访问。全局变量在定义时不需要使用关键字&#xff0c;直接赋值即可。 xiaoman xmzsprint(xiaoman)局部变量是在特定作用域内定义的变量&#xff0c;只能在其所属的作用域…

腾讯云4核8G12M轻量服务器优惠价格446元一年,646元15个月

腾讯云4核8G12M轻量服务器优惠价格446元一年&#xff0c;646元15个月&#xff0c;180GB SSD云硬盘&#xff0c;2000GB月流量。 一张表看懂腾讯云服务器租用优惠价格表&#xff0c;一目了然&#xff0c;腾讯云服务器分为轻量应用服务器和云服务器CVM&#xff0c;CPU内存配置从2核…

【笔记】Android ServiceStateTracker 网络状态变化逻辑及SPN更新影响

业务简介 在网络状态变化的时候&#xff08;数据或WiFi&#xff09;&#xff0c;会更新SPN。 基于Android U的代码分析。 分类&#xff1a;SPN Data_Dic-的博客-CSDN博客 功能逻辑 状态说明 飞行模式下注册上WFC的话&#xff0c;注册状态MD上报 regState: NOT_REG_MT_NOT…

SpringBoot 自定义映射规则resultMap collection一对多

介绍 collection是封装一对多关系的&#xff0c;通常情况下是一个列表&#xff0c;association是一对一&#xff0c;通常情况是一个对象。例如&#xff1a;查询班级下所有的学生&#xff0c;一个班级可以有多个学生&#xff0c;这就是一对多。 案例 有一个学生表&#xff0c…

NineData云原生智能数据管理平台新功能发布|2024年2月版

SQL开发&#xff1a;全功能支持百度云 GaiaDB 介绍&#xff1a;支持通过 SQL 开发所有能力管理 GaiaDB 实例。更多信息&#xff0c;请参见&#xff1a;真香&#xff01;NineData SQL 开发全面适配 GaiaDB 场景&#xff1a;企业使用 GaiaDB 管理企业数据&#xff0c;需要一个一…

第五篇:组件更新:完整的 DOM diff 流程是怎样的?(下)

下面我们来继续讲解上节课提到的核心 diff 算法。 新子节点数组相对于旧子节点数组的变化&#xff0c;无非是通过更新、删除、添加和移动节点来完成&#xff0c;而核心 diff 算法&#xff0c;就是在已知旧子节点的 DOM 结构、vnode 和新子节点的 vnode 情况下&#xff0c;以较…

Sora核心之一:可变时长、分辨率、尺寸

Overview 一、总览二、摘要三、引言四、方法4.1、架构改动4.2、训练改变4.3、NaViT的效率 NaViT 一、总览 题目: Patch n’ Pack: NaViT, a Vision Transformer for any Aspect Ratio and Resolution 机构&#xff1a;Google DeepMind 论文: https://arxiv.org/pdf/2307.06304…

python72-Python的函数入门,为函数提供文档

之前介绍过可以使用Python内置的help()函数查看其他函数的帮助文档,我们也经常通过help()函数查看指定函数的帮助信息&#xff0c;这对于Python开发者来说非常重要。 我们还可以为函数编写说明文档一只要把一段字符串放在函数声明之后、函数体之前&#xff0c;这段字符串将被作…

LVGL:切换页面

static lv_obj_t *contanier1 NULL; static lv_obj_t *contanier2 NULL;static void win_btn_event_callback(lv_event_t* e) {lv_event_code_t code lv_event_get_code(e);if (code LV_EVENT_CLICKED){lv_obj_t * obj lv_event_get_target(e);//按钮if(lv_obj_get_child(co…

回溯算法03-电话号码的字母组合(Java)

3.电话号码的字母组合 题目描述 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 示例 1&#xff1a; 输入&#xff1a;d…

#define MODIFY_REG(REG, CLEARMASK, SETMASK)

#define MODIFY_REG(REG, CLEARMASK, SETMASK) WRITE_REG((REG), (((READ_REG(REG)) & (~(CLEARMASK))) | (SETMASK))) 这个宏 MODIFY_REG 是在嵌入式编程中&#xff0c;它用于修改一个寄存器的特定位&#xff0c;而不影响其他位。这个宏接受三个参数&#xff…

onav_rim 复现记录

onav_rim 复现记录 任务复现过程克隆项目&#xff0c;创建环境源码安装habitat-sim从github上安装CLIP环境配置收尾工作数据集下载模型评估其他问题训练训练模型 任务 上次复现one4all失败&#xff0c;但我就是想看看我的电脑能不能做end2end的视觉导航任务。这次看到了《Obje…

Java多线程——信号量Semaphore是啥

目录 引出信号量Semaphore &#xff1f;Redis冲冲冲——缓存三兄弟&#xff1a;缓存击穿、穿透、雪崩缓存击穿缓存穿透缓存雪崩 总结 引出 Java多线程——信号量Semaphore是啥 信号量Semaphore &#xff1f; Semaphore 通常我们叫它信号量&#xff0c; 可以用来控制同时访问特…

Java实现布隆过滤器示例

布隆过滤器&#xff08;Bloom Filter&#xff09;是一种用于快速检查一个元素是否属于一个集合的数据结构。它基于哈希函数的思想&#xff0c;可以在空间和时间上实现高效的元素判断。 布隆过滤器通常用于解决以下问题&#xff1a; 1.快速查询&#xff1a;布隆过滤器可以在常数…

3. 在Go语言项目中使用Zap日志库

文章目录 一、介绍二、 默认的Go Logger1. 实现Go Logger2. 设置Logger3. 使用Logger4. Logger的运行5. Go Logger的优势和劣势 三、Uber-go Zap1. 为什么选择Uber-go zap2. 安装3. 配置Zap Logger4. 定制logger4.1 将日志写入文件而不是终端4.2 将JSON Encoder更改为普通的Log…

大学四年我从非科班到互联网大厂之路

文章目录 一、两度高考、依然选错&#xff1f;二、初来乍到、陷入囹圄三、破局重生、从头再来四、找实习的坎坷之路五、提前结束实习&#xff0c;开始秋招六、秋招一路凯歌七、写在最后&#xff1a;人生是一场长久的旅途 很久没来CSDN上写过文章了&#xff0c;上一次写已经是20…

pycharm安装pojie2024最新

pojie工具请关注微信公众号“program那些事儿”&#xff0c;回复ideapj&#xff0c;即可获取。 一、下载 官网&#xff1a;https://www.jetbrains.com/pycharm/download/?sectionwindows 点击如图所示&#xff0c;下载pycharm专业版的软件&#xff0c;安装就是一步一步的装&a…

让运维无忧,实战解析巡检报告功能实现方案

随着大数据技术的演进和信息安全性需求的提升&#xff0c;数据规模的持续扩张为数据运维工作带来了严峻考验。面对海量数据所形成的繁重管理压力&#xff0c;运维人员面临效率瓶颈&#xff0c;而不断攀升的人力成本也使得单纯依赖扩充运维团队来解决问题变得不再实际可行。 由…

黄金投资是收益高还是风险高?

黄金作为一种传统的投资工具&#xff0c;长久以来一直受到投资者的青睐。然而&#xff0c;在讨论黄金投资的收益与风险时&#xff0c;必须明确一点&#xff1a;黄金投资既有可能带来较高的收益&#xff0c;同时也伴随不可忽视的风险。 从收益的角度来看&#xff0c;黄金投资的确…

Linux上轻松搞定Docker环境安装

Docker环境安装 是否安装docker # 该命令通过查询Docker服务的状态来检查是否已安装&#xff0c;且是否在正常运行 systemctl status docker下面这种状态就是docker正常运行的状态&#xff1a; 安装yum-utils&#xff1a; yum install ‐y yum‐utils device‐mapper‐per…
最新文章