116. UE5 GAS RPG 实现击杀掉落战利品功能

这一篇,我们实现敌人被击败后,掉落战利品的功能。首先,我们将创建一个新的结构体,用于定义掉落体的内容,方便我们设置掉落物。然后,我们实现敌人死亡时的掉落函数,并在蓝图里实现对应的逻辑,在场景里生成掉落物。最后,让掉落物动起来,显得掉落物需要玩家赶紧去拾取的感觉。

添加新的资产结构体

为了实现对敌人掉落战利品的配置,我们需要创建一个新的类,作为配置掉落物的新的资产类。
在这里插入图片描述
命名为战利品类
在这里插入图片描述
在类里,我们首先添加一个结构体,用于设置一种物品的掉落内容和几率。

USTRUCT(BlueprintType)
struct FLootItem
{
	GENERATED_BODY()

	//战利品在场景中的显示效果
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="LootTiers|Spawning")
	TSubclassOf<AActor> LootClass;

	//战利品生成几率
	UPROPERTY(EditAnywhere, Category="LootTiers|Spawning")
	float ChanceToSpawn = 0.f;

	//物品生成的最大数量
	UPROPERTY(EditAnywhere, Category="LootTiers|Spawning")
	int32 MaxNumberToSpawn = 0.f;

	//修改物品生成等级,false则使用敌人等级
	UPROPERTY(EditAnywhere, BlueprintReadOnly, Category="LootTiers|Spawning")
	bool bLootLevelOverride = true;
};

然后在类里,我们增加一个数组,开发者可以配置多个掉落物,然后添加一个函数,用于获取当前可以生成的战利品数组。

UCLASS()
class RPG_API ULootTiers : public UDataAsset
{
	GENERATED_BODY()

public:

	//获取需要生成的战利品数据
	UFUNCTION(BlueprintCallable)
	TArray<FLootItem> GetLootItems();

	UPROPERTY(EditDefaultsOnly, Category="LootTiers|Spawning")
	TArray<FLootItem> LootItems;
};

在函数实现这里,我们创建了一个新的数组,用于根据概率计算每个物品的是否可掉落,物品可以设置多个,所以,我们需要两层嵌套循环,如果当前可掉落,那么我们将其添加到返回数组里。最后返回。

TArray<FLootItem> ULootTiers::GetLootItems()
{
	TArray<FLootItem> ReturnItems;

	for(const FLootItem Item : LootItems)
	{
		for(int32 i=0; i<Item.MaxNumberToSpawn; ++i)
		{
			if(FMath::RandRange(1.f, 100.f) < Item.ChanceToSpawn)
			{
				FLootItem NewItem;
				NewItem.LootClass = Item.LootClass;
				NewItem.bLootLevelOverride = Item.bLootLevelOverride;
				ReturnItems.Add(NewItem);
			}
		}
	}

	return ReturnItems;
}

实现配置和触发掉落逻辑

然后,我们需要一个能够去获取配置好的数据资产的地方,最方便的就是放到GameMode里,我们在GameMode类里添加一个配置,可以在蓝图配置使用哪一个数据资产

	//战利品数据配置
	UPROPERTY(EditDefaultsOnly, Category="Loot Tiers")
	TObjectPtr<ULootTiers> LootTiers;
	

为了方便获取数据资产,我们在蓝图函数库里增加一个函数,用于获取数据资产

	/**
	 * 获取生成的战利品数据资产,此数据会配置到GameMode上
	 * @param WorldContextObject  一个世界场景的对象,用于获取当前所在的世界
	 * @return 战利品数据
	 *
	 * @note 敌人死亡后,所需生成的战利品
	 */
	UFUNCTION(BlueprintCallable, Category="RPGAbilitySystemLibrary|CharacterClassDefaults", meta=(DefaultToSelf = "WorldContextObject"))
	static ULootTiers* GetLootTiers(const UObject* WorldContextObject);

函数实现,我们将获取到GameMode,并从GameMode身上获取到数据资产

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

	//返回敌人战利品配置,需要设置到GameMode上
	return  GameMode->LootTiers;
}

最后,我们要在敌人类里实现掉落逻辑,我们增加一个函数,这个函数需要在蓝图里实现逻辑

	//生成战利品
	UFUNCTION(BlueprintImplementableEvent)
	void SpawnLoot();

