獨立游戲《星塵異變》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.pswp.cn/web/12123.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/12123.shtml
英文地址,請注明出處:http://en.pswp.cn/web/12123.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

huggingface:利用git克隆目標資源

前言 因為有很多模型資源都被放在了huggingface上&#xff0c;為了下載它們&#xff0c;著實讓一個不懂git的人犯了難&#xff0c;繞了很多遠路&#xff0c;甚至將不需要解決的問題也都拿上了臺面&#xff0c;因此我將在本篇博客中記載一些關于【huggingface】中利用git克隆目標…

【c++】全面理解C++多態:虛函數表深度剖析與實踐應用

&#x1f525;個人主頁&#xff1a;Quitecoder &#x1f525;專欄&#xff1a;c筆記倉 朋友們大家好&#xff0c;通過本篇文章&#xff0c;來詳細理解多態的內容 目錄 1.多態的定義及實現1.1多態的構成條件1.2虛函數的重寫1.3 C11 override 和 final1.4重載、覆蓋(重寫)、隱藏…

wireshark協議大致過濾規則

參考鏈接&#xff1a;真保姆鏈接 1、比較操作符 等于 &#xff01;不等于 >大于 <小于 >大于等于 <小于等于 2、協議類型 直接在Filter框中直接輸入協議名即可。注意&#xff1a;協議名稱需要輸入小寫。 tcp&#xff0c;只顯示TCP協議的數據包列表udp&#xff0c…

鴻蒙內核源碼分析 (內核啟動篇) | 從匯編到 main ()

這應該是系列篇最難寫的一篇&#xff0c;全是匯編代碼&#xff0c;需大量的底層知識&#xff0c;涉及協處理器&#xff0c;內核鏡像重定位&#xff0c;創建內核映射表&#xff0c;初始化 CPU 模式棧&#xff0c;熱啟動&#xff0c;到最后熟悉的 main() 。 內核入口 在鏈接文件…

在k8s中安裝Grafana并對接Prometheus,實現k8s集群監控數據的展示

&#x1f407;明明跟你說過&#xff1a;個人主頁 &#x1f3c5;個人專欄&#xff1a;《Grafana&#xff1a;讓數據說話的魔術師》 &#x1f3c5; &#x1f516;行路有良友&#xff0c;便是天堂&#x1f516; 目錄 一、引言 1、Grafana簡介 2、Grafana的重要性與影響力 …

強化訓練:day9(添加逗號、跳臺階、撲克牌順子)

文章目錄 前言1. 添加逗號1.1 題目描述2.2 解題思路2.3 代碼實現 2. 跳臺階2.1 題目描述2.2 解題思路2.3 代碼實現 3. 撲克牌順子3.1 題目描述3.2 解題思路3.3 代碼實現 總結 前言 1. 添加逗號 ??2. 跳臺階 ??3. 撲克牌順子 1. 添加逗號 1.1 題目描述 2.2 解題思路 我的寫…

【Vue】vue中動態樣式綁定

在Vue中&#xff0c;可以使用動態樣式綁定來根據數據的變化來動態修改元素的樣式。動態樣式綁定可以通過以下幾種方式實現&#xff1a; 對象語法 <template><div :style"dynamicStyles"></div> </template><script> export default {…

STM32學習和實踐筆記(28):printf重定向實驗

1.printf重定向簡介 在C語言中printf函數里&#xff0c;默認輸出設備是顯示器&#xff0c;如果想要用這個函數將輸出結果到串口或者LCD上顯示&#xff0c;就必須重定義標準庫函數里中printf函數調用的與輸出設備相關的函數。 比如要使用printf輸出到串口&#xff0c;需要先將f…

linux 任務管理(臨時任務定時任務) 實驗

目錄 任務管理臨時任務管理周期任務管理 任務管理 臨時任務管理 執行如下命令添加單次任務&#xff0c;輸入完成后按組合鍵Ctrl-D。 [rootopenEuler ~]# at now5min warning: commands will be executed using /bin/sh at> echo "aaa" >> /tmp/at.log at&g…

什么是 PL/SQL

PL/SQL 是 Oracle 公司開發的一種過程化擴展 SQL 語言&#xff0c;它結合了 SQL 語句和過程化編程的特點&#xff0c;允許開發者在一個塊&#xff08;block&#xff09;中編寫聲明、條件語句、循環等&#xff0c;使得數據庫編程更加靈活和強大。PL/SQL 常用于 Oracle 數據庫系統…

