Architecture - Blueprint Inventory Part One [Long Post!]

Unfortunately, every time I screen record, the unreal engine crashes. So, I'm instead going to have to backtrack through what I have already done to try and showcase it in several screenshots instead, so that I can upload a small amount here and there whenever I have added something to the games blueprints! Woo!

The following posts will be following an already existing tutorial that I will be talking through, made by user "Unreal Gaime Dev" - Please make sure to watch his tutorials and show him some love, whilst this inventory isn't clean or crisp, it is a very well functioning inventory using physical slots instead of a list.

I just got done adding a very very simple currency system that currently isn't used anywhere else in the game, that's something that will come at a later date. Instead of spending two 6-hour days coding, I figured I'll stop until tomorrow and show the blog some love.

The screen shot dimensions may be a little off on the preview, I don't really know the intricacies of Blogger to know how or where to change this, so if you are looking to see a closer, more detailed screen shot, simply click on the image and it will open it in a 1080 resolution!



At the dawn of time


In the very beginning, the very first thing that I added, before any kind of UI widgets, was a struct. The struct I set is called "Item Info," and as the name might suggest, it's information that will be fed into every item that I choose to add into the game.




Whenever I need to add a new property to the item, such as "Can Be Sold," or what I did today, "Static Mesh," I simply need to add the variable to this struct, compile and save, compile the master item blueprint, and then it will be ready to start working on. At the very start, there was only Name, Description, Icon, Can Be Used, Use Text, Can Be Stacked, and Category. I've not had to add too many variables outside of what I believed to be the core ones, but any new additions I will be sure to make clear with a new post!

Secondly was the Category Enum. Or, rather, I had to complete the Enum before I could complete the Struct, even though I started the struct first. The Enum was responsible for the Item's Category.

Unlike Structs, Enums can't hold different variants of variables, they can only hold a collection of one. When I first made the system, the only enumerators I had were Consumables and Quest Items. I've managed to fill it out quite well so far! 

Recently, the framework for the crafting system has been almost completed, one of the changes I had to do was make the item categories allow for different tiers, as the better the player did in the puzzle, the higher tier the item they will receive, and the more money it will be worth. So, the two additions of Equipment and Weapons had to then be split even further into the five rarity tiers that I chose. 

With the item properties struct completed, the next thing was to make the Master Item class that will use this struct. The reason for using a master item over and over again instead of making each item its own blueprint is simple: Make the master item hold the Item Info as a blueprint variable of type S_ItemInfo. Then, every time you make a child of this master item, you don't have to set up Item Info every single time, it will be a default of the class. Efficiency is clever laziness.

So from this master item class, three new items were born: A ring, a map, and a potion. If you're looking for a reasoning why these items, there isn't one. Just the first three things that came into my head. I needed to make sure that everything was working and the items themselves weren't important, as later down the line I will need to bulk add maybe 200 or so items to flesh the game out. The work I am doing now is to make sure when I do that, it will be extremely simple, like filling out a form for each item, and the item then knowing what to do whenever it is used or interacted with, etc.

Finally, another struct was added called "InventorySlot." This is basically the information that the visual inventory will need to know, and it simply consists of two things: The Item Class, which is a variable of BP Master Item, and is a reference to the items class only. And then an integer variable for the amount of items in that slot. (1 for non stackable items, then 1-99 for those that can.)

The Inventory

The inventory was perhaps the second trickiest part of this whole project so far, and the inventory blueprint currently holds 22 unique functions and 11 variables, with each function having its own local variables. Trying to retrace my steps with this one is going to be very hard, so instead I will pick out parts that I can remember!

Variables

The variables that I set to begin with were how many inventory slots I wanted the player to have, the maximum stack size for stackable items, a reference to the players "TopDownCharacter," and a reference to the Inventory Slot struct. One of the first functions was to give the player an inventory. This inventory at the moment is hypothetical, as there is no visual representation of it just yet, but the code must be implemented first. It resized the players "Slots" array (Of type Inventory Slot) to the "Amount of Slots" variable. So, whatever number was in the Amount of Slots, the player will get that many. This can be changed later on if perhaps 42 slots is too many, but I went for 42 slots on a 6 row grid. 

Method #1 - Is slot empty?

The very first function added to the inventory was a simple method of checking if the current slot at Index# was empty. 

Because of how small and simple it is, I won't explain this method. There may be several methods I either don't explain or skip on this specific blog post, because I have a lot to go through. 

(If only my project management and time management were on point, I could have had 20 blog posts detailing every new function I add!)

Method #2 - Get item information at slot index


Next up was searching for finding the S_ItemInfo from the S_InventorySlot, assuming that the slot had something inside of it. If the slot had no item class or amount assigned to it, then the function returns that slot as empty. Otherwise, it will return the inventory slots information.

Method #3 - Search for an empty slot


The next task, or rather, next two tasks, are very similar in nature. First, a method to find the next empty slot that can be filled. Secondly, the next available stack that is not full. Both of these functions use a ForEach loop with a break. The empty slot logic cycles through all of the inventory slots present in the "slots" array (the players inventory) and whenever it finds a valid item class, it skips that index and starts searching the next index, until eventually it finds an empty slot. It then returns the "IsEmpty" bool, and the index number.

Method #4 - Search for a stack that has free spaces



As for the Available Stack, it's a little more complicated but the logic is still pretty much the same. Instead of just searching for the slots item class, it also has to check that the item class can be stacked, find out how many are currently in the stack, and check that the amount is lower than the Maximum Stack Size we determined at the start of the inventory BP.

Method #5 - Add Item

Add Item -vs- Add Item (Internal)