然后在触发死亡逻辑时,我们调用此函数来生成战利品

在这里插入图片描述

添加蓝图

代码方便,我们完成了,接着,我们要在编辑器里,添加一个新的数据资产
在这里插入图片描述
资产类型使用我们创建的战利品资产
在这里插入图片描述
我们将其和之前的资产放到一块
在这里插入图片描述
然后,在资产里,我们将之前制作的药瓶和水晶(持续回血)添加到战利品里,掉落概率设置为100,并且要使用敌人等级掉落。
在这里插入图片描述
接着将其设置到GameMode蓝图里
在这里插入图片描述
我们在敌人蓝图基类里实现统一的掉落战利品机制,首先通过蓝图库函数获取到数据资产实例,然后通过GetLootItems获取到需要生成的掉落物
在这里插入图片描述
然后创建一个蓝图函数,用于通过蓝图函数库,来设置掉落物的转向。
在这里插入图片描述
然后我们将其设置为纯函数,这样,不需要通过执行箭头调用。
在这里插入图片描述
然后将转向存储起来方便后续使用
在这里插入图片描述
然后,我们通过一个定时器,让物品掉落持续生成,这样可以防止卡顿,并且物品有一个个生成的效果,我们在设置定时器时,直接调用一次此事件。
在这里插入图片描述
接着就是生成战利品的自定义事件,我们通过索引,从返回的数组里获取到需要生成的对应的数据,并计算出物品掉落位置,最后生成Actor
在这里插入图片描述
我们创建获取变换的纯函数,通过转向对敌人位置进行一个朝向在一定范围内随机偏移,并使用旋转的朝向。
在这里插入图片描述
在创建Actor后,我们需要更新掉落物的等级,如果此物品需要修改等级,那么我们将通过此函数内的逻辑进行修改
在这里插入图片描述
函数内,我们首先判断是否需要修改,然后将其转换为场景物品的基类,然后判断当前物品是否存在,最后将敌人等级应用到掉落物身上。
在这里插入图片描述
最后一步,就是修改索引,每调用一次,我们将索引+1,下次再调用此事件时,将会生成下一个坐标的物品,如果索引超过或等于数组长度时,我们将结束定时器,完成掉落物的生成。
在这里插入图片描述
最后展示一下完成的蓝图连线

在这里插入图片描述

然后进入关卡打怪测试效果
在这里插入图片描述

关于掉落物的一些扩展

如果后续扩展的话,我考虑对于每个大关卡创建单独的一套掉落,然后在数组资产里增加几个数组,比如效果,使用小怪的一套掉落,而精英怪使用精英怪的一套掉落,最后是boss的掉落,使用boss的一套掉落逻辑。
然后获取掉落时,可以根据敌人品质,去获取不同的掉落,我们当然没必须单独为敌人去配置掉落。BOSS除外,我们当然可以对一些特殊BOSS去配置单独的掉落,比如关卡的最终BOSS掉落,以及一些特殊怪物掉落。

实现掉落物自动旋转和悬浮效果

为了实现这个效果,我们要在掉落物的基类RPGEffectActor里增加一些属性和函数,用于实现此效果
要实现这个功能,我们增加一批函数,用于实现此功能

	// 计算后的Actor所在的位置
	UPROPERTY(BlueprintReadWrite)
	FVector CalculatedLocation;

	// 计算后的Actor的旋转
	UPROPERTY(BlueprintReadWrite)
	FRotator CalculatedRotation;

	// Actor是否帧更新旋转
	UPROPERTY(BlueprintReadWrite, Category="Pickup Movement")
	bool bRotates = false;

	// Actor每秒旋转的角度
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Pickup Movement")
	float RotationRate = 45.f;

	// Actor是否更新位置
	UPROPERTY(BlueprintReadWrite, Category="Pickup Movement")
	bool bSinusoidalMovement = false;

	// 正弦值-1到1,此值为调整更新移动范围
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Pickup Movement")
	float SineAmplitude = 1.f;

	// 此值参与正弦运算,默认值为1秒一个循环(2PI走完一个正弦的循环,乘以时间,就是一秒一个循环,可用于调整位置移动速度)
	UPROPERTY(EditAnywhere, BlueprintReadWrite, Category="Pickup Movement")
	float SinePeriod = 1.f; //2 * PI

	//调用此函数,Actor开始自动更新上下位置
	UFUNCTION(BlueprintCallable)
	void StartSinusoidalMovement();

	//调用此函数,Actor开始自动旋转
	UFUNCTION(BlueprintCallable)
	void StartRotation();
