73738847473883949 Annoying questions

Hey guys, sorry to be annoying, I am at best a novice programmer, and I need lots of help, I would like to start by asking this question.

If i create a new array in c#

ArrayList cars = new ArrayList();

then I add a list of gameobjects to it,
cars = GameObject.FindGameObjectsWithTag(“Car”);
for (int i = 0; i < Car.Length; i++)
{

}

This of course populates the array with all game objects with the “Car” tag in my scene, My problem is, I don’t know how to access it, I mean I know i can do a cars[0] and cars[1] and so on to individually get these values, but if I have 40 cars, I don’t want to try to put the name of the object into 40 separate string variables, so anyone know how to do this dynamically ? I want to get a list of all objects, then for each object I want to get a list of components, like name, mesh,collider.ridgidbody etc, and then I need to be able to access these values, At the moment, I am just trying to display the contents of a string array i created with 3 values, but I can only get it to display the first one unless i name each entry by 0 or 1 etc someone please feel pity on the crappy coder here and give me some advice :shock:

Cars
Sorry for short answer, on mobile phone

OK, first thing, your labeling an ArrayList as “cars” then turning around and getting a GameObject[ ] as “cars”. You can’t do that, each variable needs to have a unique name.

And the proper way to use the ArrayList is… ArrayList.Add()

ArrayList cars = new ArrayList();

//then I add a list of gameobjects to it,
carobjs = GameObject.FindGameObjectsWithTag("Car");
for (int i = 0; i < carobjs.Length; i++){
	cars.Add(carobjs[i]);
}

FindGameObjectsWithTag already returns an array of GameObjects, so you don’t need to make an array beforehand (and certainly not ArrayList, which is slow and untyped).

var cars = GameObject.FindGameObjectsWithTag("Car");

is sufficient. So to access the name for each one, you’d do:

for (int i = 0; i < cars.Length; i++)
{
    print (cars[i].name);
}

To access the mesh, you’d do

cars[i].GetComponent<MeshFilter>().mesh;

–Eric

Another suggestion:

List<GameObject> cars = new List<GameObject>(GameObject.FindGameObjectsWithTag("Car"));
for(int i = 0; i < cars.Count; i++)
{
Debug.Log(cars[i].name);
Debug.Log(cars[i].GetComponent<Transform>());
}

The triangle brackets <> on some classes allow you to make a List of a specific type, like in the first line where it is a List of GameObjects.
Then when you go through your loop, you can use the i from the for loop to get each individual GameObject. The ArrayList works the same, but you need to specify in the code that each entry is a GameObject when you get it (like this: ((GameObject)cars*).name ) which is slower and harder to read.*
ArrayList, is a List of all sorts of objects, whereas List<> is a list of specific objects specified by whatever is in the <>.
The Debug Logs show that you can access the individual parts of the GameObjects.

Thankyou, I understand it now, so now for question 2 of 73738847473883949.

I am trying to take the output of the foreach loop and create a button from each listing, I have that part working,

cars = GameObject.FindGameObjectsWithTag(“Car”);
foreach (GameObject g in cars)
{
if(GUILayout.Button(g.name))
{

print(g.name);

}

This works, It places the buttons in the window i have set aside for them, it lists them all by name, works just like i want it too, however when i click on the button it performs the task for every button, on top of trying to do it all inside the same gui.window

Ideally, I want this info window to appear on level, its static and will always have something populating it. This part works fine

But when I click on one of the buttons inside the list is where i hit the problem, I want it to open another window with information about just that one button clicked, the problems i run into now is, I cant get a second separate window up, even though i make a new one, it wants to put all of the info in the first window, and wont show the second window at all, this is the entire code.

public GameObject[ ] planets;
public int totalPlanets;
public int totalPlanetNames;
ArrayList planetNames = new ArrayList();
private Rect m_SelectionWindowRect = new Rect(10.0f, 10.0f, 300.0f, 100.0f);
private Rect m_PlanetInfoBox = new Rect(10.0f, 10.0f, 300.0f, 100.0f);
private bool showPlanetWindow = false;

void Start()
{

}

public void OnGUI()
{
// if (SelectionManager.IsSelected(gameObject))
//{
m_SelectionWindowRect = GUI.Window(GetInstanceID(), m_SelectionWindowRect, SelectionWindow, “Planets”);

//}
}

void SelectionWindow(int id)
{

planets = GameObject.FindGameObjectsWithTag(“Planet”);
foreach (GameObject g in planets)
{
if(GUILayout.Button(g.name))
{

print(g.name);
// Do I need to push these to an array ?
}

}

// GUILayout.Box("I am the selection and my name is " + gameObject.name);
GUI.DragWindow();

}
PlanetInfoBox is the second window, its set as the same rect as the first for now, but i was dragging the window out of the way to try, I also tried it in a completly different position, same effect.

first of all, if your in C# avoid use of ArrayList. instead put this at the top of your .cs file:

using System.Collections.Generic;

Then instead of ArrayList use List or even better HashSet. The reason these are better is because ArrayList stores things as object type which makes your code slower because everytime you need to get something out of it, it needs to type check and cast. ArrayList is good if you want a list of things that arent the same type however. But the reason i suggest HashSet is because its better/faster with checking if theres a item in the array.

But even better than these 2 things is if you use a native array ( GameObject[ ] ) which is what the FIndGameObjectsWithTag returns.

For the second question you could use a Dictionary<GameObject, Rect> for your windows. the code for this would look like

    Dictionary<GameObject, Rect> windows = new Dictionary<GameObject, Rect>(); 
    
    void OnGUI() {

        foreach( var go in GameObject.FindGameObjectsWithTag("Planets") ){
            if( GUILayout.Button(go.name) ){ 
                // check if it has a window.
                if( windows.ContainsKey(go) ){
                    // it does so remove the window.
                    windows.Remove( go );
                }else{
                    // it does not so create the window.
                    windows.Add( go, m_SelectionWindowRect );// make it at the m_SelectionWindowRect
                }
            }
        }

        // now do all windows.
        foreach( var keyValuePair in windows ) {
            var rect = GUI.Window( keyValuePair.Key.GetInstanceID(), keyValuePair.Value, SelectionWindow );
            if ( rect != keyValuePair.Value ) { // the window was moved or resized 
                windows[keyValuePair.Key] = rect;// set the new rect.
            }
        }
    }
}

