当前位置: 首页 > news >正文

5. UE5 RPG使用GAS技能系统

之前也介绍过GAS的使用:
UE 5 GAS Gameplay Ability System
UE 5 GAS 在项目中处理AttributeSet相关
UE 5 GAS 在项目中通过数据初始化
基础的讲解这里不再诉说,有兴趣的可以翻我之前的博客。

接下来,在RPG游戏中实现GAS系统的使用。
GAS系统可以放到角色Pawn身上,也可以放到PlayerState里面,如果放到Pawn身上,GAS也会跟着销毁,这个比较方便与敌人身上,所以敌人的Ability System Component(ASC)和Attribute Set我们将直接放置到敌人的Pawn身上,而玩家控制的角色,牵扯到一个复活的问题,我们需要保存技能相关的数据,将放置到PlayerState身上,那样如果销毁掉角色Pawn,相关数据也会保存下来。

创建PlayerState

在这里插入图片描述
首先点击创建c++类
在这里插入图片描述
创建一个新的玩家状态类

// 版权归暮志未晚所有。#include "Player/PlayerStateBase.h"APlayerStateBase::APlayerStateBase()
{NetUpdateFrequency = 100.f; //每秒和服务器更新频率,使用GAS后可以设置的高一些
}

创建完成后再PlayerState.cpp中初始化时,修改NetUpdateFrequency 默认为2,使用了GAS可以设置的更高
在这里插入图片描述
打开ue,创建蓝图类
在这里插入图片描述
放置到蓝图文件夹内
在这里插入图片描述
将GameMode里面的玩家状态类修改成当前创建的蓝图。
GAS的载体就制作完成,接下来添加GAS系统。

添加GAS

在这里插入图片描述
打开插件,搜素gameplay,找到gameplay Abilities,添加,重新启动。
在这里插入图片描述
添加新的c++类,父类为AbilitySystemComponent
在这里插入图片描述
创建ASC基类
在这里插入图片描述
接下来创建数据集类,父类为AttributeSet

PrivateDependencyModuleNames.AddRange(new string[] { "GameplayAbilities", "GameplayTags", "GameplayTasks" });

在私有模块中添加相关模块

代码中添加

带有ASC的Actor也被称为ASC的OwnerActor。ASC实际作用的Actor叫作AvatarActor。OwnerActor和AvatarActor可以是同一个Actor,比如MOBA游戏中的野怪。它们也可以是不同的 Actors,比如MOBA游戏中玩家和AI控制的英雄角色,OwnerActor是PlayerState、AvatarActor是HeroCharacter。大部分情况下OwnerActor和AvatarActor可以是角色Actor。不过想像一下你控制的英雄角色死亡然后重生的过程,如果此时要保留死亡前的Attributes或者GameplayEffects,那么最理想的做法是将ASC交给PlayerState。

如果OwnerActor和AvatarActor是不同的Actors,那么两者都需要实现IAbilitySystemInterface。这个接口只有一个方法需要被重载UAbilitySystemComponent* GetAbilitySystemComponent() const,此方法将返回ASC。
在这里插入图片描述
首先在角色基础的类里面创建两个属性,分别用来定义技能组件和属性,记得声明它们的类。主角类和敌人基础的类都会继承角色基础类,那么,它们都会创建相关的属性。

AEnemyBase::AEnemyBase()
{GetMesh()->SetCollisionResponseToChannel(ECC_Visibility, ECR_Block); //设置可视为阻挡AbilitySystemComponent = CreateDefaultSubobject<UAbilitySystemComponentBase>("AbilitySystemComponent");AbilitySystemComponent->SetIsReplicated(true); //设置组件用于在网络上复制AttributeSet = CreateDefaultSubobject<UAttributeSetBase>("AttributeSet");
}

敌人的基类里面,只需要在初始化时实例化相应的组件
在这里插入图片描述
主角的组件和数据,我们首先需要先在PlayerState身上设置,然后再characterBase身上去引用PlayerState身上的对应组件和数据,这样,即使character销毁掉,创建新的,我们一样可以获取到修改后的数据。