private:

	//当前掉落物的存在时间,可以通过此时间实现动态效果
	float RunningTime = 0.f;

	// Actor生成的默认初始位置,在Actor动态浮动时,需要默认位置作为基础位置
	FVector InitialLocation;

	// 每一帧更新Actor的位置和转向
	void ItemMovement(float DeltaSeconds);

我们还需要用到帧更新函数

virtual void Tick(float DeltaSeconds) override;

在事件开始时,我们将掉落物的默认位置和旋转保存,并设置计算后的属性,我们需要在后续使用它更新Actor

void ARPGEffectActor::BeginPlay()
{
	Super::BeginPlay();

	//设置初始位置
	InitialLocation = GetActorLocation();
	CalculatedLocation = InitialLocation;
	CalculatedRotation = GetActorRotation();
}

我们需要在帧更新了去保存当前效果的执行时间,并调用更新函数

void ARPGEffectActor::Tick(float DeltaSeconds)
{
	Super::Tick(DeltaSeconds);
	//更新当前Actor的存在时间
	RunningTime += DeltaSeconds;
	ItemMovement(DeltaSeconds);
}

在更新函数里,我们根据变量判断是否需要更新,来对转向和位置更新,这里需要提到的是,位置更新用到了正弦三角函数进行更新

void ARPGEffectActor::ItemMovement(float DeltaSeconds)
{
	//更新转向
	if(bRotates)
	{
		const FRotator DeltaRotation(0.f, DeltaSeconds * RotationRate, 0.f);
		CalculatedRotation = UKismetMathLibrary::ComposeRotators(CalculatedRotation, DeltaRotation);
	}
	//更新位置
	if(bSinusoidalMovement)
	{
		const float Sine = SineAmplitude * FMath::Sin(RunningTime * SinePeriod * 6.28318f);
		CalculatedLocation = InitialLocation + FVector(0.f, 0.f, Sine);
	}
}

你会发现上面的变量无法在蓝图面板直接设置,那么如何将其设置为true呢,我们通用函数将其设置为true

void ARPGEffectActor::StartSinusoidalMovement()
{
	bSinusoidalMovement = true;
	InitialLocation = GetActorLocation();
	CalculatedLocation = InitialLocation;
}

void ARPGEffectActor::StartRotation()
{
	bRotates = true;
	CalculatedRotation = GetActorRotation();
}

后续效果我们需要在蓝图里实现,所以,我们创建一个拾取的基类,然后将所有可掉落物都继承此蓝图,没必要在每个蓝图里实现一遍
在这里插入图片描述
我们在拾取物基类里,创建一个时间轴,来实现掉落物的从无到有的效果,并通过时间轴的更新实现一些位置更新,和缩放效果。在时间轴播放完成后,我们调用开始旋转和开始移动的默认效果。
在这里插入图片描述
时间轴里,我们增加了两个轨道,用于分别更新位置和缩放使用
在这里插入图片描述
在帧更新里,我们通过计算后的位置和旋转更新Actor即可
在这里插入图片描述

以下是拾取物的表现效果

在这里插入图片描述

添加音效

最后一个功能,我们在Actor里添加一些音效,来实现一些点缀效果。
首先在Actor增加一个变量,设置音效基础类型
在这里插入图片描述
然后找到对应的音效
在这里插入图片描述
设置给变量

在这里插入图片描述
在更新位置和缩放后(我折叠成了一个函数),我们通过修改位置的值,判断如果大于0.3时,执行一次模拟触碰到地面的音效
在这里插入图片描述
然后在事件开始时增加一个生成的音效

在这里插入图片描述
在销毁时,播放一个拾取的音效。
在这里插入图片描述

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

亚马逊云服务器Amazon EC2

