独立游戏《星尘异变》UE5 C++程序开发日志3——实现一个存存组件

本篇日志中,我将会介绍如何实现一个有格子,每个格子有容量的物品库存,如下图:

一.库存容器

1.储存数据的容器

        库存容器最重要的目的就是存储每一种类的物品拥有的数量,这里我用的是哈希表:

std::unordered_map<std::string, int>StardustCount;//从星尘ID到存储的数量的映射

哈希表的优点就是查询速度极快,我们的的库存在每次发生“反应”,进口等过程时都要进行数量的查询,所以要尽可能降低查询的复杂度,这也就是为什么我们不用TMap,因为TMap在每次使用"[]"运算符前,要检查其是否含有要查询的元素。

        而他的优点就是不便于展示,因为我们要实现的库存是有有格子,每个格子有存储上限的容器,所以我们要再定义一个数组,数组中的每一个索引对应的就是展示的一个格子:

2.显示数据的容器

	UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category="Storage")TArray<UStardustItemClass*>Storage;//输入仓库

        数组中的数据类型是一个UObject指针,该UObject内除了上一篇日志中展示的数据外,多了一个该槽位物品数量的变量"Quantity":


USTRUCT(BlueprintType)
struct FStardustItem
{GENERATED_BODY();UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "StardustBase")FName StardustName{"Empty"};//名称UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "StardustBase")FText Description;//描述UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "StardustBase")FName StardustId{ "Empty" };//编号UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "StardustBase")FStardustStatisticsForReaction ReactionStatistics{FStardustStatisticsForReaction()};//反应数据UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "StardustBase")FStardustStatisticsForInventory InventoryStatistics{FStardustStatisticsForInventory()};//库存数据UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "StardustBase", meta = (UIMin = 1))int Quantity{0};//数量FStardustItem() = default;explicit FStardustItem(const FStardustDataTable& Stardust){StardustId = Stardust.StardustId;StardustName = Stardust.StardustName;Description = Stardust.Description;Quantity = 0;ReactionStatistics = Stardust.ReactionStatistics;InventoryStatistics = Stardust.InventoryStatistics;}void SetQuantity(int Num)//设置该槽位内的星尘数量{if (Num > 0){Quantity =  Num;}else{//数量为0就将其替换成默认空的物品*this = FStardustItem();};}};UCLASS(BlueprintType)
class ASTROMUTATE_2_API UStardustItemClass : public UObject
{GENERATED_BODY()
public://物品信息UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category="StardustItem")FStardustItem ItemData;};

3.库存的其他数据

        我们游戏中的库存不是无限大的,所有有一个最大的槽位数,该变量可能受游戏中的因素影响,上面的数组大小始终等于该变量大小

        然后我们还需要加载全局单例,后面需要用到上一篇日志中提到过的“星尘”数据表

//仓库槽位数
UPROPERTY(EditAnywhere, BlueprintReadWrite, category = "StardustInventory")
int SlotsCapacity;
//全局单例,用于查询数据表中的物品数据
UPROPERTY()
class UAstromutateGameInstance* Instance;
//在.cpp的BeginPlay中实例化Instance
//Instance = Cast<UAstromutateGameInstance>(GetWorld()->GetGameInstance());

二.容器的查询

        因为我们之前实现过哈希表,所以可以直接O(1)查询某物品在库存中的容量

UFUNCTION(BlueprintCallable, Category = "StardustInventory")
FORCEINLINE int CheckStardust(FName StardustType) {return StardustCount[TCHAR_TO_UTF8(*StardustType.ToString())];};//从映射中O(1)查询其在库存中的数量	

        我们还有一个查询某物品在库存中还能添加多少的函数,也是利用哈希表O(1)实现

//.h中的声明
//检查星尘在库存中还能添加多少
UFUNCTION(BlueprintCallable, Category = "StardustInventory")
int CheckAddable(const FName& StardustId);//.cpp中的实现
nt UStarInventoryComponent::CheckAddable(const FName& StardustId)
{std::string StardustIdString{ TCHAR_TO_UTF8(*StardustId.ToString()) };//将FName转换成std::stringint StackLimit{ Instance->StardustMap[StardustIdString]->InventoryStatistics.StardustStackLimit };//该类物品的堆叠上限int AvailableInPartial{ StackLimit - StardustCount[StardustIdString] % StackLimit };//该类物品在非空槽位中还能装多少if (StardustCount[StardustIdString] % StackLimit == 0)//所有物品的堆叠上限不能为0{AvailableInPartial = 0;}int AvailableInEmptySlots = StardustCount["Empty"] * StackLimit;//在空槽位中可放的数量return AvailableInEmptySlots + AvailableInPartial;
}

三.库存的修改

