Loading

Logo

Inventory and Equipment

Programming and System Design · 10 minutes Read

Creating items from various sizes that are able to be stored, joined together, split, and equipped.

This inventory system relies on my Saving and Loading in Unity blog post to work optimally.

Just a quick disclaimer before we start, this post will most likely be very programming heavy, and people reading should possess at least a moderate amount of Unity experience to adapt and upgrade the code. As of today, I've added every feature I could think of, but as you develop a game or system, more complex technical requirements arise that require someone with an understanding of the code to be able to handle, and if you desire to implement this system into your products these issues might arise further on in your project.

This inventory system works like most modern ARPGs, with variance in item sizes, equipment requirements, and splitting and stacking. Everything within this code is customisable, and I hope you find reading through it useful. The first step is creating a simple JSON file with all the item variables, these can be whatever values you require but just remember elements such as gameobjects or prefabs cannot be saved within JSON and must be called after. So, without further ado, let's jump straight into the code.

"Items": [
	{
		"ID": 0,
		"Title": "Sword",
		"Description": "Does some Damage",

First we introduce some basic variables, of course these all depend on the type of game you're creating, but it's generally good to have a title and description nevertheless.

		"Stackable": true,
		"StackAmount": 10,
		"CurrentAmount": 0,

These variables are to store simple numerical values that we can later influence through code.

		"Size": [],
		"SizeX": 1,
		"SizeY": 1,
	}
]

Lastly, we introduce variables to store the size of this object, the ability to drag and store depending on its X and Y size as players drag it around the inventory.

Part 1: Setting Up

Once we have the JSON file initialised with all the values we need, we now need to parse it through Unity to create our database as described in my Saving and Loading blog post.

This list will store every item you've created and is vital to accessing their values whether they're in the first or last slot of your inventory. Likewise, to access any value from that specific item, reference its ID from the JSON file before you instantiate them.

public void LoadItems()
{
	int i = 0;
	foreach (Item k in loadDataBase)
	{
		items[i] = k;
		i++;
	}
}

The next part is relatively laborious as it requires you to instantiate the individual slots that each item gets instantiated and dragged within. To do so in a clean manner, make sure to utilise Unity's inbuilt Grid Layout Group where you can set the sizes and spacing between each slot. Next, create a prefab called slot, adding a script onto it that will hold certain values, customisable to what specifications you want each inventory slot to be able to hold, for example, assigning a Sword a "Weapon" tag, you can add a requirement for a specific slot to only hold Weapons.

for (int i = 0; i < slotAmount; i++)
{
	items.Add(new Item());
	slots.Add(Instantiate(inventorySlot));
	slots[i].GetComponent<Slot>().id = i;
	int i = 0;
}

Part 2: Creating the Items

So at this point, we have our items and values set up, as well as some empty slots created on-screen each with their unique ID, and accepted state. Next, we call the InstantiateNewItems void to apply the items list to each slot, and create them if not empty.

public void InstantiateNewItems()
{
	int i = 0;
	foreach (Item j in items)
	{
		if (j.ID != -1) // Item is not null
		{
			GameObejct itemObj = Instantiate(inventoryItem);
			itemObj.GetComponent<ItemData>().CreateItem(j);
			itemObj.GetComponent<ItemData>().item.Amount = j.Amount;
			itemObj.GetComponent<ItemData>().slot = i;
			itemObj.name = j.Title;
		}
		i++;
	}
}

We then call the CreateItem void inside each item to set a reference to the item class we also created earlier, using the JSON list as a reference for values. Due to the fact each item was saved directly onto a new JSON file, we don't read from the JSON list until we make a new item, allowing us to save unique variables, supporting elements such as crafting and customisation. However, this works both ways, with any future game update we push not being able to access the pre-created items. A solution for this would be saving and loading only the item ID, and instantiating a completely new one upon starting, yet this removes customisation.

To create a completely new item from scratch, simply access the JSON file directly, and instantiate it using its ID. Lastly, you can set up any other values you prefer such as text, images, and other unique attributes. For mine, I set up an image to scale with the size of the item and set a small text that appears when the item is above 1.

Part 3: Dragging and Placing

All right, we're nearly there, this is the last part, and it's arguably the hardest due to the number of checks required. The simple part is being able to drag and drop each item, however, the complexity arises once you take into consideration the size and collisions. For this example, I created a couple of items with various sizes, as well as a way to spawn and delete them. I'll avoid covering how to do every single part as I'm sure you can figure out, but I'll quickly cover how to approach it.

The first step is setting up a simple drag and drop interface. This can further be updated with elements such as single-clicking and then clicking somewhere else to move, as well as a double-clicking to instantly equip. A way to optimise is by using the same code as dragging but instead have it instantly teleport to whatever position you require, and then run the rest of the script. Remember to move every item inside that items size list, you can do this by setting each of them as an items parent, and moving that instead. The next step is to set up a raycast that can be called upon to detect collisions. Mine is set up to only detect Slots and upon getting a hit, updates that items "draggingslot" value to the hit value. The reason I don't update the items slot value straight away is because we need to run a couple of checks to see if it'll fit, and it's important to know where the item is being dragged as well as where it was was originally.

Upon dragging the item to an empty slot, simply loop through each item with the raycast and check if it can fit. If it can, then update the slot values to the draggingslot values, and set their position and parent by using the slot list you created earlier. However, upon hitting another item it gets more complicated as you need to run numerous checks to see if it fits. Due to having each item have a size list, we can run a simple check to see which item is bigger, allowing us to optimise the checks ever so slightly. If the item you're dragging is bigger, then you can move the other item and only run a raycast check on that item. If you want some lenience, you can have the items position update a couple of spaces to the left and right to check if it fits. If the item you're dragging is smaller, then you know it will fit, and you only need to run a check on the other item, this can likewise afford some lenience. One major element is to allow the ienumerator to loop through various items, this allows you to drag a sword on top of numerous items and for them all to swap positions. Lastly, remember to update the items list for when you save and load those items onto the gamemanager.

Unfortunately, I dont have any examples to show the full potential of this inventory system, but if you're interested in seeing how it works you can play Tavvnsgard.