// 版权归暮志未晚所有。#include "Player/PlayerStateBase.h"
#include "AbilitySystem/AbilitySystemComponentBase.h"
#include "AbilitySystem/AttributeSetBase.h"APlayerStateBase::APlayerStateBase()
{NetUpdateFrequency = 100.f; //每秒和服务器更新频率,使用GAS后可以设置的高一些AbilitySystemComponent = CreateDefaultSubobject<UAbilitySystemComponentBase>("AbilitySystemComponent");AbilitySystemComponent->SetIsReplicated(true); //设置组件用于在网络上复制AttributeSet = CreateDefaultSubobject<UAttributeSetBase>("AttributeSet");
}

在PlayerStateBase.cpp里面实例化。

接下来比较重要的一步就是,如何在Character里面去获取PlayerState的技能组件,这里我们使用了GAS组件自带AbilitySystemInterface接口去实现。
在这里插入图片描述
需要在.h文件中使用技能组件,所以,我们将模块移入到Public列表中。

// 版权归暮志未晚所有。#pragma once#include "CoreMinimal.h"
#include "AbilitySystemInterface.h"
#include "GameFramework/PlayerState.h"
#include "PlayerStateBase.generated.h"class UAbilitySystemComponent;
class UAttributeSet;
/*** */
UCLASS()
class AURA_API APlayerStateBase : public APlayerState, public IAbilitySystemInterface
{GENERATED_BODY()public:APlayerStateBase();virtual UAbilitySystemComponent* GetAbilitySystemComponent() const override; //覆盖虚函数获取ascUAttributeSet* GetAttributeSet() const { return AttributeSet; } //获取asprotected:UPROPERTY()TObjectPtr<UAbilitySystemComponent> AbilitySystemComponent;UPROPERTY()TObjectPtr<UAttributeSet> AttributeSet;
};

在playerState里,继承接口,实现接口的虚函数,用于获取asc,并实现获取as的函数。

UAbilitySystemComponent* APlayerStateBase::GetAbilitySystemComponent() const
{return AbilitySystemComponent;
}

cpp里定义也只是返回asc组件。
在这里插入图片描述
character同样继承此接口,并实现对应的函数。
在这里插入图片描述
接下来我们要设置复制模式,以便来同步客户端和服务器端数据。

AbilitySystemComponent->SetReplicationMode(EGameplayEffectReplicationMode::Mixed);

在角色的asc上面,我们使用Mixed模式同步。

AbilitySystemComponent->SetReplicationMode(EGameplayEffectReplicationMode::Minimal);

而怪物的asc,则使用Minimal模式

初始化AbilitySysytemComponent

ASC需要有OwnerActor和AvatarActor进行初始化,而且必须在服务器和客户端都要完成初始化。

对于玩家控制的角色,ASC存在于Pawn中,我通常在Pawn的 PossessedBy()方法中完成ASC在服务器端的初始化,在PlayerController的AcknowledgePawn()方法中完成ASC在客户端的初始化。

对于玩家控制的角色,ASC存在于PlayerState中,我通常在Pawn 的PossessedBy() 方法中完成ASC在服务器端的初始化(这一点与上述相同),在 Pawn的 OnRep_PlayerState()方法中完成ASC在客户端的初始化(这将确保PlayerState在客户端已存在)。

对于AI控制的角色,ASC存在于Pawn中,通常在Pawn的 BeginPlay()方法中完成ASC在服务器端和客户端的初始化。

既然根据文档知道了如何初始化,那么,我们按照相应的方式初始化。首先初始化敌人身上的ASC,敌人作为ai怪物,只需要在BeginPlay里面初始化即可。
在这里插入图片描述
首先覆盖BeginPlay()的函数

void AEnemyBase::BeginPlay()
{Super::BeginPlay();AbilitySystemComponent->InitAbilityActorInfo(this, this);
}

然后在BeginPlay()里面调用InitAbilityActorInfo初始化即可完成。

接下来是玩家控制角色的ASC初始化,玩家控制角色按照文档说法,我们需要在AvatarActor里面进行初始化。
在这里插入图片描述
如果ASC存在于PlayerState中,则覆盖这两个函数,然后添加私有初始化函数(因为里面初始化代码一致)

void AHeroCharacter::InitAbilityActorInfo()
{APlayerStateBase* PlayerStateBase = GetPlayerState<APlayerStateBase>();check(PlayerStateBase);//从playerState获取ASC和ASAbilitySystemComponent = PlayerStateBase->GetAbilitySystemComponent();AttributeSet = PlayerStateBase->GetAttributeSet();//初始化ASCAbilitySystemComponent->InitAbilityActorInfo(PlayerStateBase, this);
}

