C# Directly Accessing Lists in GUI

This is a two part question:

  1. Is there a way to make a list that each item in the list is linked to an object or prefab in unity, if so any links to a place I can learn?

  2. Is it possible in the GUI to have a piece of text within a list able to be clicked in turn selecting it? Again with this question if any resources are available I’d love a link. When I mean clickable I do not mean using a GUI button/grid/toolbar. I mean like a display of said list in the first question all being able to be clicked on and selected.

I know I said two part, but I cannot resist asking whether or not there is a guide or tutorial on Inventory setup somewhere on the internet.

Just create a List of GameObjects (or whatever class your data is in (such as a ScriptableObject-derived class)), then loop through the list, and draw the controls for each one. I’ll write a quick example for you:

using UnityEngine;
using System.Collections.Generic;

public class GameObjectManager : MonoBehaviour
{
   public List<GameObject> gameObjects;
   public int selectedIndex = -1;

   void Start()
   {
      if (gameObjects == null)
         gameObjects = new List<GameObject>();
   }

   void OnGUI()
   {
      for (int i = 0; i < gameObjects.Count; i++)
      {
         if (GUILayout.Toggle(selectedIndex == i, gameObjects[i].name, "Button"))
            selectedIndex = i;
      }
   }
}

This will create a List of GameObjects that can be selected. (Only one can be selected at a time.)

For an inventory system I would recommend making ScriptableObject-derived classes to represent Inventory Items, then make your List, and add code for handling the selected item (equipping it, applying it’s effects, etc.). If this is beyond your depth, there are numerous tutorials you can use to get to this point, but I recommend starting with simple tutorials and working your way up.

Try the Teaching Section to find tutorials (or lists of tutorials, such as this).

My question is how you got List? I saw on Unity Reference that lists were only available in Unityscript and ArrayLists had to be used instead. I say this also considering I am getting an error now based on the list that was created following your example. Just curious, Thanks for the info though! :slight_smile:

Alright I got a lot of what i wanted to work. The only thing I need now is how to determine whether or not the object within the list has a specific tag. I only want this function to work on items with a specific tag because it wouldn’t make much sense otherwise.

List is a part of System.Collections.Generic. Also, sorry if it has some errors. I wrote it directly in here, and didn’t test it, as it is a very simple script.

As for tags, use:

if (gameObjects[i].tag == "MyTag")
{
   // Do something...
}

