行业知识
第6章---GameplayTag初识以及拾起物品UI制作
2026-11-09 03:30:52
来源:互联网转载
文件结构
Source
()- Private
- AbilitySystemComponen
- RPGAbilitySystemComponent.cpp
- RPGAttributeSet.cpp
- Character
- PGGameCharacterBase.cpp
- RPGGameEnemy.cpp
- RPGGamePlayerCharacter.cpp
- Game
- RPGGameModeBase.cpp
- Interaction
- EnemyInterface.cpp
- Player
- RPGPlayerController.cpp
- RPGPlayerState.cpp
- Actor
- RPGEffectActor.cpp
- UI
- HUD
- RPGHUD.cpp
- WidgetController
- OverlayWidgetController.cpp
- RPGWidgetController.cpp
- Widgets
- RPGUserWidget.cpp
- Public
- AbilitySystemComponent
- RPGAbilitySystemComponent.h
- RPGAttributeSet.h
- Character
- RPGGameCharacterBase.h
- RPGGameEnemy.h
- RPGGamePlayerCharacter.h
- Game
- RPGGameModeBase.h
- Interaction
- EnemyInterface.h
- Player
- RPGPlayerController.h
- RPGPlayerState.h
- Actor
- RPGEffectActor.h
- UI
- HUD
- RPGHUD.h
- WidgetController
- OverlayWidgetController.h
- RPGWidgetController.h
- Widgets
- RPGUserWidget.h
文件概述
RPGAbilitySystemComponent
.h文件
// Copyright KimiLiu#pragma once#include "CoreMinimal.h"#include "AbilitySystemComponent.h"#include "RPGAbilitySystemComponent.generated.h"DECLARE_MULTICAST_DELEGATE_OneParam(FEffectAssetTags, const FGameplayTagContainer&/*AssetTags*/);/** * Ability System Component 拥有两个Owner: Owner Actor 以及Avatar Actor,这两个Actor有可能相同,有可能不相同 * Owner Actor 指的是实例化组件的Actor * Avatar Actor 指的是ASC实际上服务的Actor,例如 * - RPGGameEnemy 内的ASC的 Owner Actor 和 Avatar Actor 都是 RPGGameEnemy 这个 Actor 类自身。因为ASC由 RPGGameEnemy 实例 * 化,同时服务于 RPGGameEnemy * - RPGGamePlayerCharacter 内的ASC的 Owner Actor 是 RPGPlayerState,而 Avatar Actor 是RPGGamePlayerCharacter。因为 * ASC由RPGPlayerState实例化,但是ASC服务于PRGGamePlayerCharacter */UCLASS()class AURA_API URPGAbilitySystemComponent : public UAbilitySystemComponent{ GENERATED_BODY()public: // ASC初始化完成(设置了实际所有者以及逻辑所有者) void AbilityActorInfoSet(); // FEffectAssetTags EffectAssetTags;protected: // 当有任何GE在自身上被应用时会触发委托调用该函数 void EffectApplied(UAbilitySystemComponent* AbilitySystemComponent, const FGameplayEffectSpec& GameplayEffectSpec, FActiveGameplayEffectHandle ActiveGameplayEffectHandle); };.cpp文件
// Copyright KimiLiu#include "AbilitySytstem/RPGAbilitySystemComponent.h"void URPGAbilitySystemComponent::AbilityActorInfoSet(){ // 绑定委托 OnGameplayEffectAppliedDelegateToSelf.AddUObject(this, &URPGAbilitySystemComponent::EffectApplied);}void URPGAbilitySystemComponent::EffectApplied(UAbilitySystemComponent* AbilitySystemComponent, const FGameplayEffectSpec& GameplayEffectSpec, FActiveGameplayEffectHandle ActiveGameplayEffectHandle){ //GEngine->AddOnScreenDebugMessage(1, 5.f, FColor::Red, FString("Effect Applied")); FGameplayTagContainer TagContainer; GameplayEffectSpec.GetAllAssetTags(TagContainer); // 广播 EffectAssetTags.Broadcast(TagContainer); }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;};/** * AS拥有预测功能(Prediction)能够让多人游戏的客户端在拥有更少的延迟。客户端能够立刻改变自己维护的AS,然后通知服务端,由服务端判定这个更 * 改是否合法,如果不合法,则服务端拒绝更改AS并通知客户端回滚AS */UCLASS()class AURA_API URPGAttributeSet : public UAttributeSet{ GENERATED_BODY()public: URPGAttributeSet(); //复制变量时必须重写的函数,用于注册需要复制的变量 virtual void GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const override; //在属性被更改前调用,不用来处理逻辑,只用来限制值大小 virtual void PreAttributeChange(const FGameplayAttribute& Attribute, float& NewValue) override; //在属性被更改后调用,用来处理逻辑 virtual void PostGameplayEffectExecute(const FGameplayEffectModCallbackData& Data) override; /** * 创建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 */ UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Health, Category="Vital Attribute") FGameplayAttributeData Health; ATTRIBUTE_ACCESSORS(URPGAttributeSet, Health); UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_MaxHealth, Category="Vital Attribute") FGameplayAttributeData MaxHealth; ATTRIBUTE_ACCESSORS(URPGAttributeSet, MaxHealth); UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Mana, Category="Vital Attribute") FGameplayAttributeData Mana; ATTRIBUTE_ACCESSORS(URPGAttributeSet, Mana); UPROPERTY(BlueprintReadOnly, ReplicatedUsing = OnRep_Mana, Category="Vital Attribute") FGameplayAttributeData MaxMana; ATTRIBUTE_ACCESSORS(URPGAttributeSet, MaxMana); 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;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"URPGAttributeSet::URPGAttributeSet(){ InitHealth(50.f); InitMaxHealth(100.f); InitMana(50.f); InitMaxMana(100.f);}void URPGAttributeSet::GetLifetimeReplicatedProps(TArray& OutLifetimeProps) const{ Super::GetLifetimeReplicatedProps(OutLifetimeProps); //注册需要复制的属性Health,没有复制条件,不论复制的结果是否等于客户端原有结果,都进行复制调用 DOREPLIFETIME_CONDITION_NOTIFY(URPGAttributeSet, Health, COND_None, REPNOTIFY_Always); DOREPLIFETIME_CONDITION_NOTIFY(URPGAttributeSet, MaxHealth, COND_None, REPNOTIFY_Always); DOREPLIFETIME_CONDITION_NOTIFY(URPGAttributeSet, Mana, COND_None, REPNOTIFY_Always); DOREPLIFETIME_CONDITION_NOTIFY(URPGAttributeSet, MaxMana, COND_None, REPNOTIFY_Always);}// 此处的Clamp只能更改CurrentValue,不能更改BaseValue,因此还需要在Post函数中做一次Clampvoid 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(Props.SourceAvatarActor)) { Props.SourceAvatarActor = Pawn->GetController(); } } // 获取来源角色 if (Props.SourceController) { Props.SourceCharacter = Cast(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(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()) { GEngine->AddOnScreenDebugMessage(1, 3.f, FColor::Red, FString::Printf(TEXT("Health: %f"), GetHealth())); SetHealth(FMath::Clamp(GetHealth(), 0.f, GetMaxHealth())); } if (Data.EvaluatedData.Attribute == GetManaAttribute()) { GEngine->AddOnScreenDebugMessage(1, 3.f, FColor::Blue, FString::Printf(TEXT("Mana: %f"), GetHealth())); SetMana(FMath::Clamp(GetMana(), 0.f, GetMaxMana())); } }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);}OverlayWidgetController
.h文件
// Copyright KimiLiu#pragma once#include "CoreMinimal.h"#include "AbilitySytstem/RPGAttributeSet.h"#include "UI/WidgetController/RPGWidgetController.h"#include "OverlayWidgetController.generated.h"USTRUCT(BlueprintType)struct FUIWidgetRow : public FTableRowBase{ GENERATED_BODY() UPROPERTY(EditAnywhere, BlueprintReadOnly) FGameplayTag MessageTag = FGameplayTag(); UPROPERTY(EditAnywhere, BlueprintReadOnly) FText Message = FText(); UPROPERTY(EditAnywhere, BlueprintReadOnly) TSubclassOf MessageData; UPROPERTY(EditAnywhere, BlueprintReadOnly) UTexture2D* Image = nullptr;};class URPGUserWidget;DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnAttributeChangeSignature, float, NewValue);DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FMessageWidgetRowSignature, FUIWidgetRow, Row);/** * */UCLASS(BlueprintType, Blueprintable)class AURA_API UOverlayWidgetController : public URPGWidgetController{ GENERATED_BODY()public: virtual void BroadcastInitialValues() override; virtual void BindCallbacksToDependences() override; UPROPERTY(BlueprintAssignable, Category="GAS|Attribute") FOnAttributeChangeSignature OnHealthChanged; UPROPERTY(BlueprintAssignable, Category="GAS|Attribute") FOnAttributeChangeSignature OnMaxHealthChanged; UPROPERTY(BlueprintAssignable, Category="GAS|Attribute") FOnAttributeChangeSignature OnManaChanged; UPROPERTY(BlueprintAssignable, Category="GAS|Attribute") FOnAttributeChangeSignature OnMaxManaChanged; UPROPERTY(BlueprintAssignable, Category="GAS|Messages") FMessageWidgetRowSignature MessageWidgetRowDelegate;protected: UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Widget Data") TObjectPtr MessageWidgetDataTable; // ~Start Delegate Function // ~End Delegate Function // 自定义带的模板函数,以后可以常用,指定父类可以获得多个子类的相关函数 template T* GetDataTableRowByTag(UDataTable* DataTable, const FGameplayTag& Tag); };// 模板函数实现template T* UOverlayWidgetController::GetDataTableRowByTag(UDataTable* DataTable, const FGameplayTag& Tag){ T* Row = DataTable->FindRow(Tag.GetTagName(), TEXT("")); return Row;}.cpp文件
.AddLambda可以把函数直接写在()内,不需要多写一个函数,方便了很多,可以后期一次性看到我们绑定的函数是啥,以及这个函数干嘛用的
// Copyright KimiLiu#include "UI/WidgetController/OverlayWidgetController.h"#include "AbilitySytstem/RPGAbilitySystemComponent.h"#include "AbilitySytstem/RPGAttributeSet.h"//初始化多播执行事件void UOverlayWidgetController::BroadcastInitialValues(){ //父类的AttributeSet类型是UAttributeSet不是RPGAttributeSet需要自行Cast const URPGAttributeSet* RPGAttributeSet = CastChecked(AttributeSet); //执行初始化多播通知 OnHealthChanged.Broadcast(RPGAttributeSet->GetHealth()); OnMaxHealthChanged.Broadcast(RPGAttributeSet->GetMaxHealth()); OnManaChanged.Broadcast(RPGAttributeSet->GetMana()); OnMaxManaChanged.Broadcast(RPGAttributeSet->GetMaxMana()); }// 绑定(注册)Attribute改变事件,当Attribute的基础值改变的时候,会执行相应Attribute的对应的函数void UOverlayWidgetController::BindCallbacksToDependences(){ const URPGAttributeSet* RPGAttributeSet = CastChecked(AttributeSet); AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate( RPGAttributeSet->GetHealthAttribute()).AddLambda( [this](const FOnAttributeChangeData& Data) { OnHealthChanged.Broadcast(Data.NewValue); } ); AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate( RPGAttributeSet->GetMaxHealthAttribute()).AddLambda( [this](const FOnAttributeChangeData& Data) { OnMaxHealthChanged.Broadcast(Data.NewValue); } ); AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate( RPGAttributeSet->GetManaAttribute()).AddLambda( [this](const FOnAttributeChangeData& Data) { OnManaChanged.Broadcast(Data.NewValue); } ); AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate( RPGAttributeSet->GetMaxManaAttribute()).AddLambda( [this](const FOnAttributeChangeData& Data) { OnMaxManaChanged.Broadcast(Data.NewValue); } ); Cast(AbilitySystemComponent)->EffectAssetTags.AddLambda( [this](const FGameplayTagContainer& AssetTags) { for(FGameplayTag Tag : AssetTags) { // "A.1".MatchesTag("A") will return True, "A".MatchesTag("A.1") will return False FGameplayTag MessageTag = FGameplayTag::RequestGameplayTag(FName("Message")); if (Tag.MatchesTag(MessageTag)) { FUIWidgetRow* Row = GetDataTableRowByTag(MessageWidgetDataTable, Tag); MessageWidgetRowDelegate.Broadcast(*Row); } } } );}// ~Delegate Function Start // ~Delegate Function End()
- RPGUserWidget.h
- HUD
- AbilitySystemComponent
- HUD
- AbilitySystemComponen
上一篇:红警ol怎么加入服务器?
下一篇:宝塔面板怎么更改配置?