Laying out Icons In an inventory, that will rearrange to fit

Hi guys,

Wow, Im really enjoying using the new gui system. It kinda makes my head spin, and understanding the details is slowly making sense, but I’ve reached a point where it might be wise to ask for a quick bit of advice.

So Ive got a GuiBox that mostly fills the screen, and in that are small 128x128 icons, and Im trying to get them to layout nicely. Whats the best method? Currently they stack vertically rather than next to each other and into a second row. I figured the easiest way is to have greyed out textures at first, then change them based on game events, rather than try an insert new textures where there was nothing origionally.Anyways, if anyone with a flair for UnityGui feels like checking this out and advising on how to get it to layout nicer, that would be great. Thank you

AaronC

var Toy1Textures:String;
var Toy_01_00 : Texture2D;
var Toy_01_01 : Texture2D;
var Toy_01_02 : Texture2D;
var Toy_01_03 : Texture2D;
var Toy2Textures:String;

var Toy_02_00 : Texture2D;
var Toy3Textures:String;
var Toy_03_00 : Texture2D;
var Toy4Textures:String;
var Toy_04_00 : Texture2D;
var Toy5Textures:String;
var Toy_05_00 : Texture2D;
var Toy6Textures:String;
var Toy_06_00 : Texture2D;
var Toy7Textures:String;
var Toy_07_00 : Texture2D;
var Toy8Textures:String;
var Toy_08_00 : Texture2D;
var Toy9Textures:String;
var Toy_09_00 : Texture2D;

private var embedded_Icon_Toy_01 = Toy_01_00;
private var embedded_Icon_Toy_02 = Toy_02_00;
private var embedded_Icon_Toy_03 = Toy_03_00;
private var embedded_Icon_Toy_04 = Toy_04_00;
private var embedded_Icon_Toy_05 = Toy_05_00;
private var embedded_Icon_Toy_06 = Toy_06_00;
private var embedded_Icon_Toy_07 = Toy_07_00;
private var embedded_Icon_Toy_08 = Toy_08_00;
private var embedded_Icon_Toy_09 = Toy_09_00;

var showGUI = false;
private var Toy_01=0;


function Awake(){
 embedded_Icon_Toy_01 = Toy_01_00;
 embedded_Icon_Toy_02 = Toy_02_00;
 embedded_Icon_Toy_03 = Toy_03_00;
 embedded_Icon_Toy_04 = Toy_04_00;
 embedded_Icon_Toy_05 = Toy_05_00;
 embedded_Icon_Toy_06 = Toy_06_00;
 embedded_Icon_Toy_07 = Toy_07_00;
 embedded_Icon_Toy_08 = Toy_08_00;
 embedded_Icon_Toy_09 = Toy_09_00;
}


function Update() {
	if(Input.GetKeyDown("i")){
		Debug.Log("Opening Inventory");
showGUI=true;
	}
}









function OnGUI() {
if (showGUI==true) {

	GUI.Box (new Rect (10,10,Screen.width-20, Screen.height-20), "Inventory");
		if(GUI.Button (Rect (Screen.width - 130,10,120,20), "Next Page"))
		{
		print("Page2CodeHere");
			showGUI=false;
		}
	
		if (GUI.Button(Rect(10,10, 128, 20),"Close Window"))
	 		showGUI=false;
  
	 GUILayout.BeginArea (Rect (10,30,Screen.width-20, Screen.height-40));
	 GUI.BeginGroup (new Rect (0,0,Screen.width-20, Screen.height-20));
	
	GUILayout.Box (embedded_Icon_Toy_01);
	GUILayout.Box (embedded_Icon_Toy_02);
	GUILayout.Box (embedded_Icon_Toy_03);
	GUILayout.Box (embedded_Icon_Toy_04);
	GUILayout.Box (embedded_Icon_Toy_05);
	GUILayout.Box (embedded_Icon_Toy_06);
	GUILayout.Box (embedded_Icon_Toy_07);
	GUILayout.Box (embedded_Icon_Toy_08);
	GUILayout.Box (embedded_Icon_Toy_09);
		//	its those bits above that I need to layout better

	GUI.EndGroup ();
  GUILayout.EndArea ();
 	
}
   
}

(WIP)

How about creating a 2 dimensional Texture array. Each position in the array will represent one slot in your inventory.
If a texture is null, display a default icon.

Of course instead of using a Texture array, it would be better for later use, if you built your own struct, which keeps reference to the actual Object the Texture represents.

Then run through the array like so:

Texture[][] inventory
int iconWidthHeight = 20;

// Create the an 8x8 Texture-Array
public void Awake()
{
    inventory = new Texture[8][];
    for( int i = 0; i < inventory.Length; i ++ )
    {
        inventory[i] = new Texture[8];
    }
}