bash腳本 報錯:/bin/bash^M:解釋器錯誤: 沒有那個文件或目錄

bash腳本 報錯&#xff1a;/bin/bash^M&#xff1a;解釋器錯誤: 沒有那個文件或目錄 出現這個問題是因為該腳本文件在windows下編輯過 在windows下&#xff0c;每一行的結尾是\n\r&#xff0c;而在linux下文件的結尾是\n&#xff0c;那么你在windows下編輯過的文件在linux下打…

J-STAGE (日本電子科學與技術信息集成)數據庫介紹及文獻下載

J-STAGE (日本電子科學與技術信息集成)是日本學術出版物的平臺。它由日本科學技術振興機構&#xff08;JST&#xff09;開發和管理。該系統不僅包括期刊&#xff0c;還有論文集&#xff0c;研究報告、技術報告等。文獻多為英文&#xff0c;少數為日文。目前網站上所發布的內容來…

零基礎學Java第十三天之日期類

日期時間類 1、Date 1、理解 表示特定的瞬間&#xff1a;Date對象表示從"epoch"&#xff08;即1970年1月1日 00:00:00 GMT&#xff09;開始計算的毫秒偏移量。不包含時區信息&#xff1a;原始的Date類不直接處理時區。它只是一個時間點&#xff0c;沒有與時區關聯。…

使用Vue調用ColaAI Plus大模型,實現聊天(簡陋版)

首先去百度文心注冊申請自己的api 官網地址&#xff1a;LuckyCola 注冊點開個人中心 查看這個文檔自己申請一個ColaAI Plus定制增強大模型API | LuckyColahttps://luckycola.com.cn/public/docs/shares/api/colaAi.html來到vue的頁面 寫個樣式 <template><Header …

ICode國際青少年編程競賽- Python-5級訓練場-綜合練習6

ICode國際青少年編程競賽- Python-5級訓練場-綜合練習6 1、 for i in range(3):Dev.step(2 * (i 1))Dev.turnLeft()while Flyer[2 - i].disappear():wait()Dev.step(2 * (i 1))Dev.turnRight()while Dev.x ! Item[i].x:wait()2、 for i in range(3):Dev.step(2 * i 1)while …

用Python的pynput庫成為按鍵記錄高手

哈嘍&#xff0c;大家好&#xff0c;我是木頭左&#xff01; 揭秘鍵盤輸入&#xff1a;pynput庫的基本介紹 無論是為了安全審計、數據分析還是創建熱鍵操作&#xff0c;能夠記錄和處理鍵盤事件都顯得尤為關鍵。這就是pynput庫發揮作用的地方。pynput是一個Python庫&#xff0c…

Java 對象序列化

序列化&#xff1a;把對象轉化為可傳輸的字節序列過程稱為序列化。 反序列化&#xff1a;把字節序列還原為對象的過程稱為反序列化 序列化的作用是方便存儲和傳輸&#xff0c;細節可參考如下文章&#xff1a; 序列化理解起來很簡單 - 知乎序列化的定義 序列化&#xff1a;把對…

echarts map地圖添加背景圖

給map地圖添加了一個陰影3d的效果&#xff0c;添加一張背景圖&#xff0c;給人感覺有3d的效果 具體配置如下&#xff1a; html代碼模塊&#xff1a; <div class"echart_img" style"position: fixed; visibility: hidden;"></div><div id&q…

Autoware內容學習與初步探索(一)

0. 簡介 之前作者主要是基于ROS2&#xff0c;CyberRT還有AutoSar等中間件完成搭建的。有一說一&#xff0c;這種從頭開發當然有從頭開發的好處&#xff0c;但是如果說絕大多數的公司還是基于現成的Apollo以及Autoware來完成的。這些現成的框架中也有很多非常好的方法。目前作者…

【Java的抽象類和接口】

1. 抽象類 1.1 抽象類概念 在面向對象的概念中&#xff0c;所有的對象都是通過類來描繪的&#xff0c;但是反過來&#xff0c;并不是所有的類都是用來描繪對象的&#xff0c;如果 一個類中沒有包含足夠的信息來描繪一個具體的對象&#xff0c;這樣的類就是抽象類。 以上代碼中…