Inventory, simple and easy

I have made an inventory. Simple. You see an object in the game, clicks on it, and then you get that object in your inventory.

This is my inventory:

//	Inventory.js
//	This script manages the inventory and displays the inventory items in a grid pattern
//	Attach to your Inventory Manager Object
//	Based on the code posted by Der Dude on the Unity3D forums: http://forum.unity3d.com/viewtopic.php?t=11865

static var statInventory : Inventory1;										//	To set an instance of this script
enum SlotType 	{Items, Weapons, Logs, Empty}

//	HELPER CLASSES
@System.Serializable														//	Our Representation of an InventoryItem
class InventoryItem 
{
	var itemName : String;													//	What the item will be called in the inventory
	var itemIcon : Texture;													//	What the item will look like in the inventory
	var itemDescription : String;											//	The description of the item
	var slotType : SlotType;												//	What slot the item will fit in
}


private var inventory : InventoryItem[];									//	Our master inventory (private)							
private var contentArray : InventoryItem[];									//	The array to contain the item being passed to and from the LootObject

var inventoryWidth : int;													//	the number of columns to display the inventory in
var inventoryLength : int;													//	the size of the inventory in total number of slots

var iconWidthHeight : int;													//	The pixel size (height and width) of an inventory slot
var spacing : int;															//	Space between slots (in x and y)
var offSet : Vector2;														//	The start position of the inventory

var emptySlot : Texture;													//	This will be drawn when a slot is empty

private var openInventoryWindow : boolean;									//	Controls OnGUI and opens/closes the inventory window
								
private var inventoryWindow : Rect;											//	The dimensions of the inventory window

private var currentLootableItem : LootObject;								//	The pointer to the current lootable item being processed
private var newLootableItem : LootObject;									//	The pointer to a new lootable item to be processed

function Awake () 
{																			//	Setup the initial states of the variables
	statInventory = this;
	
	inventoryWindow = new Rect (10, 10, Screen.width - 10, Screen.height - 10);

	openInventoryWindow = false;

	currentLootableItem = null;
	
	inventory = new Array (inventoryLength);								//   Create & init the array to hold the inventory 
	for (var i : int = 0; i < inventory.length; i++) 
	{ 
		inventory *= null;* 
  • }*
    }

function Update ()
*{ *

  • if (Input.GetKeyUp (KeyCode.I))*

  • { // If the “i” key is pressed…*

  •  openInventoryWindow = !openInventoryWindow;										//	... toggle the inventory window.*
    
  • }*
    }

function OnGUI ()
{

  • // Inventory Window*
  • if (openInventoryWindow) // If the “open inventory window” toggle is true*
  • { *
  •  GUI.Window (1, inventoryWindow, DrawInventoryWindow, "Inventory");	//   The title of this window could be passed as a String from the LootableItem*
    
  • }*
    }

function DrawInventoryWindow () // The window function to draw the inventory window
*{ *

  • if (GUI.Button (Rect (5,5,10,10), “”)) // Left upper corner quit button*

  • {*

  •  CloseInventoryWindow ();*
    
  • }*

  • var j : int;*

  • var k : int;*

  • var currentInventoryItem : InventoryItem; // Establish a variable to hold our data*

  • var currentRect : Rect;*

  • for (var i : int = 0; i < inventory.length; i ++) { // Go through each row …*

  •  j = i / inventoryWidth;												//   ... divide by array by width to get rows...*
    
  •  k = i % inventoryWidth;												//   ... find the remainder by width to get columns...*
    

_ currentInventoryItem = inventory*; // … set this point in the matrix as our current point …_
_ currentRect = (new Rect (offSet.x + k * (iconWidthHeight + spacing), offSet.y + j * (iconWidthHeight + spacing), iconWidthHeight, iconWidthHeight));_
_
if (currentInventoryItem == null) // … if there is no item in the j-th row and the k-th column, draw a blank texture*_
* { *
* GUI.DrawTexture (currentRect, emptySlot);*
* }*
* else*
* {*
* GUI.DrawTexture (currentRect, currentInventoryItem.itemIcon);*
* }*

* // If there is an item at this location and there is a button click…*
* if (currentInventoryItem != null && GUI.Button (currentRect, “”, GUIStyle (“label”)))*
* {*
* if (Input.GetMouseButtonUp (0)) // … if that click is mouse button 0: see the description*
* { *
* GUIContent (" " + currentInventoryItem.itemDescription); // Get the description out*
* }*

* }*
* }*
}

function CloseInventoryWindow ()
{
* openInventoryWindow = false;*
}

function AddItem (item : InventoryItem)
{
* for (var i : int = 0; i < inventory.length; i ++) // Go through each row*
* { *
_ if (inventory == null) // If the position is empty…
* {
inventory = item; // … add the new item…
return (true); // … and exit the function.
}
}
Debug.Log (“Inventory is full”);
return (false);
}*_