Yeah I realized the System.Collections.Generic thing shortly after posting that. Yeah that tag code you suggested worked perfectly! The reason this is a huge challenge for me is that i am working on a crafting system with hardly any experience in game design (I have what I would call a little bit above basic understanding of C#). This is pretty much a system where you can select a weapon or piece of armor, break it down and receive the components that it is composed of while adding the parts to a list where you can combine multiple different blades with hilts/grips/handles etc. Essentially making crafting a very unique experience.

Sounds like a cool system. Good luck!

Thanks! I’m gettin a little further all the time, I have it to where when you select a weapon in inventory, it instantiates that weapon on screen in a space designated for it, that item is essentially targeted, and when you break it down, it cycles through the target to the children objects that contain other parts and adds the proper tagged item to it’s proper list. First I just found gameObject with tag, which was a really dumb and not proper way to do lol.

Hey I know technically my question was solved, but I am having an issue currently. Unity won’t allow me to Destroy a GameObject? I’ve never experienced this. But I can show an example of where it’s first given a value and where it’s destroyed.

Value Declaration:

		Inventory inventory = GetComponent<Inventory>();
		for(int i = 0; i < inventory.inventoryList.Count; i++)
		{
			target = inventory.inventoryList[i];
		}

Destruction (Big line of code, probably needs a lot of optimization, but it’s a rough draft :/) :

			if(GUI.Button(new Rect((Screen.width / 1.6f) + 170, Screen.height - 60, 150, 40), "Break Down"))
			{
				if(inventory.inventoryList[i].tag == "Weapon")
				{
					//Crafting List Addition
					blades.Add (inventory.inventoryList[i].transform.FindChild("Blade").gameObject);
					hilts.Add (inventory.inventoryList[i].transform.FindChild("Hilt/Hilt").gameObject);
					handles.Add (inventory.inventoryList[i].transform.FindChild("Hilt/Handle/Handle").gameObject);
					grips.Add (inventory.inventoryList[i].transform.FindChild("Hilt/Handle/Grip/Grip").gameObject);
					
					//Inventory Adjustment
					inventory.inventoryList.Add (inventory.inventoryList[i].transform.FindChild("Blade").gameObject);
					inventory.inventoryList.Add (inventory.inventoryList[i].transform.FindChild("Hilt/Hilt").gameObject);
					inventory.inventoryList.Add (inventory.inventoryList[i].transform.FindChild("Hilt/Handle/Handle").gameObject);
					inventory.inventoryList.Add (inventory.inventoryList[i].transform.FindChild("Hilt/Handle/Grip/Grip").gameObject);
					
					inventory.inventoryList.RemoveAt (i);
					
					Destroy (target);
				}

In the for loop you assigned the target repeatedly. I can’t see why. Also, because your second chunk of code uses ‘i’ I have to assume it is inside a for loop somewhere. You cannot remove items from a list you are iterating through. This will cause the length of the list to change, which can break the for loop unless you adjust the counter (i) when an item is removed. What you should do is keep a reference to the selected control outside of any loops, and do the break down check there.

using UnityEngine;
using System.Collections.Generic;

public class GameObjectManager : MonoBehaviour
{
   public List<GameObject> gameObjects;
   public GameObject target;

   void Start()
   {
      if (gameObjects == null)
         gameObjects = new List<GameObject>();
   }

   void OnGUI()
   {
      // Keep this area simple and clean. We only use the loop to display buttons we can use to select game objects.
      for (int i = 0; i < gameObjects.Count; i++)
      {
         if (GUILayout.Toggle(target == gameObjects[i], gameObjects[i].name, "Button"))
            target = gameObjects[i];
      }

      // By splitting this away from any loop, and using a reference to the selected target,
      // we can keep things simple, without worrying about whether we will get an index error.
      if (GUI.Button(new Rect(...), "Break Down"))
      {
         // ... Add parts to lists
         GameObject clone = (GameObject)Instantiate(target.Find("Blade").gameObject);
         clone.name = "Blade"; // Otherwise, it would be called "Blade(Clone)"
         partsList.Add(clone);

         gameObjects.Remove(target);
         Destroy(target);
      }
   }
}

That should do it.

EDIT: Forgot a step. Updated the code. You’ll notice that I duplicate the part that I am adding to the partsList (using Instantiate). That’s because, when you Destroy a GameObject, any reference to it or the GameObjects it contains will be lost, because those contained GameObjects are also Destroyed. By cloning them, you get an exact copy that won’t be lost when the original is destroyed.

Very helpful! The reason I used a for loop and inventory.selectedindex in the Break Down Method is because when trying to use target.Find it does not show up for some reason, could it be because I have it set for private or something? I’m trying to keep as many things private as possible in this script. Yeah I think the main problem I have is not keeping things very neat, I try to keep some organization but I probably end up using a lot of useless code. I mean there was a lot more to that script than I had shown you lol.

using UnityEngine;
using System.Collections.Generic;

public class GameObjectManager : MonoBehaviour
{
public List gameObjects;
public GameObject target;

void Start()
{
if (gameObjects == null)
gameObjects = new List();
}

void OnGUI()
{
// Keep this area simple and clean. We only use the loop to display buttons we can use to select game objects.
for (int i = 0; i < gameObjects.Count; i++)
{
if (GUILayout.Toggle(target == gameObjects_, gameObjects*.name, “Button”))_
_target = gameObjects;
}*_

// By splitting this away from any loop, and using a reference to the selected target,
// we can keep things simple, without worrying about whether we will get an index error.
if (GUI.Button(new Rect(…), “Break Down”))
{
// … Add parts to lists
partsList.Add(target.Find(“Part/SubPart/SubSubPart”).gameObject);

gameObjects.Remove(target);
Destroy(target);
}
}
}

Both of these issues could be solved easily using eDriven. Look at the drag drop demo here. You could supply your own GUI elements (inventory images). Each GUI element can hold the proprietary Data - using it you could link to your prefabs or game objects.

For selectable lists, you could use the list component:

1154291--43974--$list.png