Basic Inventory and Looting System

Inventory-iPhone

I’ve been looking through the Unity3D forums for information and answers about creating a basic inventory system. The analogy that I was trying to work towards was a system more akin to Worlds of Warcraft, where the player is looting objects such as chests or dead opponents rather than picking up objects from the ground, and discarding objects would simply destroy the item rather than “drop” the item back  into the game as a newly instantiated GameObject.

From my search, three threads stood out:

http://forum.unity3d.com/viewtopic.php?t=11865    Der Dude

http://forum.unity3d.com/viewtopic.php?t=46222    Alexwilds

http://forum.unity3d.com/viewtopic.php?t=51475    stneas

All three of these systems deserve your time and analysis as they all have different approaches to creating an inventory system.

The system posted by stneas is by far the most complicated and could be the most versatile, as it includes editor scripts, serialization and a whole host of other good code. DerDude’s system, on the other hand, is the most straightforward and easy to understand and this is where I chose to start.

This is the web build of this example project.

Some notes before starting:

Due to license issues, many of the images seen in the web build of the example project are not included in the example package. Notably the images from Blizzard’s World of Warcraft, are not included. These are definitely not licensed for commercial use or distribution and are used in the above example for testing purposes only. Please do not use any images for any purpose that could violate their license or any local or international laws.

Just to be clear, this code is based on material posted on the Unity3D forums at http://forum.unity3d.com by Der Dude on http://forum.unity3d.com/viewtopic.php?t=11865 and all due credit needs to go to Der Dude for the time and effort he has put into the code I based this system on. All relevant comments from Der Dude have been left intact within the code. I will not be explaining Der Dude’s code outside the context of what is used in this enhanced version.

The Basic Inventory & Looting System

This is the unitypackage containing all the relevant items from the example project.

From the player’s perspective, hitting the “I” key toggles the main inventory window. If a loot window, hitting the “I” key to close the main inventory window will also close the currently open loot window. Clicking on any lootable object creates new loot contents from a loot table and opens a loot window for that lootable object displaying the new loot content. If the Inventory window is not open, opening a loot window will open the inventory window. Repeatedly clicking on the same lootable object will toggle the loot window open and closed. Clicking on a different lootable object will leave the loot window open, but will change the focus of the loot window to the new object.

From a coder’s point of view, this example inventory uses three scripts: Inventory.js, LootableObject.js and LootTable.js.

Inventory.js is the main script controlling the system.

LootableObject.js makes any GameObject “lootable”.

LootTable.js assigns the loot to the lootable object.

(Each one of the scripts contained in the example project is well commented.)

To get this project to work “out of the box”, create an empty GameObject (in the example case this is called InventoryManger) and attach the two scripts Inventory.js andLootTable.js to it. These scripts will oversee the management of the Inventory and Loot. Attach the scriptLootableObject.js to any object you want to be lootable.

The looting system is started when the player clicks on a lootable object. First the lootable object checks withLootTable.js and receives a new array of loot content from the appropriate loot table.

After receiving new loot contents from the Loot Table, the lootable object passes a reference to itself and its contents to Inventory. Inventory will open a loot window and display the contents of this lootable object. If the new lootable object is not the same as the current lootable object in focus with Inventory (and the current lootable object is not null – which would be the case at the start of a game or session), Inventory sends back an updated array to the lootable object and changes focus to the new lootable object.

When the loot window is open and the player clicks on an item in the loot window, that item is transferred from the loot window to the inventory.

CHANGED: (The inventory system works primarily in OnGUI(). The designer is given variables to create an inventory display matrix.

    var inventorySizeX : int;
    var inventorySizeY : int;
    var iconWidthHeight : int;
    var spacing : int;
    var offSet : Vector2;

 

These variables are used to create a grid of square spaces for icon textures.

On Awake() a series of arrays is created and sized based on

inventorySizeX and inventorySizeY.

These arrays are displayed in OnGUI() if the inventory window is open. Using iconWidthHeight, spacing andoffSet, OnGUI() iterates through these arrays and draws either the item icon if the grid location is occupied, or draws a “blank” texture if it is not. If the icon is clicked, there is proto-code to either equip the item or destroy the item depending on which button the player uses.

The basic concept above is still in effect, but instead of using a matrix of arrays, or what is called a 2D array (this is a link to the definition of a 2D array), the system now uses a standard flat builtin array (a link to the definition of a builtin array) that is then divided into rows and columns using either simple division or the modulus based on the user’s choice of grid size).

This is the very basic over-view of the project. Each script has detailed comments explaining their use. If you have any additional questions you can see this thread on the Unity3D forums:

http://forum.unity3d.com/viewtopic.php?p=319613

There are some additional important notes regarding this sample project:

(Regarding iPhone Usage)

This package is not intended for the iPhone unmodified, as it used OnGUI, which will lead to a tremendously high amount of drawcalls.

