44. UE5 RPG 初始化敌人的属性

news2024/11/16 9:49:14

在正常的游戏中,我们应该考虑如何去初始化角色属性,并且要给角色分好类型。比如,在我们游戏中,我们如何去初始化小兵的属性,并且还要实现小兵随着等级的增长而增加属性。而且就是小兵也有类型的区分,比如我们将在后面设置小兵分为三种:战士,游侠,法师。而小兵的属性实现,一般需要策划进行配表实现,将小兵的属性统一性的存入到表格导入项目。
我们将使用枚举去定义敌人的类型并创建一个ECharacterClass,并创建一个DataAsset命名为UCharacterClassInfo用来设置每种类型使用的属性初始化的GE。对于随着等级变动的基础属性,我们将使用曲线表格去生成所有等级的数据。并且,在数据中,我们去设置敌人需要附带的技能。
所以,接下来,我们实现的步骤是:

  1. 创建一个枚举ECharacterClass来定义角色的种类
  2. 创建一个DataAsset类 UCharacterClassInfo用来设置角色所使用得数据
  3. 创建曲线表格,用来定义角色属性跟随等级变化的值
  4. 创建设置角色属性的GE
  5. 通过函数实现角色应用设置的数据。

创建DataAsset

首先,我们创建角色使用的DataAsset,打开UE创建一个新类,继承DataAsset,并将其命名为CharacterClassInfo
在这里插入图片描述
在项目中,首先创建我们第一步需要的枚举,这里创建的三个职业的枚举

//角色职业类型的枚举
UENUM(BlueprintType)
enum class ECharacterClass : uint8
{
	Elementalist, //法师
	Warrior, //战士
	Ranger //游侠
};

接着创建一个结构体,用于根据不同的职业选择不同的结构体,这是只添加了第一项,就是基础的属性设置,后面我们会增加更多的内容。

USTRUCT()
struct FCharacterClassDefaultInfo
{
	GENERATED_BODY()

	UPROPERTY(EditDefaultsOnly, Category="Class Defaults")
	TSubclassOf<UGameplayEffect> PrimaryAttributes;
};

有了枚举和角色初始化的结构体以后,我们就可以创建DataAsset类了,在数据类里,我们首先创建一个Map类型,用于创建不同职业对应的基础属性GE,然后对于SecondaryAttributes和VitalAttributes,我们共用一套。最后增加一个函数,用于通过职业类型去获取基础的属性GE。

/**
 * 根据职业选择初始化角色的数据
 */
UCLASS()
class AURA_API UCharacterClassInfo : public UDataAsset
{
	GENERATED_BODY()

public:

	UPROPERTY(EditDefaultsOnly, Category="Class Defaults")
	TMap<ECharacterClass, FCharacterClassDefaultInfo> CharacterClassInformation;
	
	UPROPERTY(EditDefaultsOnly, Category="Common Class Defaults")
	TSubclassOf<UGameplayEffect> SecondaryAttributes;
	
	UPROPERTY(EditDefaultsOnly, Category="Common Class Defaults")
	TSubclassOf<UGameplayEffect> VitalAttributes;

	//通过枚举获取对应的初始化类
	FCharacterClassDefaultInfo GetClassDefaultInfo(ECharacterClass CharacterClass);
};

函数的视线,就是通过Map返回对应的类型的GE。

FCharacterClassDefaultInfo UCharacterClassInfo::GetClassDefaultInfo(ECharacterClass CharacterClass)
{
	return CharacterClassInformation.FindChecked(CharacterClass);
}

创建完成后,我们编译打开UE,在里面创建一个可配置的DataAsset
在这里插入图片描述
选择我们前面创建的类
在这里插入图片描述
打开以后,就是需要我们填充的值,这里有个细节,就是如果你得枚举第一项就选择枚举默认值,那么后面将无法添加,因为Map类型的Key不允许相同,所以你可以先增加后面的枚举类型,然后再最后设置默认枚举值。
在这里插入图片描述

创建对应的GE

创建了数据以后,我们需要创建对应的GE文件去填充,但是GE里面的数据需要根据等级去变动,所以,我们需要通过数据表格去实现这个功能。
首先我们创建对应的GE,之前,我们创建了一套主角使用的GE,主要属性是设置的固定值,虽然后续我们不会这么使用,刚好,直接使用它复制三个对应三个职业使用,然后创建数据图表,让GE根据等级去数据图表中获取数据。
在这里插入图片描述
然后是它的SecondaryAttributes和VitalAttribues,我们在主角上使用的次级属性设置的GE是Infinite类型的,复制一个修改成Instant类型的。因为敌人在我们的游戏设计中,它们是不会升级也不会变动的,所以不需要实时监听数值变化。而VitalAttributes则直接共用一套就行,毕竟就是最后在生成将血量和蓝量填充到最满,不需要额外制作。
在这里插入图片描述