public void OnGUI()
{
    //Go through each row
    for( int i = 0; i < inventory.Length; i ++ )
    {
        // and each column
        for( int k = 0; k < inventory[i].Length; k ++ )
        {
            //if there is a texture in the i-th row and the k-th column, draw it
            if( inventory[i][k] )
            {
                GUI.DrawTexture( new Rect( k*iconWidthHeight, i*iconWidthHeight, iconWidthHeight, iconWidthHeight ), inventory[i][k] );
            }
        }
    }
}

[/code]

Hey,

Any chance you could make that into a script? Nothing I do makes that snippet compile. I know theres some obvious stuff missing but even adding that doesnt help.

Thanks
AaronC

I did forget a semicolon.

The bigger problem however was, that I failed to mention I wrote that snippet in C# and from the looks of this post you use JavaScript.

So I attatched both versions to this Reply.

78851–3031–$inventory_996.cs (1 KB)
78851–3032–$inventoryjs_196.js (895 Bytes)

Thanks. Its really good having real world examples. Thats pretty fancy but too slick this time round. I need to assign to different icons and your solution, though elegant, restricts me to one. So its not about procedurally laying it out but by having say 30 different icons and getting the preassigned icons to sit nice. Like my script doesnt.

Your solution would be really good for multiples of the same item though. Ive decided to go for a “find screensize divide screen up scale each icon relative to the overall screensize” approach. I can do simple math…most of the time.

Cheers-Much appreciated.
AC

It doesn’t actually restrict you at all. Each slot in the inventory array can hold a different Texture. All you need to do iss assign them. The default texture is only used, when there is none in the appropriate slot (empty).

To prove my point, I extended the above script. It now has Functions called AddItem, which search for a free spot in the inventory.
When you click mouse button 0 or 1, an item is added to the inventory with textures you assign.

Also the Array doesn’t consist of Textures anymore, but of instances of a class called InventoryItem. This class can hold any data necessary. Now it only holds a texture and a GameObject.

Guess I have too much time on my hands… :wink:

//Our inventory
var inventory : Array;

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

//the size of the inventory in x and y dimension
public var inventorySizeX = 8;
public var inventorySizeY = 5;

//The pixel size (height and width) of an inventory slot
var iconWidthHeight = 20; 

//Space between slots (in x and y)
var spacing = 4;

//set the position of the inventory
public var offSet = Vector2( 100, 100 );

// TEST VARIABLES
// Assign these to test adding Items with mouse clicks (see Update())
public var testTex : Texture;
public var testTex2 : Texture;

//Our Representation of an InventoryItem
class InventoryItem
{
	//GameObject this item refers to
	var worldObject : GameObject;
	//What the item will look like in the inventory
	var texRepresentation : Texture;
}

// Create the Inventory 
function Awake() 
{ 
	inventory = new Array(inventorySizeX);
	
    for( var i = 0; i < inventory.length; i ++ ) 
    { 
        inventory[i] = new Array(inventorySizeY);
    } 
} 

function OnGUI() 
{ 
	var texToUse : Texture;
	var currentInventoryItem : InventoryItem;
	
    //Go through each row 
    for( var i = 0; i < inventory.length; i ++ ) 
    { 
        // and each column 
        for( var k = 0; k < inventory[i].length; k ++ ) 
        { 
        	texToUse = emptyTex;
        	currentInventoryItem = inventory[i][k];
        	
            //if there is an item in the i-th row and the k-th column, draw it 
            if( inventory[i][k] != null ) 
            { 
                texToUse = currentInventoryItem.texRepresentation;
            } 
            
            GUI.DrawTexture( new Rect( offSet.x+k*(iconWidthHeight+spacing), offSet.y+i*(iconWidthHeight+spacing), iconWidthHeight, iconWidthHeight ), texToUse );
        } 
    } 
} 

function AddItem( item : InventoryItem )
{
	 //Go through each row 
    for( var i = 0; i < inventory.length; i ++ ) 
    { 
        // and each column 
        for( var k = 0; k < inventory[i].length; k ++ ) 
        { 
        	//If the position is empty, add the new item and exit the function
        	if( inventory[i][k] == null ) 
            {
            	 inventory[i][k] = item;
            	 return;
            }
        }
    }	
    
    //If we got this far, the inventory is full, do somethign appropriate here	
}

function AddItem( worldObject : GameObject, texRep : Texture )
{
	var newItem = new InventoryItem();
	
	newItem.worldObject = worldObject;
	newItem.texRepresentation = texRep;
		
	AddItem( newItem );	
}

function Update()
{
	if( Input.GetMouseButtonDown( 0 ) ) 
	{
		AddItem( gameObject, testTex );	
	}
	
	if( Input.GetMouseButtonDown( 1 ) ) 
	{
		AddItem( gameObject, testTex2 );	
	}	
}

78860–3033–$inventoryjs_907.js (2.64 KB)

Hey thats great, thanks! lots of cool little treats in there!
AC

No problemo.

More advanced functionality like actually using the items is missing of course. You could start by making the items draw as buttons and checking if they’re being clicked.

Just post if I can help some more.