Just a note, don’t use “GameObject.FindGameObjectsWithTag(“Planets”)” in your OnGUI! Please, cache it!

Dictionary<GameObject, Rect> windows = new Dictionary<GameObject, Rect>();
This is a awsome function, thankyou so much for showing it to me, trying to tear it apart so that I understand it better now, and I have run into a question or 5 billion,.

Please keep in mind I am a novice, So I know this probably sounds dumb, This function Works very well, However it just creates the buttons one of top of each other in the area I choose for my window to be, but there is no window, so i am unable to drag or re-size them, as they are not inside a window.

Also when the buttons are clicked, it opens a new window in the same spot of the first window, I don’t comprehend GUI to well, It seems to me, that if you create a gui function, you should be able to create and change, or destroy windows on the fly, but it seems every time I attempt to create more than 1 GUI.Window in a scene, It either completely erases the contents of the first window, or tries to jam the contents of the second window, inside the first. If i try to GUILayout End area, or end horizontal or vertical it erases the first window, so I don’t get it, I wish I could find a In depth GUI tutorial, as once i can understand a function, then its all good, but there is so much info on the net, and so many ways to do the same thing, and the wiki gives as little info as possible to still be called a wiki, not even any c# examples.

I apologize for asking so many Noob questions, I suffer from PTSD, so REALLY need Unity as a way to keep my mind occupied, I just need to understand these functions, spending 8 hours trying to get a script to print out Object Names, is really frustrating lol, So if there is anyone out there, who wouldn’t mind being annoyed, please let me know, I could write pages of questions, also if anyone knows of some clear cut, well explained tutorials, Videos would be best, as I think I have read about 5 billion pages on Unity functions, my eyes hurt, I would be very grateful,.

"Just a note, don’t use “GameObject.FindGameObjectsWithTag(“Planets”)” in your OnGUI! Please, cache it! "

I assume you mean run the FindGame tag somewhere else, if so, I am too much of a noob to get it to work anywhere else but inside OnGui, otherwise I cant get any of the return vales, In other words, I have yet to figure out how to pass the return value of FindGameTag to any other function, besides where I declare it, I mean I can pass it once, but dont know how to send the entire contents to another function yet, so I guess I am stuck using more memory than i should until i understand it all better.

Thankyou all for the help, This script is now working more or less, the way I want it too.

private Rect m_SelectionWindowRect = new Rect(10.0f, 10.0f, 300.0f, 100.0f);
private Rect m_PlanetInfoBox = new Rect(100.0f, 10.0f, 350.0f, 150.0f);
private Rect rect;
private GameObject selection;
Dictionary<GameObject, Rect> windows = new Dictionary<GameObject, Rect>();
private bool showWindow = true;

void Start()
{

}

void OnGUI()
{
foreach (var go in GameObject.FindGameObjectsWithTag(“Planet”))
{
if (GUILayout.Button(go.name))
{
if (!showWindow)
showWindow = true;
selection = GameObject.Find(go.name);
windows.Add( go, m_SelectionWindowRect );// make it at the m_SelectionWindowRect

}

}
// now do all windows.
foreach (var keyValuePair in windows)
{
if(showWindow)
rect = GUILayout.Window(keyValuePair.Key.GetInstanceID(), m_PlanetInfoBox, SelectionWindow, selection.name);

}

}
void SelectionWindow(int id)
{

GUILayout.Label("Planet: " + selection.name);
GUILayout.Label(selection.name + "'s mass is: " + selection.rigidbody.mass);
GUILayout.Label(selection.name + "'s Location is: " + selection.transform.localPosition.x + “,” + selection.transform.localPosition.y + “,” + selection.transform.localPosition.z + “.”);
if (GUILayout.Button(“Close”))
{
showWindow = false;
}
GUI.DragWindow();

}

void PlanetWindow(int id)
{

}

private GameObject[ ] planets;

void Start()
{
planets=GameObject.FindGameObjectsWithTag(“Planet”);
}

then just do:

foreach(var go in planets)

That way, you only find all of the objects once.

Oh, that’s how you do it, thank-you very much