翻译自Udemy的视频课程introduction-to-unreal-engine-4-ability-system
01、创建一个用于表示技能信息的结构体,具体方式为:创建一个C++actor,命名为AbilityTypes,把它修改成Struct,这种方式比自己手动编码添加Struct要方便(Enum亦然)
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "AbilityTypes.generated.h"//表示当前能力的消耗类型
UENUM(BlueprintType)
enum class EAbilityCostType :uint8 {
Health,
Mana,
Strength
};USTRUCT(BlueprintType)
struct FGameplayAbilityInfo {
GENERATED_BODY()
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AbilityInfo")
float CooldownDuration;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AbilityInfo")
float Cost;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AbilityInfo")
EAbilityCostType CostType;
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AbilityInfo")
UMaterialInstance* UIMat; //slot图标
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AbilityInfo")
TSubclassOfAbilityClass; //对应的AbilityClass类
//两个构造函数
FGameplayAbilityInfo();
FGameplayAbilityInfo(float InCooldownDuration,float InCost, EAbilityCostType InCostType, UMaterialInstance* InUIMat, TSubclassOfInAbilityClass);
};
.cpp文件中需要完成两个构造函数
#include "AbilityTypes.h"FGameplayAbilityInfo::FGameplayAbilityInfo()
:CooldownDuration(0.f),
Cost(0),
CostType(EAbilityCostType::Mana),
UIMat(nullptr),
AbilityClass(nullptr)
{
}FGameplayAbilityInfo::FGameplayAbilityInfo(float InCooldownDuration, float InCost, EAbilityCostType InCostType, UMaterialInstance* InUIMat, TSubclassOf
InAbilityClass)
:CooldownDuration(InCooldownDuration),
Cost(InCost),
CostType(InCostType),
UIMat(InUIMat),
AbilityClass(InAbilityClass)
{
}
02、创建一个C++GameplayAbility类,命名为BaseGameplayAbility,提供所创建的结构体信息的访问方式(GetAbilityInfo),方便程序调用
#pragma once
#include "CoreMinimal.h"
#include "Abilities/GameplayAbility.h"
#include "AbilityTypes.h"
#include "BaseGameplayAbility.generated.h"/**
*
*/
UCLASS()
class ABILITYSYSTEM_API UBaseGameplayAbility : public UGameplayAbility
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "AbilityBase")
UMaterialInstance* UIMaterial;
UFUNCTION(BlueprintCallable)
FGameplayAbilityInfo GetAbilityInfo();
};
对应CPP文件
#include "BaseGameplayAbility.h"
FGameplayAbilityInfo UBaseGameplayAbility::GetAbilityInfo()
{
UGameplayEffect* CoolDownEffect = GetCooldownGameplayEffect();
UGameplayEffect* CostEffect = GetCostGameplayEffect();
if (CoolDownEffect && CostEffect) {
float CoolDownDuration = 0;
float Cost = 0;
EAbilityCostType CostType;
CoolDownEffect->DurationMagnitude.GetStaticMagnitudeIfPossible(1, CoolDownDuration);
if (CostEffect->Modifiers.Num() > 0)
{
FGameplayModifierInfo EffectInfo = CostEffect->Modifiers[0];
EffectInfo.ModifierMagnitude.GetStaticMagnitudeIfPossible(1, Cost);
FGameplayAttribute CostAttr = EffectInfo.Attribute;
FString AttributeName = CostAttr.AttributeName;
if (AttributeName == "Health")
{
CostType = EAbilityCostType::Health;
}
else if (AttributeName == "Mana")
{
CostType = EAbilityCostType::Mana;
}
else if (AttributeName == "Strength")
{
CostType = EAbilityCostType::Strength;
}
//确保获取了所有的信息
return FGameplayAbilityInfo(CoolDownDuration, Cost, CostType, UIMaterial, GetClass());
}
}
return FGameplayAbilityInfo();
}
03、在BasePlayerController中添加AddAbilityToUI方法(使用蓝图继承重写),用于对每个技能设置图标
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/PlayerController.h"
#include "AbilityTypes.h"
#include "BasePlayerController.generated.h"/**
*
*/
UCLASS()
class ABILITYSYSTEM_API ABasePlayerController : public APlayerController
{
GENERATED_BODY()
public:
UFUNCTION(BlueprintImplementableEvent, Category = "PlayControllerBase")
void AddAbilityToUI(FGameplayAbilityInfo AbilityInfo);
};
04、在BaseCharacter中同样添加AddAbilityToUI,用于调用PlayerController的AddAbilityToUI方法,同样提供获取一堆技能的方法
UFUNCTION(BlueprintCallable, Category = BaseCharacter)
//用于获取一堆技能
void AquireAbilities(TArray>AbilitiesToAquire); private:
void AddAbilityToUI(TSubclassOf
AbilityToAdd);
对应的CPP文件中,实现添加的方法(注意添加头文件)
#include "BaseGameplayAbility.h"
#include "AbilityTypes.h"void ABaseCharacter::AquireAbilities(TArray
> AbilitiesToAquire)
{
for (TSubclassOfAbilityItem:AbilitiesToAquire)
{
AquireAbility(AbilityItem);
//如果是UBaseGameplayAbility的子类,说明可以添加UI
if (AbilityItem->IsChildOf(UBaseGameplayAbility::StaticClass()))
{
//这里加*与不加的区别?
TSubclassOfAbilityBaseClass = *AbilityItem;
if (AbilityBaseClass != nullptr)
{
AddAbilityToUI(AbilityBaseClass);
}
}
}
}void ABaseCharacter::AddAbilityToUI(TSubclassOf
AbilityToAdd)
{
ABasePlayerController* PlayerControllerBase = Cast(GetController());
if (PlayerControllerBase)
{
UBaseGameplayAbility* AbilityInstance = AbilityToAdd.Get()->GetDefaultObject();
if (AbilityInstance)
{
FGameplayAbilityInfo AbilityInfo = AbilityInstance->GetAbilityInfo();
PlayerControllerBase->AddAbilityToUI(AbilityInfo);//最终实现是在蓝图中
}
}
}
4、蓝图中实际设置,和UI紧密相关(要是教程的话必须把UI那块也细讲,个人参考时主要理清做了什么,以及之间的联系)
01、首先是Slot:可以根据AbilityInfo来更新图标和Cost信息,可以自定义StartCoolDown事件,在EventTick中更新CoolDown的图标信息
02、PrimaryUI:自定义AddAbilityToSlot函数来添加技能图标,自定义GetSlotAbilityClass函数来获取技能槽中的技能类,EventConstruct里面用于设置图标
03、PlayerController中自定义TryActiveAbilityInSlot函数,设置按键输入绑定,调用各个槽的技能
04、创建BP_BaseGameplayAbility,是C++BaseGameplayAbility的子类,在里面添加一个DoUICoolDown方法,用于调用Slot的StartCoolDown事件
05、将HealthRegen和Dash技能的父类设置为BP_BaseGameplayerAbility。并且为每个技能的CommitAbility后调用DoUICoolDown方法
最终的效果为:调用技能,技能显示冷却(当然也可以优化,当Cost为0的时候,就不显示Cost的值等等)