创建GE使用的数据表格

为了能实现敌人的初始属性,我们将创建曲线表格来实现角色等级增长带来的属性数值的变化。我们在实现时,只要给敌人设置不同的等级,它就会生成不同的属性的敌人。
在这里,我们选择使用曲线表格,曲线表格的好处是可以自动填充中间的数据,并且可以过渡的更好。
在这里插入图片描述
创建曲线表格时,它会提示我们创建什么类型的曲线,
Constant就是没有过渡,到了位置显示固定值,一般不会使用
Linear就是线性过渡
Cubic就是贝塞尔曲线,它会圆滑的过渡,这里我们选择Cubic
在这里插入图片描述
曲线表格推荐使用CT开头,比如我们创建的法师的类型的就叫做CT_PrimaryAttributes_Elementalist
在这里插入图片描述
打开曲线表格,我们将四个属性都添加进去,然后选择曲线编辑
在这里插入图片描述

选中一项属性,然后鼠标右键添加关键帧
在这里插入图片描述
可以在上面添加关键帧的等级和数值,然后点击缩放匹配
在这里插入图片描述
添加完成数值后,我们可以右键点击自动
在这里插入图片描述
它就可以自动平滑处理
在这里插入图片描述
在这种情况下,你没必要每个等级都设置,并且可以看到对应等级的值
在这里插入图片描述
填充完数据之后,我们将对应职业的属性设置上,在选择使用表格后,前面的数值将是得到的值的倍率,然后选择表格中的曲线,即可实现对应的效果。
在这里插入图片描述
后面我们将使用另外两种格式创建另外两个职业的数值,我们不知道它的格式是怎么样的,可以通过将当前创建的曲线表格导出CSV或者JSON格式
在这里插入图片描述
CSV文件打开就是表格的形式,我们可以以此为模版进行修改,但是CSV格式导入到UE无法进行平滑处理
在这里插入图片描述
CSV格式也可以通过文本打开
在这里插入图片描述

JSON格式就是标准的JSON字符串显示,我们可以通过修改KEY和Value实现值的配置。
在这里插入图片描述

从外部文件导入表格数据

上面我们查看了对应的格式,我们可以以此为模版修改数据,并且直接导回到UE内。
导入到UE分为两种形式,第一种是直接将文件导入,我们可以在内容浏览器选择导入,直接将所需的文件导入到UE内
在这里插入图片描述
选择文件后,需要选择数据表格式和数据表插值类型。
在这里插入图片描述
导入后,如果选的是Cubic,那可以实现光滑取消的效果
在这里插入图片描述
如果你是先创建的文件,然后重新导入
在这里插入图片描述
曲线就会变成线性插值
在这里插入图片描述

使用数据表格设置GE

上面我们实现了使用外部数据创建GE使用的数据表格,这里再仔细讲一下如何使用数据表格设置GE。在你设置属性时,后面有一个使用曲线表格,
在这里插入图片描述
选择我们所使用的表格
在这里插入图片描述
表格里面能够存储多个数据,所以,我们还需要指定使用哪一条曲线
在这里插入图片描述
现在的设置的浮点数将是对从数据表格中获取到的结果的缩放,比如在等级0时,返回5 * 1为最终返回的力量值。
在这里插入图片描述
接下来,我们将所有的属性都设置上去,三个职业对应三个GE。
在这里插入图片描述

实现通过设置的通用GE实例化敌人

创建完成对应的GE,我们并使用数据表格填充了对应的数据,接下来,我们将通过代码实现对应的逻辑去初始化角色。
首先,我们考虑将创建数据放在哪里,这里我们将其放到GameMode上面,对于GameMode来说,在不同场景可以设置不同的GameMode,刚好合适,比如你创建了一个关卡,可以设置上对应的数据,关卡内的敌人初始化时,就使用这一套GE去初始化。
在我们的GameMode基类上增加一个变量,用于设置数据

public:

	UPROPERTY(EditDefaultsOnly, Category="Character Class Defaults")
	TObjectPtr<UCharacterClassInfo> CharacterClassInfo;