一、什么是Amazon EC2&#xff1f; Amazon Elastic Compute Cloud (Amazon EC2) 在 Amazon Web Services (AWS) 云中提供按需、可扩展的计算容量。使用 Amazon EC2 可降低硬件成本&#xff0c;让您能够更快地开发和部署应用程序。您可以使用 Amazon EC2 启动任意数量的虚拟服务…

Word 右键内容不显示段落/字体问题解决

有时需要调整图片的行间距&#xff0c;但是右键图片所在行&#xff0c;没有段落的选项。 可以将焦点保持在图片所在行&#xff0c;然后点击右下角的图标。同理不显示字体也可以点击左边字体中的右下角图标。

学生公寓智能限电系统的功能和作用

学生公寓智能限电系统‌是一种用于管理和限制学生公寓用电的设备和技术&#xff0c;旨在确保用电安全、防止火灾事故&#xff0c;并促进节能减排。以下是关于学生公寓智能限电系统的详细介绍&#xff1a; 1、功能和作用 智能限电系统通过以下功能来管理和限制用电&#xff1a…

[IT项管理(双语)]项目的基本概念

什么是项目 1.1项目的定义 项目&#xff08;project&#xff09;是为了创造一个特定的产品&#xff0c;服务&#xff0c;或者成果而采用的临时性的努力。 项目 产出唯一 临时性 1.2运营的定义 运营&#xff08;operation&#xff09;是 为了维持业务而进行的工作。 Imp1.3运…

ASP.NET Core SignalR 双工通信

01. 介绍 &#x1f3af; ASP.NET Core SignalR 是一个开放源代码库&#xff0c;它简化了向应用添加实时 Web 功能的过程。 实时 Web 功能使服务器端代码可以在服务器上激发事件时将事件推送到连接的客户端。 使用 SignalR&#xff0c;客户端也可以将消息发送到服务器&#xff…

Sonar基于SonarQube统一产品命名,助力提升开发者体验,以及本地、云端或IDE端的代码质量与安全

日前&#xff0c;领先的代码质量和安全解决方案提供商Sonar宣布&#xff0c;将围绕SonarQube简化其现有的产品命名。 作为Sonar的旗舰品牌&#xff0c;SonarQube代表了公司的核心使命&#xff1a;提高所有代码的质量和安全性&#xff0c;同时提供更好的开发人员体验。这些变化…

搭建高可用负载均衡系统:Nginx 与云服务的最佳实践

搭建高可用负载均衡系统&#xff1a;Nginx 与云服务的最佳实践 引言 在项目开发过程中&#xff0c;我们通常在开发和测试阶段采用单机架构进行开发和测试。这是因为在这个阶段&#xff0c;系统的主要目的是功能实现和验证&#xff0c;单机架构足以满足开发人员的日常需求&…

芯科科技突破性超低功耗Wi-Fi 6和低功耗蓝牙5.4模块加速设备部署

致力于以安全、智能无线连接技术&#xff0c;建立更互联世界的全球领导厂商Silicon Labs&#xff08;亦称“芯科科技”&#xff0c;今日宣布推出SiWx917Y超低功耗Wi-Fi 6和低功耗蓝牙&#xff08;Bluetooth LE&#xff09;5.4模块。 作为成功的第二代无线开发平台的新产品&…

CentOS7虚拟机 网络适配器 NAT模式和桥接模式区别

一、环境介绍 宿主机&#xff1a;Windows电脑 虚拟机&#xff1a;VMware下的CentOS7 局域网&#xff1a;路由器下的各真实主机组成的网络 内部局域网&#xff1a;宿主机构建的一个内部网路 二、NAT和桥接网络链接模式区别 NAT模式&#xff1a;相当于宿主机构建一个内部局域网&a…

【AIGC半月报】AIGC大模型启元:2024.12(上)

【AIGC半月报】AIGC大模型启元&#xff1a;2024.12&#xff08;上&#xff09; &#xff08;1&#xff09;OpenAI-12日发布会&#xff08;持续更新中........&#xff09;Day01-12.06&#xff1a;o1满血版上线&#xff08;已发布&#xff09;Day02-12.07&#xff1a;强化微调&a…

开源堡垒机JumpServer配置教程:使用步骤与配置

