Writing up the last post about my point-and-click interface turned out to a be pretty good way of keeping me organized so I thought I’d do the same for my current inventory setup. As before, I’ll be using Playmaker, this time I’ll also be using Arraymaker and EasySave2 so you’ll need the actions for those as well…
For my purposes, an inventory needs to perform several functions:
- Keep track of items collected
- Display relevant icons for each item
- Allow using items with scene objects/characters and vice versa
- Allow combining of items within the inventory
It also needs to work across multiple scenes, if you pick up an object in one room you’ll want to be able to use it in another, and upon re-entering said room, we’ll need to make sure any objects previously collected don’t reappear. For a simple test, I have two separate scenes, one with several items to collect (padlock, knife and tape) and one with a static object (cardboard box with key inside) with which to interact:
The 3d objects you can see there are Scene Items, the Inventory Items prefab contains the icons we’ll use to fill the inventory (in this case TK2d sprites), and the Inventory object keeps track of any changes via two Playmaker Array List Proxy components; referenced as Inventory and Collected Items respectively (not shown).
Above is the FSM Template used for each Scene Item. Each have a couple of local GameObject variables exposed in the inspector: Inv_Item for designating the corresponding Inventory Item (eg. ITEM_Knife is paired with INV_Knife) and Inventory just to set the reference to the relevant scene object. There is also Self (Gameobject) and Name (String). Upon clicking:
- we add the relevant Inventory Item to the Inventory array and make sure the icon is active
- get and add the objects name to the Collected Items array
- deactivate the Scene Item
You might have noticed that we’re storing the Inventory Items as an Array List of GameObjects while we’re storing the Collected Items as Strings. The issue with using an array of objects across scenes is that upon loading, if an object in one scene doesn’t exist in another it gets stored as an empty slot, I’m using auto save/load when exiting/entering scenes so the list will get overwritten as soon as you change scene a couple of times. There is probably a solution using Resources.Load but I’ve gone for the simpler method of simply storing the Scene Items by their Name and running GameObject.Find when loading each scene. This doesn’t affect the Inventory Items which all need to be available in every scene.
- Upon Scene Load we load the two Array Lists from a previously stored save file. At this stage all potential Inventory Items are active and in scene so we have no issues building an array of GameObjects. After our arrays are both populated without issue we set about updating the scene to match, firstly deactivating ALL the Inventory Items and activating ALL the Scene Items.
- We then cycle through each of our arrays and activate/deactivate the relevant Items, for the Inventory Items (in yellow) this can be done directly while for the Scene Items (in red) we have to use GameObject.Find first.
- To arrange the Inventory Items we simply set the position of the first one to a predefined Vector3 (Inv_Slot) and for each subsequent Item we increase that a little. When the cycle is finished Inv_Slot is reset to its original value.
- Standard save/ load functions assigned to key presses and the scene switch. Note, as with Scene Load, we need to make sure all Inventory Items are active before updating the array or we’ll end up with empty slots.
If you’re testing the scene at this stage you’ll need to create the autosave.sav file or it’ll throw a file missing error. To do this:
- temporarily changed the Start State to Idle
- temporarily rename the Save File in the Save Arrays state to autosave.sav
- start the scene and hit the S key
Don’t forget to change the Start State and Save File name back to the way they were afterwards. Now when you start the scene and subsequently change scene, autosave.sav should get updated. The Scene Select FSM looks like this:
Now that we hopefully have the inventory updating with Items being added to it, we need to sort out interactions within it and getting Items back out again. The FSM template for individual Inventory Items is set up as follows:
- We only want to select one Inventory Item at a time so a global variable Cursor State keeps track of when the cursor is “occupied”. We can then check if a user is trying to select an Item or use a previously selected Item on something else. To provide some visual feedback we scale up selected Inventory Items slightly and then back down when reset.
- We store the currently selected in a Global Variable Selected INV Item in order to access it either from other Inventory Items or from Scene Items. Scale up when selected with a first click, deselect and scale down with a second click on the same Item.
- If a player clicks on an Inventory Item with another already selected, we check through an array of Compatible Items and if necessary, create the Result Inv Item, add it to the Inventory array, remove the second picked Item and tell the Inventory to cycle through and reorganize. Finally resetting all the Items to their original states and Cursor State to 0. This happens in the video with the lock and key.
Although not really exploited in this scenario, each Inventory Item has its own Array List Proxy containing any compatible Items. In this case we could just as easily have used a single GameObject variable but the setup allows for a bit more variation eg. a lock object that could be opened with a key, a hairpin, a piece of wire or a screwdriver you could just drag and drop them all into slots on this array and check through them when necessary.
Once we have a selectable inventory we can test it out in the second scene, the box has the following FSM:
The box is actually two separate objects, one open, the other closed, a Global Variable (bool) Box Open is used to keep track. On click we compare the previously set Selected INV Item with a local variable and activate/deactivate objects as required and update Box Open.
So that’s a pretty simple inventory system working and the beginnings of a save system too, you can see a video of it in action on YouTube here. There’s an awful lot that could be optimised in this setup so I might update at a later stage. As always, comments, crits and corrections are very welcome.