        我们库存中的增加和删除操作都是基于对单个槽位的修改实现的,传入参数是期望的“星尘”,用的是完整的槽位中物品的结构,返回值为是否修改成功,修改时需要同时维护数组和哈希表:

bool UStarInventoryComponent::SetSlotElement(const FName StardustId,const int Amount, int index)
{if (index < 0 || index >= Storage.Num()){//检查索引是否合法UE_LOG(LogTemp, Error, TEXT("se slot at %d failed,invalid index"), index);return false;}int OriginalAmount = Storage[index]->ItemData.GetQuantity();	FName OriginalId = Storage[index]->ItemData.StardustId;StardustCount[TCHAR_TO_UTF8(*Storage[index]->ItemData.StardustId.ToString())] -= OriginalAmount;//先将这一格清空//如果星尘是新加进来的,就要将表格中的数据赋给新星尘std::string NewStardustId{ TCHAR_TO_UTF8(*StardustId.ToString()) };FStardustTable StardustInfo= *Instance->StardustMap[NewStardustId];int StackLimit = StardustInfo.InventoryStatistics.StardustStackLimit;//将新星辰的数据覆盖原星辰Storage[index]->ItemData = FStardustItem(StardustInfo);if (Amount > StackLimit){//超出堆叠上限的部分直接抛弃if (OriginalId == "Empty" && Storage[index]->ItemData.StardustId != "Empty"){StardustCount["Empty"]--;}if (OriginalId != "Empty" && Storage[index]->ItemData.StardustId == "Empty"){StardustCount["Empty"]++;}StardustCount[NewStardustId] += StackLimit;Storage[index]->ItemData.SetQuantity(StackLimit);return true;}if (Amount <= 0){//将该槽位的星尘替换成空星尘StardustCount["Empty"]++;Storage[index]->ItemData.SetQuantity(Amount);return true;}if (OriginalId == "Empty" && Storage[index]->ItemData.StardustId != "Empty"){StardustCount["Empty"]--;}if (OriginalId != "Empty" && Storage[index]->ItemData.StardustId == "Empty"){StardustCount["Empty"]++;}//正常更改数量Storage[index]->ItemData.SetQuantity(Amount);StardustCount[NewStardustId] += Amount;return true;
}

        我们还有一个整理背包的函数,可以实现将库存中同类物品尽可能放在一起:        

持续更新中。。。

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

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

如何用 OceanBase做业务开发——【DBA从入门到实践】第六期

当应用一款新的数据库时&#xff0c;除了基础的安装部署步骤&#xff0c;掌握其应用开发方法才是实现数据库价值的关键。为此&#xff0c;我们特别安排了5月15日&#xff08;周三&#xff09;的《DBA 从入门到实践》第六期课程——本次课程将带大家了解OceanBase数据库的开发流…

一键追爆款,GPT一键改文‌‍‬⁣⁡​⁤⁢​⁢⁡⁣‬‍‌​​‬ ​‍⁤‬ ‬⁡⁡⁡‍‌‬⁡⁡⁢‬⁤⁢⁢⁤​‍‌​​‬ ​⁣‌,绘唐3,绘唐工具

ai画影满足你的制作要求 一键追爆款&#xff0c;GPT一键改文 入口工具 AI推文小说&漫画解说&解压混剪 人物定义&#xff0c;角色定义&#xff0c;lora转换&#xff0c;模型转换&#xff0c;可视化参考满足 一键追爆款 一键挂机生成&#xff0c;效果更精彩&#xff…

Python-VBA函数之旅-tuple函数

目录 一、tuple函数的常见应用场景 二、tuple函数使用注意事项 三、如何用好tuple函数&#xff1f; 1、tuple函数&#xff1a; 1-1、Python&#xff1a; 1-2、VBA&#xff1a; 2、推荐阅读&#xff1a; 个人主页&#xff1a; https://myelsa1024.blog.csdn.net/ 一、tu…

【数据结构】线性表----链表详解

数据结构—-链表详解 目录 文章目录 链表的定义链表的构成链表的分类双向和单向带头和不带头循环和不循环 链表的命名基本操作的实现初始化打印取值查找插入指定位置插入删除删除销毁 部分其他链表的代码实现循环链表双向链表 优点/缺点&#xff08;对比顺序表&#xff09;优点…

探索 Linux 三剑客:grep、sed 和 awk 的强大魅力

序言 在 Unix 和 Linux 系统中&#xff0c;有一组被称为“三剑客”的命令行工具&#xff0c;它们是 grep、sed 和 awk。虽然它们在外表上看起来很简单&#xff0c;但它们的功能却非常强大&#xff0c;为文本处理提供了无限可能。本文将深入探讨这三个工具的用法和功能&#xf…

Franz Electron + React 源码启动运行填坑指南

环境要求 安装miniconda python 环境electron/rebuild用得着&#xff0c;miniconda 默认自带的 python 是 3.11 版本&#xff0c;比较新&#xff1b; 安装virsual studio 2019 要把C桌面相关的都安装了&#xff0c;大概需要20G&#xff0c;不要安装到 C 盘&#xff0c;都安装到…

古月居讲师/签约作者招募计划

机器人&#xff0c;作为一个集成了多学科技术的复杂系统&#xff0c;其开发过程充满了挑战。为了帮助开发者们更好地克服这些挑战&#xff0c;提升项目的开发效率和质量&#xff0c;古月居特别招募[博客签约作者/课程讲师]。如果您平常热爱记录、分享开发者经验的习惯&#xff…

vue3 中 使用 antd中的select 组件的带搜索框 展开后可对选项进行筛选搜索功能

鼠标进入以后下拉显示&#xff1a; 输入字符串以后&#xff1a; 可以看出对数据进行了筛选。 具体代码&#xff1a; 结构上&#xff1a;<a-selectv-model:value"formState.formFlow"show-searchallowClearplaceholder"输入选择流程":options"op…

批量文件夹随机重命名:一键操作,提升管理效率的技巧

在数字化时代&#xff0c;文件夹的管理是日常工作中不可或缺的一部分。对于拥有大量文件夹的用户来说&#xff0c;批量文件夹重命名是提高工作效率的关键步骤。而随机重命名不仅能增加文件组织的多样性&#xff0c;还能在一定程度上保护隐私。本文将介绍云炫文件管理器如何通过…

答辩PPT内容生成困难?文心一言逐步引导内容生成

这些网站我愿称之为制作答辩PPT的神&#xff01; 很多快要毕业的同学在做答辩PPT的时候总是感觉毫无思路&#xff0c;一窍不通。但这并不是你们的错&#xff0c;对于平时没接触过相关方面&#xff0c;第一次搞答辩PPT的人来说&#xff0c;这是很正常的一件事。一个好的答辩PPT…

GPT-4o 屠龙式震撼!多模态、实时交互、全员免费可用,丝滑语音交互的 ChatGPT 这把赢麻了

从 5 月初爆出将在 9 日发布搜索引擎&#xff1b;到 5 月 11 日&#xff0c;官宣将在当地时间 5 月 13 日 10 时发布 ChatGPT 与 GPT-4 更新&#xff1b;再到 Sam Altman 亲自下场辟谣「不是 GPT-5&#xff0c;也不是搜索引擎」&#xff0c;而是「像魔法一样的新东西」&#xf…

transformer通俗理解

transformer中最麻烦的encoder模块其实张量和矩阵的变化维度比较复杂。我感觉这篇文章讲的特别详细Q、K、V 与 Multi-Head Attention 多头注意力机制 - 知乎 我总结一下文章几个很重要的点吧&#xff01;算是我学的一点收获 1.什么是QKV&#xff1f; 2.怎么理解多头&#xff…