开源堡垒机JumpServer配置教程&#xff1a;使用步骤与配置 上一篇文章星哥讲了如何安装JumpServer堡垒机&#xff0c;本篇文章来讲如何配置和使用JumpServer。 安装成功后&#xff0c;通过浏览器访问登录 JumpServer 地址: http://<JumpServer服务器IP地址>:<服务运…

gulp应该怎么用,前端批量自动化替换文件

背景 最近公司准备把所有项目中用到的国际化相关的key规范化&#xff0c;原因是: 一直以来公司的app和web端 在针对相同的需求以及相同的国际化语言&#xff0c;需要设置不同的两份国际化文件&#xff0c;难以维护旧版的国际化文件中&#xff0c;存在的大量值重复&#xff0c…

【5G】5G Physical Layer物理层(一)

5G多址接入和物理层与长期演进&#xff08;LTE&#xff09;存在一些差异。在下行方向&#xff0c;5G与LTE相似&#xff0c;依旧采用正交频分多址&#xff08;OFDMA&#xff09;。而在上行方向&#xff0c;5G采用了OFDMA和单载波频分多址&#xff08;SC-FDMA&#xff09;&#x…

Docker 安装 中文版 GitLab

Docker 安装系列 安装GitLab、解决服务器内存不足问题、使用域名/IP地址访问项目 1、拉取 [rootTseng ~]# docker pull twang2218/gitlab-ce-zh:latest latest: Pulling from twang2218/gitlab-ce-zh 8ee29e426c26: Pull complete 6e83b260b73b: Pull complete e26b65fd11…

力扣-图论-4【算法学习day.54】

前言 ###我做这类文章一个重要的目的还是给正在学习的大家提供方向和记录学习过程&#xff08;例如想要掌握基础用法&#xff0c;该刷哪些题&#xff1f;&#xff09;我的解析也不会做的非常详细&#xff0c;只会提供思路和一些关键点&#xff0c;力扣上的大佬们的题解质量是非…

减少30%人工处理时间,AI OCR与表格识别助力医疗化验单快速处理

在医疗行业&#xff0c;化验单作为重要的诊断依据和数据来源&#xff0c;涉及大量的文字和表格信息&#xff0c;传统的手工输入和数据处理方式不仅繁琐&#xff0c;而且容易出错&#xff0c;给医院的运营效率和数据准确性带来较大挑战。随着人工智能技术的快速发展&#xff0c;…

剖析千益畅行,共享旅游-卡,合规运营与技术赋能双驱下的旅游新篇

在数字化浪潮席卷各行各业的当下&#xff0c;旅游产业与共享经济模式深度融合&#xff0c;催生出旅游卡这类新兴产品。然而&#xff0c;市场乱象丛生&#xff0c;诸多打着 “共享” 幌子的旅游卡弊病百出&#xff0c;让从业者与消费者都深陷困扰。今天&#xff0c;咱们聚焦技术…

Mac曲线救国实现Bandizip右键一级菜单

一、前言 个人认为&#xff1a;Bandizip是Mac上最好用的压缩软件&#xff0c;没有之一。 在Mac系统上&#xff0c;学习版的Bandizip由于签名检验问题无法在访达右键的一级菜单显示 解压相关菜单。 有能力的&#xff0c;希望还是支持正版&#xff0c;找找优惠渠道应该100左右。…

理解 package.json 中版本号符号

今天&#xff0c;聊一聊在前端开发中&#xff0c; package.json 中怎么看版本号符号。 版本号符号的解释 版本号通常由三部分组成&#xff1a;主版本号、次版本号、补丁版本号&#xff0c;格式为 major.minor.patch。常见的符号有&#xff1a; ^&#xff1a;更新时允许自动…

【自用】管材流转项目前端重部署流程 vue2 webpackage4 vuecli4

一、配置 1.下载项目&#xff0c;使用 IDEA 打开&#xff0c;并配置 Nodejs 它提示我&#xff0c;需要 Node.js&#xff0c;因为 nodejs 14 的 installer 已经官网已经找不到了&#xff0c;使用 fnm 又太麻烦&#xff0c; 所以直接采用在 IDEA 中下载的方式就好了。 2.清除缓…