欢迎大家加入Unreal Engine C++ & Blueprint群一起交流:1143575617
当角色的招式过多的时候,会带来一些困扰。一个GA招式,需要至少3个GE的效果。如果这个角色有六个招式,那么它至少需要18个GE的效果。当你对某个GE效果不满意的时候,想去调整,会非常麻烦,也容易混淆。
本节通过C++代码建立一个GameplayAbility类,将它下挂的所有我们想获得的GE的数据进行搜集,然后放到一个结构体中,这样再让其他的GA继承自这个自定义的GameplayAbility类,就能轻松获得所有我们想要的GE的数据。
我们先新建一个Actor类,删除除了头文件以外的所有东西,再建立一个枚举类和一个结构体,这些数据就是我们想要从GE收集的数据。
ACTOR类头文件如下:
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "AbilityInfoType.generated.h"
class UMyGameplayAbility;
class UMaterialInstance;
//把想从GA中获得的GE的所有数据打包到这个ACTOR中的枚举与结构体中了。
UENUM(BlueprintType)
enum class ECostType : uint8 {
Health,
Heal,
Mana
};
USTRUCT(BlueprintType)
struct FGameplayAbilityInfo {
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FGameplayAbilityInfo")
float Cost;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FGameplayAbilityInfo")
float CoolDownDuration;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FGameplayAbilityInfo")
ECostType costType;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FGameplayAbilityInfo")
UMaterialInstance* MUI;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "FGameplayAbilityInfo")
TSubclassOf<UMyGameplayAbility> AbilityClass;
FGameplayAbilityInfo();
FGameplayAbilityInfo(float InCost,float InCoolDownDuration,ECostType IncostType,UMaterialInstance*InMUI, TSubclassOf<UMyGameplayAbility> InAbilityClass);
};
CPP文件内容如下:
// Fill out your copyright notice in the Description page of Project Settings.
#include "AbilityInfoType.h"
FGameplayAbilityInfo::FGameplayAbilityInfo():Cost(0), CoolDownDuration(0), costType(ECostType::Health), MUI(nullptr), AbilityClass(nullptr)
{
}
FGameplayAbilityInfo::FGameplayAbilityInfo(float InCost, float InCoolDownDuration, ECostType IncostType, UMaterialInstance* InMUI, TSubclassOf<UMyGameplayAbility> InAbilityClass)
:Cost(InCost),CoolDownDuration(InCoolDownDuration),costType(IncostType),MUI(InMUI),AbilityClass(InAbilityClass){
}
CPP中内容很简单,主要是对参数进行了初始化。这里定义了两个构造函数是为了一会将打包好的数据返回。
接下来,我们新建一个GameplayAbility类。
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "Abilities/GameplayAbility.h"
#include "AbilityInfoType.h"
#include "MyGameplayAbility.generated.h"
/**
*
*/
UCLASS()
class SHIBI_API UMyGameplayAbility : public UGameplayAbility
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "GameplayAbilityInfo")
UMaterialInstance* Mats;
UFUNCTION(BlueprintCallable, Category = "GameplayAbilityInfo")
FGameplayAbilityInfo GetGameplayAbilityInfo();
};
这里重要的就是我们定义了一个方法用于返回我们之前定义好的结构体数据类型。 记得把我们ACTOR类的头文件导入。
这是CPP文件内容。
#include "MyGameplayAbility.h"
//这个GA就是用来搜集它下挂的所有GE的属性,那些我们想要的属性,获得后打包到结构体中。
FGameplayAbilityInfo UMyGameplayAbility::GetGameplayAbilityInfo()
{
UGameplayEffect* CooldownEffect = GetCooldownGameplayEffect();
UGameplayEffect* CostEffect = GetCostGameplayEffect();
ECostType costType;
if (CooldownEffect && CostEffect) {
float CoolDownDuration = 0;
CooldownEffect->DurationMagnitude.GetStaticMagnitudeIfPossible(1, CoolDownDuration);
float CostValue = 0;
if (CostEffect->Modifiers.Num() > 0) {
FGameplayModifierInfo selectedModifier = CostEffect->Modifiers[0];
selectedModifier.ModifierMagnitude.GetStaticMagnitudeIfPossible(1, CostValue);
FString costAttrName = selectedModifier.Attribute.AttributeName;
if (costAttrName == "Health") {
costType = ECostType::Health;
}
else if (costAttrName == "Heal") {
costType = ECostType::Heal;
}
else if (costAttrName == "Mana") {
costType = ECostType::Mana;
}
}
return FGameplayAbilityInfo(CostValue,CoolDownDuration,costType,Mats,this->GetClass());
}
return FGameplayAbilityInfo();
}
现在我们对上述代码重要部分进行逐行解释。
UGameplayEffect* CooldownEffect = GetCooldownGameplayEffect();
UGameplayEffect* CostEffect = GetCostGameplayEffect();
这两行代码,定义了两个变量,都是UGameplayEffect类型的,很明显是接收GE对象的。这个GE对象从哪来?
从这里来。
拿到这两个变量之后,说明咱们从GA中对其下挂的GE产生了联系。
float CoolDownDuration = 0;
CooldownEffect->DurationMagnitude.GetStaticMagnitudeIfPossible(1, CoolDownDuration);
先来看技能冷却的GE,调用了DurationMagnitude属性。
其实是想获得Scalable Float Magnitude属性的数值,所以要从DurationMagnitude属性开始获取。
GetStaticMagnitudeIfPossible方法就是用来获取Scalable Float Magnitude属性的数值的,从源码就可以看出来:
当MagnitudeCalculationType为ScalableFloat类型的时候,就返回其值。
然后是获取CostEffect的属性值。
if (CostEffect->Modifiers.Num() > 0) {
FGameplayModifierInfo selectedModifier = CostEffect->Modifiers[0];
selectedModifier.ModifierMagnitude.GetStaticMagnitudeIfPossible(1, CostValue);
FString costAttrName = selectedModifier.Attribute.AttributeName;
......
}
CostEffect的属性是在Modifiers下面的,Modifiers是数组,0代表着数组第一位元素。
我们现在想拿到第一位元素的Attribute和Scalable Float Magnitude属性的值。
首先需要判断数组是否有FGmaplayModifierInfo类型的变量,通过CostEffect->Modifiers[0]拿到第一个元素。
再通过这第一个元素拿到数值。
最后想拿到Mana属性的值可以通过Attribute属性下的AttributeName属性或者GetName()方法拿到。
将收集全的数据打包返回。
return FGameplayAbilityInfo(CostValue,CoolDownDuration,costType,Mats,this->GetClass());
这样我们就可以轻松从蓝图中获得这些数据用作他用,或者去管理这些数据了。