Hey I’ve had Unity for about 3 months now and I’m no programmer. I’ve searched everywhere trying to figure out how to use the items once they’re in the inventory. I used the script from Der Dude 3 posts above this one and mostly I would like to at least be able to remove the texture once it’s there. How would I be able to know the location of the item in the array to remove it? Or how would I go about solving this? Thanks in advance!

First thing you could do is to not draw Textures, but Buttons.

So the line

GUI.DrawTexture( new Rect( offSet.x+k*(iconWidthHeight+spacing), offSet.y+i*(iconWidthHeight+spacing), iconWidthHeight, iconWidthHeight ), texToUse );

could be something like:

if(GUI.Button(new Rect(...), textToUse))
{
    // Do Inventory Item Action here

    //Remove it
    currentInventoryItem = null;
}

To actually create different kinds of Iventory Items you extend the InventoryItem class.

class MySwordItem : IventoryItem
{
    protected int damage;
    protected int durability;
    protected int weight;

    // This could be executed when clicked in the GUI
    void OnClick()
    {
        // Equip this sword
    }
}

You can check the type of an object like this:

if( myObject.GetType() == typeof(MySwordItem))
{
    //Do specific SwordItem action
}

EDIT: Note these are C# snippets.

Thanks for the quick reply! I got the buttons to work and I can remove things now, but I tried for a couple of hours to get the check the type of object and I’m having trouble adding something from a different class. I attempted to copy the function AddItem in the script and to modify it so that it would add the different class if some variable was true. Is there an easy fix for this? Thanks again!!

Okay I’ve been in and out of this topic for a few days now I cant seem to get a hold on this I try to simplify your code down to my level but I keep having trouble with the InventoryItem class I’ve made my own but it doesn’t use an array and I don’t know how to code it so that it’ll pick up an item display the info when you click on it and know when a slot is open and can be used…
please help I’ve been wandering around trying to stumble on a hacked solution without success and I cant find much help anywhere else :?
any help would be Greatly appreciated!

EDIT: Figured it out. But I get a NullReferenceException: Object reference not set to an instance of an object
when I call the AddItem function on another script when I’m looking for an empty slot… the GameObject and Texture variables are used… so I cant pinpoint it :?

Alright I fixed it I’ll leave the forum alone for awhile :stuck_out_tongue:

Upon request I’ve whipped up a little example project where you can add, remove and equip items from the inventory.
Note this is very generic but it should point you in the right direction, if you are having trouble extending the above scripts.

It includes a test scene. A click on the world-objects adds them to the inventory. A right click on an inventory-Item removes it (item in world, not in inventory), a left click equips it (item in world and in inventory.

212579–7817–$inventory_136.zip (1.22 MB)

Thanks, very nice you share this, i was just about to get an idea of implementing a inventory and your project looks quiet good.

I had to upgrade and the only flaw i found, it’s not removeing the image of the dropped item.
It works if i use “mouse 1” tough.

Really cool script.

(@DerDude?)

I was looking at your code and it certainly works, but I had a question about the nested arrays:

Your code has this:

var inventory : Array;

function Awake () {
	 inventory = new Array (inventorySizeX);

	for (var i : int = 0; i < inventory.length; i ++) {
		inventory[i] = new Array (inventorySizeY);
	}
}

And later your code accesses these nested arrays

function OnGUI () {
	var currentInventoryItem : InventoryItem;

	//Go through each row
	for (var i : int = 0; i < inventory.length; i ++) {
		// and each column
		for (var k : int = 0; k < inventory[i].length; k ++) {
			currentInventoryItem = inventory[i][k];

//	More Code...
}

So, I assume that the nested arrays are protected in some way that there is no confusion with the duplicated variable name. Obviously it works, and inventory[ i ][ k ]; is certainly neat. I just wouldn’t have guessed you could do that and would have used inventoryX and inventoryY (for example).

What am I asking…

I guess it’s “Why does this work?”

Why is there no confusion about the duplicated variables? How can you distill this down to inventory [ i ][ k ]?

As I’m writing this I think it’s becoming more clear…

Because the first variable is “inventory”, and then the next variable is not “inventory” [ i ], but it is in fact “inventory [ i ]”?

If so, then is it Unity.js and it’s dynamic typing that is allowing the statement:

inventory[i] = new Array (inventorySizeY);

… rather than something like:

var inventory[i] : Array = new Array (inventorySizeY);

??

What… The… Hell, Your logic is broken…
xD

Hey - I’m not a coder.

Just trying to make sense of something I don’t understand.

If I have it wrong, can you explain it?

I have taken the code here and updated it to make a more “WoW-like” Inventory and Loot system.

I have posted more details, including links to the code, here:
http://forum.unity3d.com/viewtopic.php?p=319613


(Some Textures and Icons in this project are not licensed for distribution and are for testing purposes only)

Please note that even tho’ this is pictured within an Apple iPhone, this code is platform independent and has NOT been optimized for an Apple Touch Device and is standard Unity code for any project.