16.UE5RPG获取GE应用的回调,并根据Tag设置数据显示到窗口
- 其他
- 2025-07-23 03:15:01

在上一篇介绍了对标签如何在项目中设置,这一篇先讲解一下如何在GE里面使用GameplayTag标签。 之前我在第十一章节中 11. UE5 RPG使用GameplayEffect修改角色属性(二)介绍了一些GE的属性,在UE 5.3版本中,修改的配置方式,需要在组件里面设置需要的组件 下图为与标签相关的组件
查看当前actor拥有的标签首先,我们在一个用于持续性时间的GE上面添加一个标签,比如我在一个回血的GE上面添加了一个Health的标签 然后运行游戏,按~建打开debug 左上角会显示当前actor拥有的标签,当前actor是没有任何标签的 在应用了对应的GE后,会发现角色身上多出了对应的标签,在GE效果消失后,对应的标签也被剔除。后面的括号内的数值代表当前添加的数量,它也可以被堆叠。注意,通过GE堆叠的方式是无法让标签产生堆叠的。如果设置不堆叠,每个是单独的GE,那么会出现标签堆叠的效果。
ASC使用委托监听GE接下来我们要实现GE被应用时,使用委托触发回调,进行其它处理 翻看ASC.h的源码,会发现有相应的委托代码,委托返回ASC,GE的实例,GE的引用三个参数 接着往下看,会发现基于这个委托宏,创建了多个委托属性,有添加GE给自身触发的,有添加给目标触发的,有持续时间的GE添加给自身触发的,还有周期性触发的GE的委托等等。
鼠标悬停到属性上面也能够查看到对应的返回 接下来,我们要实现的就是绑定委托,在给自身添加GE时,打印GE附加的Asset Tag
在AbilitySystemComponentBase 技能组件基类里面,我们添加一个AbilityActorInfoSet()函数,这个函数用于初始化委托的注册。 然后添加一个委托触发的回调函数EffectApplied()这个函数将在GE被添加的时候触发。
// 版权归暮志未晚所有。 #pragma once #include "CoreMinimal.h" #include "AbilitySystemComponent.h" #include "AbilitySystemComponentBase.generated.h" /** * 技能系统组件 */ UCLASS() class AURA_API UAbilitySystemComponentBase : public UAbilitySystemComponent { GENERATED_BODY() public: void AbilityActorInfoSet(); protected: void EffectApplied(UAbilitySystemComponent* AbilitySystemComponent, const FGameplayEffectSpec& EffectSpec, FActiveGameplayEffectHandle ActiveGameplayEffectHandle); };在cpp中,我们将对其进行实现,AbilityActorInfoSet()中先绑定了一个GE添加到自身的委托,事件触发时将调用EffectApplied()函数,EffectApplied()函数内,现在将获取到GE身上的AssetTags,并通过遍历的形式打印出来。
// 版权归暮志未晚所有。 #include "AbilitySystem/AbilitySystemComponentBase.h" void UAbilitySystemComponentBase::AbilityActorInfoSet() { OnGameplayEffectAppliedDelegateToSelf.AddUObject(this, &UAbilitySystemComponentBase::EffectApplied); } void UAbilitySystemComponentBase::EffectApplied(UAbilitySystemComponent* AbilitySystemComponent, const FGameplayEffectSpec& EffectSpec, FActiveGameplayEffectHandle ActiveGameplayEffectHandle) { // GEngine->AddOnScreenDebugMessage(1, 8.f, FColor::Blue, FString("Effect Applied!")); FGameplayTagContainer TagContainer; EffectSpec.GetAllAssetTags(TagContainer); for(const FGameplayTag& Tag : TagContainer) { //TODO: 将tag广播给Widget Controller const FString Msg = FString::Printf(TEXT("GE Tag: %s"), *Tag.ToString()); //获取Asset Tag GEngine->AddOnScreenDebugMessage(-1, 8.f, FColor::Cyan, Msg); //打印到屏幕上 -1 不会被覆盖 } }ASC的基础类添加了,我们还需要对其进行调用,事件委托的绑定需要在ASC初始化完成后调用。
在所有的角色基类上面我们添加一个virtual void InitAbilityActorInfo();这个函数用于初始化ASC的委托注册,下面为初始化的代码
Cast<UAbilitySystemComponentBase>(AbilitySystemComponent)->AbilityActorInfoSet();在基类上,我们不去做实现,实现在英雄类和敌人类里面去实现。
在英雄类里面,在原来的基础上,初始化ASC后进行调用
void AHeroCharacter::PossessedBy(AController* NewController) { Super::PossessedBy(NewController); //初始化ASC的OwnerActor和AvatarActor InitAbilityActorInfo(); //设置OwnerActor的Controller SetOwner(NewController); } void AHeroCharacter::OnRep_PlayerState() { Super::OnRep_PlayerState(); //初始化ASC的OwnerActor和AvatarActor InitAbilityActorInfo(); } void AHeroCharacter::InitAbilityActorInfo() { APlayerStateBase* PlayerStateBase = GetPlayerState<APlayerStateBase>(); check(PlayerStateBase); //检测是否有效,无限会暂停游戏 //从playerState获取ASC和AS AbilitySystemComponent = PlayerStateBase->GetAbilitySystemComponent(); AttributeSet = PlayerStateBase->GetAttributeSet(); //初始化ASC AbilitySystemComponent->InitAbilityActorInfo(PlayerStateBase, this); //触发Actor的技能信息设置回调 Cast<UAbilitySystemComponentBase>(AbilitySystemComponent)->AbilityActorInfoSet(); //获取PC if(APlayerControllerBase* PlayerControllerBase = Cast<APlayerControllerBase>(GetController())) { if(AMyHUD* HUD = Cast<AMyHUD>(PlayerControllerBase->GetHUD())) { HUD->InitOverlay(PlayerControllerBase, PlayerStateBase, AbilitySystemComponent, AttributeSet); } } }在敌人类里面,初始化委托方式一致
void AEnemyBase::BeginPlay() { Super::BeginPlay(); InitAbilityActorInfo(); } void AEnemyBase::InitAbilityActorInfo() { AbilitySystemComponent->InitAbilityActorInfo(this, this); Cast<UAbilitySystemComponentBase>(AbilitySystemComponent)->AbilityActorInfoSet(); }在初始化完成后,我们在UE里面的GE添加AssetTagsGameplayEffectComponent,并且添加对应的Tags,测试应用时是否有打印。
使用委托将ASC和Widget Controller绑定上面我们实现了获取添加GE时的回调,并能够打印对应GE上面添加的Tags,接下来,我们要实现ASC和Widget Controller之间的沟通,在GE添加时,在WidgetController里面也能够获取到Broadcast广播,并触发对应的回调。
ASC.h在之前的基础上,添加一个委托宏设置FEffectAssetTags,然后定义一个属性EffectAssetTags用于后续的广播。
// 版权归暮志未晚所有。 #pragma once #include "CoreMinimal.h" #include "AbilitySystemComponent.h" #include "AbilitySystemComponentBase.generated.h" DECLARE_MULTICAST_DELEGATE_OneParam(FEffectAssetTags, const FGameplayTagContainer& /* AssetTags */) /** * 技能系统组件 */ UCLASS() class AURA_API UAbilitySystemComponentBase : public UAbilitySystemComponent { GENERATED_BODY() public: void AbilityActorInfoSet(); FEffectAssetTags EffectAssetTags; protected: void EffectApplied(UAbilitySystemComponent* AbilitySystemComponent, const FGameplayEffectSpec& EffectSpec, FActiveGameplayEffectHandle ActiveGameplayEffectHandle); };在cpp里,EffectApplied是添加GE后的事件回调,之前我们是直接在这里打印的tags,现在我们修改成获取到TagContainer后,将TagContainer进行委托广播出去。
// 版权归暮志未晚所有。 #include "AbilitySystem/AbilitySystemComponentBase.h" void UAbilitySystemComponentBase::AbilityActorInfoSet() { OnGameplayEffectAppliedDelegateToSelf.AddUObject(this, &UAbilitySystemComponentBase::EffectApplied); } void UAbilitySystemComponentBase::EffectApplied(UAbilitySystemComponent* AbilitySystemComponent, const FGameplayEffectSpec& EffectSpec, FActiveGameplayEffectHandle ActiveGameplayEffectHandle) { // GEngine->AddOnScreenDebugMessage(1, 8.f, FColor::Blue, FString("Effect Applied!")); FGameplayTagContainer TagContainer; EffectSpec.GetAllAssetTags(TagContainer); EffectAssetTags.Broadcast(TagContainer); }之前我们制作的,先初始化ASC完成以后,然后通过HUD类对Widget用户控件初始化,然后再对Widget Controller初始化的。所以,在初始化Widget Controller时,ASC是初始化完成的。 我们在Widget Controller绑定事件委托里面,添加对ASC的委托EffectAssetTags进行监听即可。
以下是用户控件使用的Widget Controller的初始化委托监听的函数,前面的是之前监听AS属性值变化的代码,后面我们通过AddLambda添加了一个匿名函数,用于监听EffectAssetTags,并在里面进行测试打印。
void UOverlayWidgetController::BindCallbacksToDependencies() { const UAttributeSetBase* AttributeSetBase = CastChecked<UAttributeSetBase>(AttributeSet); AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate( AttributeSetBase->GetHealthAttribute()).AddUObject(this, &UOverlayWidgetController::HealthChanged); AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate( AttributeSetBase->GetMaxHealthAttribute()).AddUObject(this, &UOverlayWidgetController::MaxHealthChanged); AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate( AttributeSetBase->GetManaAttribute()).AddUObject(this, &UOverlayWidgetController::ManaChanged); AbilitySystemComponent->GetGameplayAttributeValueChangeDelegate( AttributeSetBase->GetMaxManaAttribute()).AddUObject(this, &UOverlayWidgetController::MaxManaChanged); //AddLambda 绑定匿名函数 Cast<UAbilitySystemComponentBase>(AbilitySystemComponent)->EffectAssetTags.AddLambda( [](const FGameplayTagContainer& AssetTags) { for(const FGameplayTag& Tag : AssetTags) { //将tag广播给Widget Controller const FString Msg = FString::Printf(TEXT("GE Tag in Widget Controller: %s"), *Tag.ToString()); //获取Asset Tag GEngine->AddOnScreenDebugMessage(-1, 8.f, FColor::Cyan, Msg); //打印到屏幕上 -1 不会被覆盖 } } ); }接着运行代码,发现左上角打印了对应的tags,代表代码无误。
创建标签消息委托上面我们实现了可以在添加GE的时候,打印GE身上的Tag,接下来,将实现在Widget里面通过委托获取GE的应用标签。
首先,在WidgetController里面,创建一个结构体,这个结构体可以被蓝图使用。 结构体内主要存储一些数据,用于在ui上面展示使用,所以,我们需要GE的信息Tag,提示文本信息,使用的Widget控件,以及显示的图片都存储到结构体内。
USTRUCT(BlueprintType) struct FUIWidgetRow : public FTableRowBase { GENERATED_BODY(); UPROPERTY(EditAnywhere, BlueprintReadOnly) FGameplayTag MessageTag = FGameplayTag(); UPROPERTY(EditAnywhere, BlueprintReadOnly) FText Message = FText(); UPROPERTY(EditAnywhere, BlueprintReadOnly) TSubclassOf<class UMyUserWidget> MessageWidget; UPROPERTY(EditAnywhere, BlueprintReadOnly) UTexture2D* Image = nullptr; };编译后,创建一个数据表格,类就选择我们创建的结构体。 接下来,我们要实现数据使用的内容,首先创建信息Tag,在GameplayTag标签管理器里面,添加信息标签。 到现在我们还没有创建Widget显示控件,先把别的内容填上 接下来在WidgetController上面增加一个配置项,用于配置数据
//EditDefaultsOnly 说明此属性可以通过属性窗口编辑,但只能在原型上进行。 UPROPERTY(EditDefaultsOnly, BlueprintReadOnly, Category="Widget Data") TObjectPtr<UDataTable> MessageWidgetDataTable;将刚才创建的数据表格设置 接着创建一个可以通过Tag在数据表格中寻找对应的数据的函数,为了兼容不同的数据表格,这里我们使用不确定的T类型,在调用时指定返回类型。
//根据传入的表格和Tag返回查找到的数据,表格类型不确定,所以使用T来表示,在使用此函数时,需要指定对应类型 template<typename T> T* GetDataTableRowByTag(UDataTable* DataTable, const FGameplayTag& Tag); template <typename T> T* UOverlayWidgetController::GetDataTableRowByTag(UDataTable* DataTable, const FGameplayTag& Tag) { T* Row = DataTable->FindRow<T>(Tag.GetTagName(), TEXT("")); return Row; }在之前我们实现的匿名函数里面,首先添加的GE内是否包含Message的Tag,如果包含,则广播出去。
//AddLambda 绑定匿名函数 Cast<UAbilitySystemComponentBase>(AbilitySystemComponent)->EffectAssetTags.AddLambda( [this](const FGameplayTagContainer& AssetTags) //中括号添加this是为了保证内部能够获取类的对象 { for(const FGameplayTag& Tag : AssetTags) { //对标签进行检测,如果不是信息标签,将无法进行广播 FGameplayTag MessageTag = FGameplayTag::RequestGameplayTag(FName("Message")); // "A.1".MatchesTag("A") will return True, "A".MatchesTag("A.1") will return False if(Tag.MatchesTag(MessageTag)) { FUIWidgetRow* Row = GetDataTableRowByTag<FUIWidgetRow>(MessageWidgetDataTable, Tag); MessageWidgetRowDelegate.Broadcast(*Row); //前面加*取消指针引用 } } } );代码逻辑基本实现到这,然后我们需要在药瓶的GE里面添加Tag 然后做一个测试,在Widget中,先将Controller类型转换为OverlayWidgetController 接着监听数据返回,打印信息 数据能够打印,证明准确无误
创建信息Widget结构体内,我们还有一项没有实现,那就是Widget组件,接下来,我们将实现这个组件。 首先创建一个用户控件,基类就使用我们之前实现的基类 在Widget里面,创建一个显示图片和文本的对象组件。 如果以水平框作为最外层,会被父节点拉伸,我们可以使用一个覆层包裹一下。
图表里面增加一个设置图片和文本的蓝图函数。 创建完成,我们可以将数据表格的数据填充上去对于的Widget
接下来,我们就可以修改Overlay的debug的蓝图,不用再打印文本,而是直接添加widget到视口。 下图为修改后的蓝图节点,我们使用数据创建一个widget,并设置显示在屏幕中间, 接下来,我们给widget制作了一个新的动画,并添加到了设置函数上面,在设置完成属性后,播放动画 播放动画后面的执行,是直接执行的,不是在动画播放完成执行,所以,我们需要制作一个事件,在延迟动画的时间后,销毁掉,并在销毁回调中测试 在测试捡起药瓶后,检查动画是否播放完成,回调是否触发,这样不会造成内存溢出。
16.UE5RPG获取GE应用的回调,并根据Tag设置数据显示到窗口由讯客互联其他栏目发布,感谢您对讯客互联的认可,以及对我们原创作品以及文章的青睐,非常欢迎各位朋友分享到个人网站或者朋友圈,但转载请说明文章出处“16.UE5RPG获取GE应用的回调,并根据Tag设置数据显示到窗口”