接下来,就是如何使用这个数据,由于它是属于通用的函数,我们将应用的函数创建到函数库里面,之前刚好有个自定义的函数库,我们在其内部增加对应的实现函数
在函数库增加一个函数,用于初始角色属性

	//初始化角色的属性
	UFUNCTION(BlueprintCallable, Category="MyAbilitySystemLibrary|CharacterClassDefaults")
	static void InitializeDefaultAttributes(const UObject* WorldContextObject, ECharacterClass CharacterClass, float Level, UAbilitySystemComponent* ASC);

在函数实现中,首先获取到关卡的GameMode,如果类型不一致,获取到的是空指针,将不执行后续操作

	//获取到当前关卡的GameMode实例
	const AMyGameModeBase* GameMode = Cast<AMyGameModeBase>(UGameplayStatics::GetGameMode(WorldContextObject));
	if(GameMode == nullptr) return;

然后获取到我们配置的DataAsset

	//从实例获取到关卡角色的配置
	UCharacterClassInfo* ClassInfo = GameMode->CharacterClassInfo;

从DataAsset获取到配置的对应职业的数据

	//获取到默认的基础角色数据
	const FCharacterClassDefaultInfo ClassDefaultInfo = ClassInfo->GetClassDefaultInfo(CharacterClass);

接下来就是三连应用,和角色一致,先应用主要属性,这个会通过等级设置的不同的属性值,然后根据基础属性生成次级属性的值,最后根据属性填充血量和蓝量的值。

	//应用基础属性
	FGameplayEffectContextHandle PrimaryContextHandle = ASC->MakeEffectContext();
	PrimaryContextHandle.AddSourceObject(WorldContextObject);
	const FGameplayEffectSpecHandle PrimarySpecHandle = ASC->MakeOutgoingSpec(ClassDefaultInfo.PrimaryAttributes, Level, PrimaryContextHandle);
	ASC->ApplyGameplayEffectSpecToSelf(*PrimarySpecHandle.Data.Get());

	//设置次级属性
	FGameplayEffectContextHandle SecondaryContextHandle = ASC->MakeEffectContext();
	SecondaryContextHandle.AddSourceObject(WorldContextObject);
	const FGameplayEffectSpecHandle SecondarySpecHandle = ASC->MakeOutgoingSpec(ClassInfo->SecondaryAttributes, Level, SecondaryContextHandle);
	ASC->ApplyGameplayEffectSpecToSelf(*SecondarySpecHandle.Data.Get());

	//填充血量和蓝量
	FGameplayEffectContextHandle VitalContextHandle = ASC->MakeEffectContext();
	VitalContextHandle.AddSourceObject(WorldContextObject);
	const FGameplayEffectSpecHandle VitalSpecHandle = ASC->MakeOutgoingSpec(ClassInfo->VitalAttributes, Level, VitalContextHandle);
	ASC->ApplyGameplayEffectSpecToSelf(*VitalSpecHandle.Data.Get());

初始化角色属性的函数完成了,接下来,我们要在敌人的基类里面实现使用此函数。
首先在敌人的基类身上增加一个变量,用来设置它的职业

	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="Character Class Defaults")
	ECharacterClass CharacterClass = ECharacterClass::Warrior;

在敌人基础的角色基础类里,有个函数叫InitializeDefaultAttributes,它是通过在角色的蓝图上面设置的三个GE进行初始化角色,也是当前的主角在使用的方式。
在这里插入图片描述
但是,在敌人这里,我们不需要在角色身上设置对应的GE,而是在GameMode的配置的数据里获取设置,所以,我们将其设置为虚拟函数

	virtual void InitializeDefaultAttributes() const;

在实现这里,只需要调用函数库实现的InitializeDefaultAttributes函数,即可实现对应的效果。

void AEnemyBase::InitAbilityActorInfo()
{
	AbilitySystemComponent->InitAbilityActorInfo(this, this);
	Cast<UAbilitySystemComponentBase>(AbilitySystemComponent)->AbilityActorInfoSet();

	//通过GE初始角色的属性
	InitializeDefaultAttributes();
}

void AEnemyBase::InitializeDefaultAttributes() const
{
	UMyAbilitySystemBlueprintLibrary::InitializeDefaultAttributes(this, CharacterClass, Level, AbilitySystemComponent);
}

编写完成,编译代码打开UE,首先进入GameMode,将我们之前编写的数据设置上去
在这里插入图片描述
然后选择场景中的敌人,设置它的等级和职业
在这里插入图片描述

测试结果

配置完成,现在角色的设置是否成功需要我们去测试结果,我们有多种方式去测试。
第一种,打印数据,在应用完GE后,打印角色的属性值来查看