The first big method of this inventory blueprint was being able to add an item to the players inventory, or rather, assign an item class and amount to the players next available empty slot. The current version of this method has been named "Add Item(Internal)", as this is the logic for adding an item, however I wanted several things to happen once an item had been added. Instead of trawling through the mass of nodes that constitute the Add Item function, I instead made a method that simply fires off the internal version of the blueprint and then added whatever was required to the "Add Item" method. Efficiency is clever laziness. 

In the context of the blueprint, this was adding an extra input variable, asking for a notification, and then showing a notification if this bool was true, as well as updating the crafting menu with the players inventory every time an item was added.

Inventory Widget Setup

With the bare basics set up, as well as a few functions that will be called upon shortly, we need a widget to visualise the players inventory. Here, three widgets were created: The inventory slot, the inventory widget, and the main widget.

Inventory Slot


The inventory Slot itself is very simple, it is a button with an icon on top of it and a text amount, all of which are variables. There are a lot of functionalities that I may cover at a later date, but mostly they are bindings to take the ItemInfo icons, stackable booleans, amounts etc.

Inventory


The inventory widget itself is just a scroll box that will house all the instances of the Inventory Slot, plus a little extra functionality that has been added, such as a currency counter, action bar, and a sorting system. The coding for the inventory is simply assigning the inventory slots co-ordinates within the widget. 

Main Widget

And finally, the main widget is the players main widget that will be drawn to their HUD. The visibility of different sections of this widget will change as keys are pressed or buttons closed. This serves as a canvas for all the user created widgets, and holds little coding itself.

Adding items to the players inventory.

Add Item (Internal) Blueprint

Fair warning: Buckle up. This function is long. You may wish to skip this method!



Now that the inventory has a physical representation and a widget for housing inventory slots, its time to populate those slots with items!



The first part of this blueprint would simply take the item class and amount that was required from the input, and then promote those to local variables so that I would not have a million wires connecting to the function entry. These were followed by a branch, checking the item class for the bool "CanBeStacked?" Different outcomes need to happen depending on certain properties the item has, and this was the first example. Assuming that the item cannot be stacked, the next task is to find the next available empty slot. 



If the "Search Empty Slot" function finds no empty slots, then the players inventory is full and nothing will be added. If it does find an empty slot, it will take the output from the "Search Empty Slot" function, and promote it to a new local variable called "Found Index." As mentioned before, this is just to try and make the code a little tidier, as this will be called upon often.

The next step is to set the array element at this "Found Index", to be the local class set at the start of this blueprint. The amount is set to one, as we are currently on the "Cannot Be Stacked" path. This then feeds directly into the "Update Slot at Index" function, which is a custom event in the inventories event graph. This simply takes the Inventory Widget reference, finds the slots widget where all the slots are given properties, and then fires off the "Update Slot" event housed in the inventory slot blueprints. 



To avoid going too off-track, I will display a screenshot of the update slot logic, but not go into any detail about its function or purpose.



Finally, a branch will determine if the local amount is now greater than one. Being that we are on the "Cannot Be Stacked" path, this would mean that we have added one instance of the item, however there is still one or more remaining to be added. If this is false and there are no more to be added, return with a success = 1, and the "Rest" output as 0. If the amount however is greater than 1, then there are still instances of this item to be added, and a small loop is created at the end of this execution where the function will call itself once more, setting the local class and amount as the new input, and returning the success boolean and rest variables as required, until eventually it runs an instance where the local amount is 0, and the branch can finally end.



The bulk of this execution chain is replicated with subtle changes as a player tries to add an item as a part of a stack. And this is where the "Search Free Stack" function comes in. If the method is able to find a free stack, it will set the index to the "Found Index" local variable, and perform another check. 


Similarly to how the first route checks for any left over items not able to be added to the same slot, this route checks for any left over items that are over the maximum stack size that will need their own inventory slot. From there, the blueprint will set the array element and keep calling itself until every item has been successfully given a slot.



The final path of this blueprint is for when the item is stackable, however there isn't a free slot, either because it's a different item or the current stack is at its maximum size. This simply follows the second routes logic of checking for how many an item can be stacked, if there are any left over, and will continue to call itself until all items have been added. 

Method #6 - Get amount at index



The method used here simply takes the players slots array, breaks it to the structs two variables, and returns the items amount as an integer. This is called to by the Inventory Slot widget, where it asks for the item amount at the players inventory index number, so it can then display that number visually.

Methods #7 and #8 - Open and close the inventory

The last two methods I want to talk about to finish off the barebones inventory system is the ability to open and close it. The blueprints for opening and closing must be made first, so that it can be called in two locations later: Once when the player clicks the red "X" on the inventory button, and another whenever the hotkey "I" is pressed. These methods simply set the widgets visibility, set a boolean to be used by the hotkey, enable the widget for use, and return. Vice Versa for closing the inventory.



End.


So as to not burn myself out writing an encyclopedia on how I got the inventory system to work (It's still not flawless!), I will leave the barebones inventory system as its own post and the next few posts labeled as "Architecture" will continue where the previous one has left off, until eventually the blog is up to speed with where I am at work wise.

Project Management

Before we end here I'd like to quickly take a moment to explain where I am with the project and what I want to have accomplished soon. As I mentioned at the beginning of this blog post, I have a very simple currency system set up now, and by the 11th of March, I plan to have at least one merchant present in the level that the player can buy and sell from. What he sells isn't as important as can he sell.

Looking over the last few blog posts and the hack and plan in general, it's clear to me that I have started to let AV slip, and may have to put some of the coding work on pause.

Comments

Popular posts from this blog

Architecture - Blueprint Inventory Part 2: Inventory Functionality, Drag and Drop