初始化代码就是获取到玩家控制角色的PlayerState,从PlayerState身上获取ASC和AS,OwnerActor就是PlayerState,而AvatarActor则就是自身。

void AHeroCharacter::PossessedBy(AController* NewController)
{Super::PossessedBy(NewController);//初始化ASC的OwnerActor和AvatarActorInitAbilityActorInfo();
}void AHeroCharacter::OnRep_PlayerState()
{Super::OnRep_PlayerState();//初始化ASC的OwnerActor和AvatarActorInitAbilityActorInfo();
}

接下来就是在PossessedBy()和OnRep_PlayerState()调用,完成服务端和客户端的初始化。

	//初始化ASC的OwnerActor和AvatarActorInitAbilityActorInfo();//设置OwnerActor的ControllerSetOwner(NewController);

注意: Mixed 复制模式要求OwnerActor的 Owner必须是Controller。 PlayerState的 Owner默认是Controller,但是Character不是。如果使用Mixed复制模式的OwnerActor不是PlayerState那么你需要在OwnerActor上调用SetOwner()并传递一个有效的Controller。(不过从4.24开始, PossessedBy() 会为Pawn设置一个新的Controller。)

参考:虚幻引擎游戏技能系统文档

相关文章:

  • vue中改变v-html中包含body标签的样式修改方法
  • 鸿蒙开发环境配置-Windows
  • cherry键盘alt+tab无法切换窗口的问题解决
  • HTML 列表 iframe
  • H12-821_324
  • 免费开源OCR 软件Umi-OCR
  • 《2023中国低代码商业落地研究报告》
  • Android 系统启动过程纪要(基于Android 10)
  • 基于FPGA的图像双边滤波实现,包括tb测试文件和MATLAB辅助验证
  • 计算机找不到msvcp120.dll的修复方法,总结五种可靠的方法
  • 使用延迟队列处理超时订单
  • 【算法练习】leetcode算法题合集之栈和队列篇
  • 安卓、ios系统详解
  • 黑马程序员 Java设计模式学习笔记(一)
  • qt学习:进度条,水平滑动条,垂直滑动条+rgb调试实战
  • 【Linux系统编程】快速查找errno错误码信息
  • 【剑指offer】让抽象问题具体化
  • Angular 响应式表单之下拉框
  • java取消线程实例
  • MySQL数据库运维之数据恢复
  • Node项目之评分系统(二)- 数据库设计
  • OSS Web直传 (文件图片)
  • spark本地环境的搭建到运行第一个spark程序
  • swift基础之_对象 实例方法 对象方法。
  • Unix命令
  • 爱情 北京女病人
  • 搞机器学习要哪些技能
  • 聊聊directory traversal attack
  • 前端相关框架总和
  • 使用 Xcode 的 Target 区分开发和生产环境
  • 通过npm或yarn自动生成vue组件
  • 我的面试准备过程--容器(更新中)
  • 项目管理碎碎念系列之一:干系人管理
  • 学习JavaScript数据结构与算法 — 树
  • 用quicker-worker.js轻松跑一个大数据遍历
  • 原生 js 实现移动端 Touch 滑动反弹
  • 原生Ajax
  • 曜石科技宣布获得千万级天使轮投资,全方面布局电竞产业链 ...
  • ​LeetCode解法汇总2182. 构造限制重复的字符串
  • ​Linux·i2c驱动架构​
  • ​业务双活的数据切换思路设计(下)
  • ###51单片机学习(1)-----单片机烧录软件的使用,以及如何建立一个工程项目
  • #ubuntu# #git# repository git config --global --add safe.directory
  • ${ }的特别功能
  • (14)Hive调优——合并小文件
  • (C++)八皇后问题
  • (八)Flask之app.route装饰器函数的参数
  • (附源码)springboot青少年公共卫生教育平台 毕业设计 643214
  • (南京观海微电子)——COF介绍
  • (学习日记)2024.01.19
  • (译)计算距离、方位和更多经纬度之间的点
  • .NET CORE Aws S3 使用
  • .Net Web窗口页属性
  • .NET 中创建支持集合初始化器的类型
  • .NET使用HttpClient以multipart/form-data形式post上传文件及其相关参数