function ResizeInventory (newInventoryLength) // This code is never called at this point, but can be when you integrate it.
*{ *
* var oldInventory : InventoryItem[] = inventory;*

* inventory = new Array (newInventoryLength);*
* for (var i : int = 0; i < oldInventory.length; i++)*
* {*
inventory = oldInventory*;*
* }*

* for (var j : int = oldInventory.length; j < inventory.length; j++)*
* {*
_ inventory = null;
* }
}*_

This is my object that is loot able:
// LootableObject.js
// Make the GameObject “Lootable”.
// This script will
// Attach this script to any GameObject that is “Lootable”

#pragma strict

private var theInventoryItem : InventoryItem; // The current contents of this lootable object
private var thisLootableItem : LootObject; // A reference to this instance of this script
private var clicked : boolean; // Trap for creating the current contents only once
private var canLoot : boolean; // Boolean to control TestDistance.
private var playerTransform : Transform; // A reference to the Player Transform
private var thisTransform : Transform;

var itemName : String;
var itemIcon: Texture2D;
var itemDescription : String;

private var Inventory : Inventory1;

function Start ()
{ // Setup the initial states of the variables
* //itemName = the object name*
* itemName = this.gameObject.name;*
* //itemIcon will get selected in Unity*
* //itemDescription as well*

* var theInventoryItem : InventoryItem;*
* //Init thhe inventory item*
* theInventoryItem.itemName = itemName;*
* theInventoryItem.itemIcon = itemIcon;*
* theInventoryItem.itemDescription = itemDescription;*

* thisTransform = this.transform;*
* playerTransform = GameObject.FindWithTag(“Player”).transform;*
* thisLootableItem = this;*
* clicked = false;*

}

function OnMouseDown()
*{ *
* Loot (); *
*} *

function Loot ()
{
* if (!clicked)*
* { // If not yet clicked, check Loot Table*
* clicked = true;*
* }*

* //Add the item to the inventory*
* Inventory.AddItem(theInventoryItem);*
* theInventoryItem = null; //Set it to null*

* //Destroy the game object*
* Destroy(this.gameObject);*
}

I will summarise what i’ve found:

  • Your Inventory array is a native array, not the UnityScript “Array” class. To create a native array you have to do it like this: inventory = new InventoryItem[inventoryLength];
  • In LootableObject’s Start function you re-declare the “theInventoryItem” variable so it’s not saved along with the class since it’s now a local variable inside this function. Remove the var keyword, it should just be theInventoryItem = new InventoryItem();.
  • I don’t get what’s the use of thisLootableItem. What’s the point of a member variable to hold the own instance? Just use this where you need it.

Well, obviously it's because you haven't created an object there- you've only declared a variable. Declaring a variable creates an object-shaped 'slot' into which an object can fit- it doesn't automatically create the object to fit in it (unless it is a value type, which JS doesn't naturally support).

To fix this error, you need to change the line

var theInventoryItem : InventoryItem;

to

var theInventoryItem : InventoryItem = new InventoryItem();

then that part should work.

Doesn’t work. Now its got a problem with the array.

NullReferenceException: Object reference not set to an instance of an object UnityScript.Lang.Extensions.get_length (System.Array a) Inventory1.AddItem (.InventoryItem item) (at Assets/Scripts/Inventory/Inventory1.js:120) LootObject.Loot () (at Assets/Scripts/Inventory/LootObject.js:60) LootObject.OnMouseDown () (at Assets/Scripts/Inventory/LootObject.js:49) UnityEngine.SendMouseEvents:DoSendMouseEvents()

I looked it up. It is this part:

for (var i : int = 0; i < inventory.length; i ++) 					//	Go through each row
	{																	
		if (inventory *== null) 										//	If the position is empty..*
  •  {				*
    

_ inventory = item; // … add the new item…_
* return (true); // … and exit the function.*
* }*
* }*
Where the bold the line is where it goes wrong. It states that the inventory no object is. That’s weird because I made it with the awake call.
inventory = new Array (inventoryLength); // Create & init the array to hold the inventory
* for (var i : int = 0; i < inventory.length; i++)*
* {*
_ inventory = null;
* }*
What the hell is going wrong?_

The first thing I notice is that in the start method, 2 lines above the line giving you the error, you are re-declaring the variable theInventoryItem, and it is not getting assigned a value. This is the cause of the error. You have this variable already declared as private at the top of your script.

Removing the 2nd declaration would be the first step I would recommend. Leaving the 1st one will leave the variable available to the remaining methods in the script.

However, you are still going to get this error, as the variable is still not being assigned anything as far as I can see.

I am a c# coder, not Javascript, so I may be all wet here, but you need to use new to create a new instance of your InventoryItem object. Something like…

theInventoryItem = new InventoryItem;

Hope this is of some help.
-Larry

Thanks for the comment.

I have an Inventory and an Lootable Object script. The Inventory script is attached to an empty game object and with the button I you can get the Inventory open.
The LootableObject is a script to attach to the object that can get picked up.
When I click, the Loot() function will get called, and the item is supposed to be added to the inventory (so in the inventory script) and then destroyed in the game world. It goes wrong on the point when I want to add the Item to the Inventory.