void AEnemyBase::InitAbilityActorInfo()
{
	AbilitySystemComponent->InitAbilityActorInfo(this, this);
	Cast<UAbilitySystemComponentBase>(AbilitySystemComponent)->AbilityActorInfoSet();

	//通过GE初始角色的属性
	InitializeDefaultAttributes();

	//打印生命值查看属性
	UE_LOG(LogTemp, Warning, TEXT("%s 的生命值为 %f"), *this->GetName(), Cast<UAttributeSetBase>(AttributeSet)->GetHealth());
}

在输出日志里,可以查看到打印的数值
在这里插入图片描述

另一种方法就是打断点,我们将断点打在应用完GE后
在这里插入图片描述
刚好可以查看它的属性值的值是否正确
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1638012.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用qemu调试NVME driver

参考nvme驱动相关的博客&#xff0c;可以使用qemu buildroot进行nvme驱动的流程debug。 一、QEMU编译 首先需要编译qemu&#xff0c;可以参考QEMU编译。wget下载最新版本的QEMU&#xff0c;编译之前&#xff0c;最好检查下依赖包是否安装&#xff0c;避免安装过程出现各种错…

c++容器与算法概述

容器与算法 每个标准库容器都提供了begin() end() 函数&#xff0c;分别返回容器的头部位置和尾部位置。 I/O 流 对于自定义的类型&#xff1a; struct Entry {std::string name;int number;};如果需要使用标准输出需要重载<< 运算符&#xff0c;特别注意&#xff1a…

环形链表的经典问题

环形链表 环形链表的介绍链表中是否带环返回链表开始入环的第一个节点 本文主要介绍如何判断一个链表是否是环形链表&#xff0c;以及如何得到环形链表中的第一个节点。 环形链表的介绍 环形链表是一种链表数据结构&#xff0c;环形链表是某个节点的next指针指向前面的节点或指…

微软如何打造数字零售力航母系列科普05 - Azure中计算机视觉的视觉指南

Azure中计算机视觉的视觉指南 什么是计算机视觉&#xff1f;如何使用Microsoft Azure将计算机视觉功能集成到应用程序和工作流中&#xff1f; 作者&#xff1a;Nitya Narasimhan 编辑&#xff1a;数字化营销工兵 •11分钟阅读 什么是计算机视觉&#xff1f;如何使用Microso…

在树莓派安装 rpi-imager

步骤 安装 sudo apt install rpi-imager 我没有更新镜像源&#xff0c; 但是能安装完&#xff0c; 只是花的时间旧点。 烧写镜像 因为我是没有桌面的树莓派系统&#xff0c; 所以我这里执行的指令是不需要显示图形化界面的 man rpi-imager ## man指令查看说明 查看帮助手…

综合性练习(后端代码练习4)——图书管理系统

目录 一、准备工作 二、约定前后端交互接口 1、需求分析 2、接口定义 &#xff08;1&#xff09;登录接口 &#xff08;2&#xff09;图书列表接口 三、服务器代码 &#xff08;1&#xff09;创建一个UserController类&#xff0c;实现登录验证接口 &#xff…

服务运营 | 精选:用药难?用药贵?运筹学与统计学视角下的药物研发与管理

作者设计了一个多阶段博弈论模型来针对罕见病的不同补贴方案&#xff0c;分析政府、联盟、制药商和患者之间的相互作用。 制药商补贴为 α C \alpha C αC&#xff0c;其中 C C C是研发成本&#xff0c; α ∈ [ 0 , 1 ) \alpha \in [0,1) α∈[0,1)是政府总成本的比例。患者补…

vue3 依赖-组件tablepage-vue3 项目公共配置封装

github求⭐ 可通过github 地址和npm 地址查看全部内容 vue3 依赖-组件tablepage-vue3说明文档&#xff0c;列表页快速开发&#xff0c;使用思路及范例-汇总 vue3 依赖-组件tablepage-vue3说明文档&#xff0c;列表页快速开发&#xff0c;使用思路及范例&#xff08;Ⅰ&#…

模型智能体开发之metagpt-多智能体实践

参考&#xff1a; metagpt环境配置参考模型智能体开发之metagpt-单智能体实践 需求分析 之前有过单智能体的测试case&#xff0c;但是现实生活场景是很复杂的&#xff0c;所以单智能体远远不能满足我们的诉求&#xff0c;所以仍然还需要了解多智能体的实现。通过多个role对动…

Android11适配

一、分区存储 1.背景 Android 11 进一步增强了平台功能&#xff0c;为外部存储设备上的应用和用户数据提供了更好的保护。作为这项工作的一部分&#xff0c;平台引入了进一步的改进&#xff0c;以简化向分区存储的转换。 为了让用户更好地控制自己的文件&#xff0c;保护用户…

