虚幻引擎GAS入门(一)
Gameplay Ability System(GAS)
是一个模块化且强大的框架,用于管理虚幻引擎中的游戏玩法逻辑。它的核心组成部分包括 Gameplay Ability(定义和执行能力)、Gameplay Effect(应用和管理效果)、Attribute Set(管理角色属性)、Gameplay Tags(标记和管理对象状态)、Gameplay Tasks(处理异步任务)以及 Gameplay Modifiers(修改属性值)。这些组件相互协作,使得开发者能够创建复杂且高度定制化的游戏玩法,如技能系统、状态效果系统等。- Gameplay Ability System(GAS)组成部分及其功能
- 学习位置UE5.3 GAS入门教程重置版 小明
创建工程
- 创建工程然后开启
GameplayAbilites
插件
- 在工程
.Build.cs
里添加这三个模块:"GameplayAbilities","GameplayTags","GameplayTasks"
- 编译后会报
307
错误,把这几个文件删除重新构建编译一下即可
- 创建基础角色类并新建基础角色的蓝图,然后创建两个继承这个蓝图的子类作为角色与敌人
简易角色基本控制
- 添加一个第三人称模版,然后删除掉就会有它给你做好的轴操作控制
- 留下需要的即可
- 然后将导入的资产中那个蓝图里面的操作复制到我们创建的角色蓝图中去更改这个轴操作
- 勾上
- 勾掉这个,角色就能正常转体
2种相机模式与夹角限制
- 首先将输入操作从角色蓝图移动到控制器蓝图中
- 限制视角
- 在玩家蓝图中写一个函数用来锁定相机操作
攻击动作的融合
- 创建混合空间设置好动作行为
- 创建动画蓝图设置初始属性
- 配置蒙太奇
- 攻击蒙太奇与移动进行融合,就可以边走边攻击了
- 这个攻击蒙太奇人物会转身,为了避免这种人物突然旋转的情况,要在蒙太奇中添加通知来是否需要融合
- 最后进行攻击动作的融合输出到最终状态
GAS结合GamePlay
- 添加
AbilitySystem
组件
- 添加技能的基类蓝图
- 获取技能
- 创建一个函数用来使用Melee
- 创建一个函数用来激活技能
- 然后在技能蓝图里面添加
Melee
这个标签
- 将技能标签添加到数组中
- 然后
Melee
事件调用激活技能这个函数
- 测试一下
- 运行结果
- 换为播放Montage
- 添加一个
GameplayEffect
技能CD,以免出现攻击反复无常的情况
- 提交CD
- 给剑添加碰撞盒
- 碰撞除了自己与同类不进行碰撞处理,其他进行碰撞处理
设置角色属性
-
新建一个
AttributeSet
类
-
虚幻引擎中提供了一种宏,帮助函数,可以很方便加载游戏的特殊的方法
#define ATTRIBUTE_ACCESSORS(ClassName, PropertyName)
GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName)
GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName)
GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName)
GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)
- 定义好属性
cpp
// Fill out your copyright notice in the Description page of Project Settings.
#pragma once
#include "CoreMinimal.h"
#include "AttributeSet.h"
#include "AbilitySystemComponent.h"
#include "BaseAttributeSet.generated.h"
/**
*
*/
#define ATTRIBUTE_ACCESSORS(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_PROPERTY_GETTER(ClassName, PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_GETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_SETTER(PropertyName) \
GAMEPLAYATTRIBUTE_VALUE_INITTER(PropertyName)
UCLASS()
class GASDEMO_API UBaseAttributeSet : public UAttributeSet
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere,BlueprintReadWrite,Category = "BaseAttributeSet")
FGameplayAttributeData HP;
ATTRIBUTE_ACCESSORS(UBaseAttributeSet, HP);
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "BaseAttributeSet")
FGameplayAttributeData MaxHP;
ATTRIBUTE_ACCESSORS(UBaseAttributeSet, MaxHP);
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "BaseAttributeSet")
FGameplayAttributeData MP;
ATTRIBUTE_ACCESSORS(UBaseAttributeSet, MP);
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "BaseAttributeSet")
FGameplayAttributeData MaxMP;
ATTRIBUTE_ACCESSORS(UBaseAttributeSet, MaxMP);
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "BaseAttributeSet")
FGameplayAttributeData Strength;
ATTRIBUTE_ACCESSORS(UBaseAttributeSet, Strength);
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "BaseAttributeSet")
FGameplayAttributeData MaxStrength;
ATTRIBUTE_ACCESSORS(UBaseAttributeSet, MaxStrength);
};
- 解决小bug,武器碰撞盒子只有在挥刀的时候才开启碰撞
- 将碰撞盒子的碰撞修改一下
伤害敌人并做夹值处理
- 新建一个数据表把角色属性加入到里面
- 将这个表设置到角色属性的
AbilitySystem
里面去
- 再新建一个
GameplayEffect
作为伤害受理,每次扣血5点值
- 在Melee攻击检测这里应用这个
GE
- 运行结果
- 处理伤害溢出问题
- 写上夹值逻辑
- 运行结果
行为树配置
- 关于两个镜头的处理,取消碰撞测试就不会让镜头被挡,启动
- 做不同等级的伤害表,新建一个
.csv
的表,第一行第一列是要空着的,然后写入伤害等级值
- 将表格拖入UE中,选择类型为曲线表格,插值类型为常量
- 将表格插入到伤害的
GE
中
- 新建行为树与黑板进行配置
- 创建
AIController
,然后执行行为树,将这个AIController
附加到Enemy
蓝图上
生命值改变时广播
- 将所有的碰撞类型改成这样
- 基础父类蓝图里面开始时将剑的碰撞盒子关掉
- 把之前的动画通知改变通道变成设置碰撞
- 在基础角色类中声明动态多播委托,因为多播委托可以在蓝图中调用
- 创建一个多播委托的处理函数
- 绑定多播委托
- 订阅一下这个广播
- 运行结果
死亡处理
- 制作一下死亡的
Montage
动画
- 添加一个死亡处理事件
停止AIController控制
- 在敌人蓝图里面添加一个停止控制的函数
- 在敌人蓝图里面重写一下父类中的检查血量的事件
- 玩家蓝图中也要重写这个事件
添加敌人的血条
- 创建一个UMG制作敌人血条
- 在敌人蓝图中添加这个UMG组件,并写上更新UI逻辑
- 运行结果
玩家住UI制作与构建技能结构体系
搭建玩家UI界面
- 创建玩家的属性UI
- 这个纹理有两个暴露出来设置的值,一个是设置百分比一个是设置颜色
- 添加一个事件来设置血球的百分比
- 添加一个事件来设置血球的颜色
- 创建角色的主UI,然后设置好这三个属性球的颜色
同步UI到玩家信息
- 在玩家控制器里面添加这个主UI窗口
- 获取到角色的控制器,然后进行血量的数值变化逻辑
给玩家一个自动回复血量Buffer
- 创建一个继承自基础技能的回复
Buffer
技能
- 添加效果
- 设置好技能效果的回复属性
- 激活技能
- 提交技能
构建技能信息结构体
- 创建一个
GameplayAbility
基类
- 创建技能信息的数据
获取技能信息与创建技能图标
获取技能详细信息函数
- 获取技能信息
cpp
// Fill out your copyright notice in the Description page of Project Settings.
#include "BaseGameplayAbility.h"
FGameplayAbilityInfo::FGameplayAbilityInfo():
CD(0),
CostValue(0),
CostType(ECostType::MP),
IconMaterial(nullptr),
AbilityClass(nullptr)
{
}
FGameplayAbilityInfo::FGameplayAbilityInfo(float CD, ECostType CostType, float CostValue, UMaterialInstance* IconMaterial, TSubclassOf<UBaseGameplayAbility> AbilityClass):
CD(CD),
CostType(CostType),
CostValue(CostValue),
IconMaterial(IconMaterial),
AbilityClass(AbilityClass)
{
}
FGameplayAbilityInfo UBaseGameplayAbility::GetAbilityInfo(int Level)
{
//获取与技能冷却相关的游戏效果
UGameplayEffect* CDEffect = GetCooldownGameplayEffect();
//获取与技能使用成本相关的游戏效果
UGameplayEffect* CostEffect = GetCostGameplayEffect();
float CD = 0;
float CostValue = 0;
ECostType CostType = ECostType::MP;
if (CDEffect && CostEffect)
{
CDEffect->DurationMagnitude.GetStaticMagnitudeIfPossible(Level, CD);
if (CostEffect->Modifiers.Num() > 0)
{
//获取花费的是哪一个类型
FGameplayModifierInfo CostEffectModifierInfo = CostEffect->Modifiers[0];
CostEffectModifierInfo.ModifierMagnitude.GetStaticMagnitudeIfPossible(Level, CostValue);
FString CostTypeName = CostEffectModifierInfo.Attribute.AttributeName;
if (CostTypeName == "HP")
{
CostType = ECostType::HP;
}
if (CostTypeName == "MP")
{
CostType = ECostType::MP;
}
if (CostTypeName == "Strength")
{
CostType = ECostType::Strength;
}
//返回技能信息
return FGameplayAbilityInfo(CD, CostType, CostValue, IconMaterial, GetClass());
}
}
return FGameplayAbilityInfo();
}
学习技能时就获取技能信息
- 在基础类里面创建一个学习获取技能信息的函数
- 学习此技能
利用结构体信息创建单个技能UI
- 创建技能的UI
- 设置技能Key与技能初始化
- 设计技能开始CD逻辑
- 更新技能图标的值,当前CD除以总CD因为材质里面的数值问题要取反,然后CD小于0的情况下就回复技能图标,并设置当前技能无CD