Hello and welcome to another one of our coffee-break tutorials! This time around we're going to be showing you how to make a simple inventory system in the style of the original "Zelda" games. In this tutorial we'll be looking at using arrays and macros to construct our inventory, and by the end of it you'll have a small project with a five slot inventory that permits you to pick things up, stack them, and then put them down again. Now, before getting started, this tutorial requires you to download the following the project and open it in GMS2:
NOTE: This tutorial is for people that use DnD™. If you prefer to use GML to make your games, we have a companion article for you here.
Before getting stuck in, we recommend that you take a moment to look through the project as it already contains some objects and some DnD™ to make your life easier. You'll see we have an inventory object and an item object. The inventory has some basic code to track the currently selected "slot" and to draw itself to the screen, while the item object simply selects a sprite to display from a selection of possible item sprites. If you run the project you can use the mouse-wheel up or down to change the currently selected inventory slot, but not do much else... So, let's fix that and create an actual working inventory!
NOTE: The graphics used in the demo project are courtesy of Kenny Assets, and we highly recommend checking out their stuff as it's great for rapid prototyping and getting started making projects in GameMaker!
To manage our inventory we're going to be using arrays. An array is really just a way of making a single variable hold more than one value, and they are incredibly useful when programming as they permit you to easily store large amounts of data using a single "source" variable, and also permit you to easily iterate over that data using a loop.
NOTE: For more information on arrays and how they work, please see the manual.
For our inventory, we'll be using a 2 dimensional array. What this means is that we'll have our base array - that corresponds to each of the item slots in our inventory - and then each "slot" of that array will itself contain another array, which will correspond to the information about the item being stored. Below you can see a schematic image of how this is going to work:
So, for example, say we want to get the amount of items in the inventory slot 3. We would access the array using the following syntax:
amount = inventory_array
Array slots are always counted from 0, so slot 3 in the inventory is slot 2 of the array, and it holds another array where its slot 2 is the amount of items being stored. Don't worry if this seems a little confusing as I'm sure it'll become clearer as we put it into practice! In fact, the next thing we need to discuss is an ideal way to make working with arrays a lot easier, and that's to use macros.
In GameMaker Studio 2 a macro is a type of constant that is created with a value when the game is first run, and the value it is given never changes and cannot be changed in the game. This means that once you assign a value to a macro, it can be used everywhere in your code and you'll know that it will always be the same, no matter what. Why is this useful to us? Well, it means that we can essentially assign names to the different slots in an array, which in turn means you don't have to remember which number corresponds to which value in the array, as you simply use the predefined macro.
Let's go ahead and create these macros now. For this we'll create a new script asset and call it
init_game. By default it'll be created with a "Declare A New Function" action, but we don't need that to define macros as they'll be pre-compiled when you run the game anyway. So, delete that action then add the Macro action (from the "Common" section of the DnD™ toolbox). We're going to define a number of different macros that will all be used to make it easier to control what's happening with our inventory, starting with some macros for each of the different item types that our game can have - in this case a sword, a bow, a key, a potion, and food, and we also define a macro for when no item is present:
We are also going to assign macros to each of the array slots for item type, item sprite, and item amount, so add those too:
If you wanted to you could add further macros for each of the inventory array "slots" too, but I don't think that's really necessary in this case as we know that array slots 0 - 4 will correspond to inventory slots 1 - 5, and we'll generally be using local variables to reference these slots anyway.
Let's quickly look at the example we gave above for getting the amount of items in the inventory slot 3, only this time using the macro:
amount = inventory_array[item_amount]
That might be slightly longer code, but it's now much more obvious what value we are retrieving! This means it's time to start adding some code to our objects and actually get this inventory working...
With those preliminaries out of the way, let's open up the object
obj_Item and edit the Create Event. We want to use the new macros we have created here to define what kind of item is being created and to store some values so that when the item is "picked up" to put in the inventory, we know what kind of item it is. For that we'll edit the Choose action already there and add some extra code to set the correct sprite index:
Now, each item in the project will have a variable
item which will hold a macro for the type of item it is, and we have also set the sprite for the object based on this value. Note that in your own games it's unlikely you'll have a single item for picking up, but what's important here is that each item in the game has the same variable that can be used to identify what the item actually is.
It's time to make our inventory functional, so open the object
obj_Inventory now and go to the Create Event. There are already some DnD™ actions in there, so we'll be adding the new actions under them, as shown in the image below:
What we are doing here is using the function
array_create() to create a 5 slot array to represent each slot in the inventory, and we are setting each inventory slot to be an empty array using
[ ]. We then use a
For loop to go through each of the empty arrays and populate them with initial values for the item type, the item sprite, and the item amount.
We need to go back to our item object and we'll have it respond to a click from the mouse, which will add the item to the inventory. For this you need to open
obj_Item (if it's not already open) and add a Mouse > Left Pressed Event to it. Before we actually add in the actions we require let's quickly outline what we'll be doing in this event:
Now you know the plan, let's add the actions! We'll do this in chunks to try and keep it clear what's happening... so to start with, let's create some local variables and change the scope:
With those local variables created and the scope set, we want to do the first loop through the item array to see if the item being picked up already exists (as we can then stack the item in the inventory):
Here we are using the
_poslocal variable as a counter while looping through the item array. If it reaches 5, it means that no item of the type being picked up currently exists in the item array, and if it's less than 5, then the item does (
_pos will be a value from 0 - 4 and correspond to the array slot that the picked up item belongs to). We'll now check the
_pos value again and perform another loop if it's 5 to find the first empty space in the inventory:
Finally, we'll check the value of
_pos again, and if it's 5 then we know that there is no space in the inventory and the item being picked up is also not already in one of the occupied slots. If it's less than 5, then we can go ahead and add the item to the inventory and destroy the item instance in the game:
Note that the last action Destroy Instance has set it's scope to
other. This is very important, as otherwise you'll destroy the inventory instance rather than the item instance, since the inventory instance is the current scope for the actions.
Now that we can pick things up, we need to be able to see what they are. For that we'll edit the
obj_Inventory Draw Event, so open that now. We already have a few actions here to draw the inventory base and the currently selected inventory slot, and we need to add further actions underneath those. We'll be using another
For loop to loop through the inventory array and draw the items based on the type and the sprite that has been stored in the item array for each slot along with the amount of each item:
The last part of the inventory puzzle that we need to resolve is how to drop items and remove them from the inventory array. For that we'll simply use the right mouse button, so in the object
obj_Inventory add the Mouse > Global > Global Right Pressed Event to the object. In this event we'll first check that an item exists in the selected inventory slot, then we'll create the item, and then remove 1 from it's amount in the inventory (and if we have none left, set the slot to have no items). To do all that we'll need the following actions:
Note that the
Apply To... action is being used to apply the correct item values to the newly created instance with the ID stored in the local variable
You can go ahead and run the project now! If all has gone well, you should be able to:
Hopefully this has given you not only a good base on which to build more sophisticated inventories for your own games, but also a better understanding of how to use arrays and macros when working with GameMaker Studio!