【华为】华为防火墙双机热备

【华为】华为防火墙双机热备 实验需求实验拓扑配置FW5-M前骤单臂路由和VRRP划分防火墙基本区域部署HRP&#xff08;华为心跳协议&#xff09; FW6-B前骤单臂路由和VRRP划分防火墙基本区域部署HRP&#xff08;华为心跳协议&#xff09; LSW2PC NATSNAT &#xff1a;Easy IPDNAT&…

汽车车灯的材料是什么?汽车车灯的灯罩如果破损破裂破洞了要怎么修复?

汽车车灯的材料主要包括灯罩和灯底座两部分&#xff0c;它们所使用的材料各不相同。 车灯罩的材料主要是透明且具有良好耐热性和耐紫外线性能的塑料。其中&#xff0c;聚碳酸酯&#xff08;PC&#xff09;是一种常用的材料&#xff0c;它具有高抗冲击性、耐化学品腐蚀和优良的…

redis核心数据结构——跳表项目设计与实现(跳表结构介绍,节点类设计,随机层级函数)

跳表结构介绍。跳表是redis等知名软件的核心数据结构&#xff0c;其实现的前提是有序链表&#xff0c;思想的本质是在原有一串存储数据的链表中&#xff0c;间隔地抽出一半元素作为上一级链表&#xff0c;并将抽提出的元素和原先的位置相关联&#xff0c;这样重复下去直到最上层…

使用 Python 和 OpenCV 进行实时目标检测的详解

使用到的模型文件我已经上传了&#xff0c;但是不知道能否通过审核&#xff0c;无法通过审核的话&#xff0c;就只能 靠大家自己发挥实力了&#xff0c;^_^ 目录 简介 代码介绍 代码拆解讲解 1.首先&#xff0c;让我们导入需要用到的库&#xff1a; 2.然后&#xff0c;设…

【数据结构-之八大排序(下),冒泡排序,快速排序,挖坑法,归并排序】

&#x1f308;个人主页&#xff1a;努力学编程’ ⛅个人推荐&#xff1a;基于java提供的ArrayList实现的扑克牌游戏 |C贪吃蛇详解 ⚡学好数据结构&#xff0c;刷题刻不容缓&#xff1a;点击一起刷题 &#x1f319;心灵鸡汤&#xff1a;总有人要赢&#xff0c;为什么不能是我呢 …

【MySQL | 第九篇】重新认识MySQL锁

文章目录 9.重新认识MySQL锁9.1MySQL锁概述9.2锁分类9.2.1锁的粒度9.2.2锁的区间9.2.3锁的性能9.2.4锁的级别 9.3拓展&#xff1a;意向锁9.3.1意向锁概述9.3.2意向锁分类9.3.3意向锁作用&#xff08;1&#xff09;意向锁的兼容互斥性&#xff08;2&#xff09;例子1&#xff08…

Springboot+vue+小程序+基于微信小程序的在线学习平台

一、项目介绍    基于Spring BootVue小程序的在线学习平台从实际情况出发&#xff0c;结合当前年轻人的学习环境喜好来开发。基于Spring BootVue小程序的在线学习平台在语言上使用Java语言进行开发&#xff0c;在数据库存储方面使用的MySQL数据库&#xff0c;开发工具是IDEA。…

主成分分析在R语言中的简单应用:使用mvstats包

在数据科学领域&#xff0c;主成分分析&#xff08;PCA&#xff09;是一种广泛使用的技术&#xff0c;主要用于数据降维和探索性数据分析。PCA可以帮助我们发现数据中的模式&#xff0c;减少数据集的复杂性&#xff0c;同时保持数据中最重要的特征。本文将介绍如何在R语言中使用…

STM32定时器中的编码器接口详解

系列文章目录 STM32单片机系列专栏 C语言术语和结构总结专栏 文章目录 1. 编码器接口简介 2. 旋转编码器简介 3. 正交编码器工作模式 4. 基本结构 5. 编码器工作模式示例 6. 代码示例 6.1 Encoder.c 6.2 Encoder.h 6.3 main.c 1. 编码器接口简介 在STM32中&#xf…

Cisco IOS XE Web UI 权限提升漏洞复现(CVE-2023-20198)

0x01 产品简介 Web UI 是一种基于GUI的嵌入式系统管理工具,能够提供系统配置、简化系统部署和可管理性以及增强用户体验。它带有默认映像,因此无需在系统上启用任何内容或安装任何许可证。Web UI 可用于构建配置以及监控系统和排除系统故障,而无需CLI专业知识。 0x02 漏洞…