Automatically populate Array in a specific order

I’m experimenting on a scene, I have a bunch of gameobjects which are children of another GameObject. All of these gameobjects have a specific name, testObj00, testObj01, testObj02 etc. I need to populate an array with these objects in a specific order, so that array[0]=testObj00, array[1]=testObj01 etc.

Inside my script what I eventually want to do, is keep all objects invisible except for ONE every frame. That is, testObj01 is visible on frame 1, testObj02 is visible on frame 2 etc…

Right now I’m doing it completely manually, it seems too straightforward, I bet there is a way better and more efficient way to code it.

Here’s what I’ve done at this point for 10 gameobjects:

using UnityEngine;
using System.Collections;

public class animatingScript : MonoBehaviour {

	public GameObject bM01;
	public GameObject bM02;
	public GameObject bM03;
	public GameObject bM04;
	public GameObject bM05;
	public GameObject bM06;
	public GameObject bM07;
	public GameObject bM08;
	public GameObject bM09;
	public GameObject bM10;

	int arrayIndex;

	public MeshRenderer[] mesherAr;

	// Use this for initialization
	void Start () {
	
		arrayIndex = 0;

		MeshRenderer bM01Renderer = bM01.GetComponent<MeshRenderer> ();
		MeshRenderer bM02Renderer = bM02.GetComponent<MeshRenderer> ();
		MeshRenderer bM03Renderer = bM03.GetComponent<MeshRenderer> ();
		MeshRenderer bM04Renderer = bM04.GetComponent<MeshRenderer> ();
		MeshRenderer bM05Renderer = bM05.GetComponent<MeshRenderer> ();
		MeshRenderer bM06Renderer = bM06.GetComponent<MeshRenderer> ();
		MeshRenderer bM07Renderer = bM07.GetComponent<MeshRenderer> ();
		MeshRenderer bM08Renderer = bM08.GetComponent<MeshRenderer> ();
		MeshRenderer bM09Renderer = bM09.GetComponent<MeshRenderer> ();
		MeshRenderer bM10Renderer = bM10.GetComponent<MeshRenderer> ();


		mesherAr = new MeshRenderer[10] {bM01Renderer, bM02Renderer, bM03Renderer, bM04Renderer, bM05Renderer, bM06Renderer, bM07Renderer, bM08Renderer, bM09Renderer, bM10Renderer};

		foreach(MeshRenderer a in mesherAr){
			a.enabled = false;
		}


	}
	
	// Update is called once per frame
	void FixedUpdate () {

		Debug.Log (arrayIndex);

		foreach(MeshRenderer a in mesherAr){
			a.enabled = false;
		}

			
		if (arrayIndex < 10) {
			mesherAr [arrayIndex].enabled = true;
			
			arrayIndex++;
		} else if (arrayIndex == 10)
			arrayIndex = 0;


	}
}

So I manually drag my gameObjects in the inspector and cycle visibility for each frame. The thing is that I will eventually need to do it for at least 50 gameobjects, so this way doesn’t seem all that good. I wish I could at least drag the parent gameobject and the script would populate my array in the correct order…

Well, that’s kind of easy. I wouldn’t go for a GameObject.Find approach since 50 calls of Find, even in Start, might not be such a good idea ^^.

There are several options how to do that. The easiest is probably to only drag the parent object to your script and let the script get all renderers in the child objects. With Linq this can even be done with a single line:

public Transform parent;
MeshRenderer[] objs;
void Start()
{
    objs = parent.OfType<Transform>().Select((t) => t.GetComponent<MeshRenderer>()).OrderBy((r) => r.name).ToArray();
}

So what is happening here is:

  • You assign the parent object of your objects to the “parent” variable in the inspector.
  • Inside Start we first have to cast the IEnumerable to the generic IEnumerable (OfType)
  • then we “convert” the Transform enumerable to a MeshRenderer enumerable with the Select method which will execute the select function for each transform.
  • now we just order the items by their names
  • and finally convert the whole thing to an array.

The obj array should contain the references to the MeshRenderer components of all child objects in the correct order.

Note: The parent must not have other objects as childs, especially not objects without a MechRenderer. If there are other objects you have to filter the enumerable first:

    objs = parent.OfType<Transform>().Select((t) => t.GetComponent<MeshRenderer>()).Where((r) => r != null && r.name.StartsWith("testObj")).OrderBy((r) => r.name).ToArray();

Here we just inserted a “Where” after we get the renderer to make sure:

  • there is even a renderer attached to that object
  • and the name has to start with “testObj”.

edit
I almost forgot this: Of course to use the Linq extension methods you have to add using System.Linq; at the top of the script. I added this as precaution for future readers ^^.

I would use a List rather than an Array, then use list.sort(). I am not a hotshot C# developer who can store all this stuff in their head right now, so I will provide a link.

Here is a page talking about sorting lists that is quite interesting:

Here is a page from Stack Overflow talking about Arrays VS Lists (basically use a List):

http://stackoverflow.com/questions/434761/array-versus-listt-when-to-use-which

I guess you want to sort the child objects based on the name of the object, so you would do the following:

  1. Find all child objects of the type you wish to store, then store them in the List.
  2. Sort all child objects based on the name of the object, alphabetically (ascending).
  3. In each update step use a foreach to step through the list. It will step through alphabetically for the name of the object, as that was already done.

Alternatively just use an int to store the index. Increment by 1 each frame, then specifically enable the List element with the correct index, and disable the list element with index - 1.