GamplayAbility 简称 GA,是GAS里面做技能的地方,释放的技能都通过他来实现,同时负责法力的消耗以及cd的管理。具体详细GA介绍前往4.6观看
// ----------------------------------------------------------------------------------------------------------------
//
// 游戏能力中的重要函数:
//
// CanActivateAbility() - 一个const函数,用于检查能力是否可以被激活。可以被UI等调用
//
// TryActivateAbility() - 尝试激活能力。调用CanActivateAbility()。输入事件可以直接调用此函数。
// - 还处理每次执行的实例逻辑和复制/预测调用。
//
// CallActivateAbility() - 受保护的、非虚函数。做一些“激活前”的准备工作,然后调用ActivateAbility()
//
// ActivateAbility() - 能力实际执行的操作。这是子类希望覆盖的地方。
//
// CommitAbility() - 提交资源/冷却时间等。ActivateAbility()必须调用此函数!
//
// CancelAbility() - 从外部源中断能力(例如,通过输入事件)。
//
// EndAbility() - 能力结束。这个函数应由能力自身调用以结束自己。
//
// ----------------------------------------------------------------------------------------------------------------
制作一个GA的基类以及连段GA
创建一个继承GameplayAbility
的CGameplayAbility
类作为后续技能的基类
再继承CGameplayAbility
类创建一个GA_Combo
#pragma once
#include "CoreMinimal.h"
#include "GAS/Core/CGameplayAbility.h"
#include "GA_Combo.generated.h"
/**
*
*/
UCLASS()
class UGA_Combo : public UCGameplayAbility
{
GENERATED_BODY()
public:
// 技能激活
virtual void ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo, const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData) override;
private:
UPROPERTY(EditDefaultsOnly, Category = "Animation")
TObjectPtr<UAnimMontage> ComboMontage;
};
#include "GAS/Abilities/GA_Combo.h"
#include "Abilities/Tasks/AbilityTask_PlayMontageAndWait.h"
void UGA_Combo::ActivateAbility(const FGameplayAbilitySpecHandle Handle, const FGameplayAbilityActorInfo* ActorInfo,
const FGameplayAbilityActivationInfo ActivationInfo, const FGameplayEventData* TriggerEventData)
{
// 检查能否释放技能(如消耗、冷却等),不能则直接结束
if (!K2_CommitAbility())
{
K2_EndAbility();
return;
}
// 服务器或预测端:播放Montage并监听动画和连招事件
if (HasAuthorityOrPredictionKey(ActorInfo, &ActivationInfo))
{
// 蒙太奇任务代理
UAbilityTask_PlayMontageAndWait* PlayComboMontageTask = UAbilityTask_PlayMontageAndWait::CreatePlayMontageAndWaitProxy(this, NAME_None, ComboMontage);
// 设置动画结束时的回调:当动画自然结束时结束技能
PlayComboMontageTask->OnBlendOut.AddDynamic(this, &UGA_Combo::K2_EndAbility);
// 设置动画被取消时的回调:当动画被手动取消时结束技能
PlayComboMontageTask->OnCancelled.AddDynamic(this, &UGA_Combo::K2_EndAbility);
// 设置动画完成时的回调:当动画正常播放完成时结束技能
PlayComboMontageTask->OnCompleted.AddDynamic(this, &UGA_Combo::K2_EndAbility);
// 设置动画被中断时的回调:当动画被其他事件中断时结束技能
PlayComboMontageTask->OnInterrupted.AddDynamic(this, &UGA_Combo::K2_EndAbility);
// 调用此函数激活任务,实际开始播放动画
PlayComboMontageTask->ReadyForActivation();
}
}
在CAbilitySystemComponent
创建赋予技能的方法以及存储技能的数组
// 幻雨喜欢小猫咪
#pragma once
#include "CoreMinimal.h"
#include "AbilitySystemComponent.h"
#include "CAbilitySystemComponent.generated.h"
/**
*
*/
UCLASS()
class UCAbilitySystemComponent : public UAbilitySystemComponent
{
GENERATED_BODY()
public:
// 初始效果
void ApplyInitialEffects();
// 技能初始化
void GiveInitialAbilities();
private:
UPROPERTY(EditDefaultsOnly, Category = "Gameplay Effects")
TArray<TSubclassOf<UGameplayEffect>> InitialEffects;
// 基础技能
UPROPERTY(EditDefaultsOnly, Category = "Gameplay Ability")
TArray<TSubclassOf<UGameplayAbility>> BasicAbilities;
// 技能
UPROPERTY(EditDefaultsOnly, Category = "Gameplay Ability")
TArray<TSubclassOf<UGameplayAbility>> Abilities;
};
初始化函数GiveInitialAbilities
的实现
void UCAbilitySystemComponent::GiveInitialAbilities()
{
// 检查当前组件是否拥有拥有者,并且拥有者是否具有网络权限(权威性)
if (!GetOwner() || !GetOwner()->HasAuthority()) return;
for (const TSubclassOf<UGameplayAbility>& AbilityClass : BasicAbilities)
{
// 赋予技能 等级为 1
GiveAbility(FGameplayAbilitySpec(AbilityClass, 1, -1, nullptr));
}
for (const TSubclassOf<UGameplayAbility>& AbilityClass : Abilities)
{
GiveAbility(FGameplayAbilitySpec(AbilityClass, 0, -1, nullptr));
}
}
然后在角色基类中添加一下初始化的调用
void ACCharacter::ServerSideInit()
{
// 设置当前角色作为Owner和Avatar,用于后续的能力和效果应用
CAbilitySystemComponent->InitAbilityActorInfo(this, this);
CAbilitySystemComponent->ApplyInitialEffects();
CAbilitySystemComponent->GiveInitialAbilities();
}
让角色调用GA
再蓝图中创建GA
随便放一个蒙太奇
简单测试
播放动画蒙太奇还需要插槽
添加与之对应的插槽名称
然后就能播放蒙太奇了,然而这样的技能点击过快会有一些鬼畜,需要添加tag来阻止技能的激活。另外还有一些脚滑,那么再添加标签之前再优化一下动画蓝图。
实现变跑变打
不跑的时候可以调用下半身动画
增加阻挡标签
关于标签的添加可以在项目设置中添加Tag
我比较喜欢在代码中添加方便调用
// 幻雨喜欢小猫咪
#pragma once
#include "CoreMinimal.h"
#include "NativeGameplayTags.h"
#include "GameplayTagContainer.h"
/**
*
*/
namespace TGameplayTags
{
// CRUNCH_是你的项目名称
CRUNCH_API UE_DECLARE_GAMEPLAY_TAG_EXTERN(Ability_BasicAttack)
}
// 幻雨喜欢小猫咪
#include "GAS/Core/TGameplayTags.h"
namespace TGameplayTags
{
// ""双引号内的是tag的定义名称,第二条的是是可以添加注释的方法
//UE_DEFINE_GAMEPLAY_TAG(Ability_BasicAttack, "Ability.BasicAttack")
UE_DEFINE_GAMEPLAY_TAG_COMMENT(Ability_BasicAttack, "Ability.BasicAttack", "基础攻击能力");
}
上面这样就可以实现了Tag
的创建,编译后这个tag就会出现了,tag的创建方法有很多我就不一一列举了。
再创建一个蓝图函数库用来实现各种方法
// 幻雨喜欢小猫咪
#pragma once
#include "CoreMinimal.h"
#include "GameplayTagContainer.h"
#include "Kismet/BlueprintFunctionLibrary.h"
#include "CAbilitySystemStatics.generated.h"
/**
*
*/
UCLASS()
class UCAbilitySystemStatics : public UBlueprintFunctionLibrary
{
GENERATED_BODY()
public:
static FGameplayTag GetBasicAttackAbilityTag();
};
#include "GAS/Core/CAbilitySystemStatics.h"
#include "TGameplayTags.h"
FGameplayTag UCAbilitySystemStatics::GetBasicAttackAbilityTag()
{
// 如果不喜欢用代码创建tag可以用下列方法,感觉有打错字的风险
// 可以使用这种方法来获取到tag
//return FGameplayTag::RequestGameplayTag("ability.basic attack");
// 在cpp函数中定义的tag的获取方法如下
return TGameplayTags::Ability_BasicAttack;
}
在GA_Combo
中添加构造函数,对技能添加Tag
UGA_Combo::UGA_Combo()
{
//两种方法都能将Tag放过去
//AbilityTags.AddTag(TGameplayTags::Ability_BasicAttack);
// 添加“基础攻击”标签,标识该技能为基础攻击
AbilityTags.AddTag(UCAbilitySystemStatics::GetBasicAttackAbilityTag());
// 设置互斥标签,防止同一时间释放多个基础攻击
BlockAbilitiesWithTag.AddTag(UCAbilitySystemStatics::GetBasicAttackAbilityTag());
}