Two of the most obvious solutions are to either use the underlying logic and convert the OnGUI() display technique to a sprite based UI system like SpriteUI or EZGUI, or to use OnGUI(), but make them “full screen” with the game paused in the background.

(Updated 10-06-15)

FIXED: (To maintain a consistency with the loot window which uses a GUI.Window, the inventory could be drawn in its own window. I have put unimplemented stubs in Inventory.js for this purpose.

FIXED: (The code for Equip Item does nothing.)

The code for Destroy Item is not trapped and destroys the item immediately with only a Debug.Log to tell you what’s been done.

Mouse-click (1) and (2) cause erratic behaviour in the Unity Web-Player, especially in Safari, where they bring up additional functionality either within the webplayer or the browser (http://forum.unity3d.com/viewtopic.php?t=38176).

FIXED: (You could lose an item if the inventory is full. This is noted in the script comments, but as this system moves the item from the lootable object to the Inventory it will be deleted from the lootable object, but bounce when it reaches the Inventory, effectively destroying it. This needs to be checked and trapped. (See the following comment…))

FIXED: (The system saves the changed contents of the lootable object back to that lootable object when the focus changes to a new lootable object. This is not the best approach and has the potential problem in a real world game of duplicating items if there were a crash or quit before the lootable object is updated after the game if the game was saved before updating the object. The lootable object should be updated with every transfer of an item from the loot window to the inventory window. (This is a simple fix, but should be performed with the fix for the comment above.))

Currently the system only has one sample loot table and the lootable object passes a dummy reference to itself as a placeholder. This could be modified to be a variable that could be passed to identify the type of lootable object that sent the request and allow LootTable.js to choose which loot table you are using, e.g.: passing “RottingZombie” could be used to find the Rotting Zombie specific loot table.

Currently the system does not take into account the possibility for a lootable object to be “empty”. The system will not return an array without content and there are no traps to deal with a lootable object with no content. Additional work would have to be done to allow “empty” lootable objects.

That being said, once a lootable object has been “emptied” and all of it’s contents have been moved to the inventory, if the player continues to click on the now “empty” lootable object, the system will continue to display an empty window. A simple trap of “isLootable” can be coded to become “false” if Inventory returns an empty contents array.

Currently all of the positions are not resolution independent, but are fixed based on the dimensions of the Apple iPhone. These can easily be changed.

For the purposes of a web player or stand-alone build, the escape key should be watched and used to close all of the open windows if pressed.

Updated 10-06-15

The package has been updated. It now includes code for equipping and un-equipping. Moving items is trapped and checked, so none should get lost or duplicated (even tho’ those situations would have been rare). The code checks for distance between the lootable object and the player, won’t open the loot panel if the player is too far away and closes it if the player leaves the area. The inventory can be resized, tho’ the code is only expecting the inventory to get BIGGER. If the inventory could be reduced in size, there is no code to deal with inventory items beyond the size of the new inventory size.

Unity iPhone 1.7:

I have tested this update on my iPhone and it works. There is a script attached to the main camera called OnTouchDown. You need to enable this script AND edit the script to un-quote the contents for the Lootable Objects to work on the iPhone. All the content is currently quoted out to allow compilation for non-iPhone Unity. You should also quote out/disable the function Update () in Inventory.js. My eyeball test said it was more performant than I was expecting, but I’d suggest that it was not performant enough for a real title, and a Sprite-based UI system should be used instead of OnGUI.

This is as far as I’m planning on taking this system at this time, if there are any specific questions or request, get a hold of me using one of the links below:

Please leave any comments and feedback for me at:

Little Angel on the Unity3D forum, or on the forums here on The Ant Ranch.

 

– Little Angel

3 Comments

Mike

about 1 year ago Reply

This is really nice, but ever since Unity 5, it always throws an error. Assets/Inventory/Scripts/Items/ItemEffect.js(44,28): BCE0019: 'RemoveItem' is not a member of 'Inventory'.

Mike

about 1 year ago Reply

Just wanted to note the error. //This takes care of deletion function DeleteUsedItem() { if (item.stack == 1) //Remove item { playersInv.RemoveItem(this.gameObject.transform); } else //Remove from stack { item.stack -= 1; } Debug.Log(item.name + " has been deleted on use"); } ******** Assets/Inventory/Scripts/Items/ItemEffect.js(44,24): BCE0019: 'RemoveItem' is not a member of 'Inventory'. Anyway to fix this? new to coding and love the script before the upgrade...

Adam

about 1 year ago Reply

This is a very old system and uses the immediate mode UI. I'd now do everything using the Unity Sprite UI. If you need pointers, pop up a post on the Unity forum and tag me ( @adam buckner ) and I'll try to give you a hand.

Leave a Comment

Please be polite. We appreciate that. Your email address will not be published and the required fields are marked.