0
\$\begingroup\$

I'm using Unity. I have an empty elements called GameElements which I programmatically add child elements to (players can spawn these objects themselves in-game).

Within my script Play.cs I have a method to handle the onclick event when someone clicks the Play image/button. I want to run through all of the child elements of my GameElements object and run the method on the script Circle.cs which is attached to those child elements.

Here is my Play.cs:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Play : MonoBehaviour
{ 
    public GameObject GameElements;
    public Circle CircleScript;

    public void OnMouseDown()
    {
        Debug.Log("Clicked!", gameObject);

        GameElements = GameObject.Find("GameElements");

        // Loop through game objects and init them
        Transform[] allChildren = GameElements.GetComponentsInChildren<Transform>();
        foreach (Transform child in allChildren) {
            // do whatever you want with child transform object here
            Debug.Log("child...", child);
            CircleScript = (Circle) child.GetComponent(typeof(Circle));
            CircleScript.Init();
        }
    }
}

The click events do generate a Debug Log in console for the child objects as expected.

However I get the following:

NullReferenceException: Object reference not set to an instance of an object
Play.OnMouseDown () (at Assets/Game/Scripts/Play.cs:22)
UnityEngine.SendMouseEvents:DoSendMouseEvents(Int32)

Any help appreciated.

\$\endgroup\$
2
  • \$\begingroup\$ What is the value of GameElements here: GameElements = GameObject.Find("GameElements");? \$\endgroup\$ – Skalli Aug 27 '18 at 15:44
  • \$\begingroup\$ Why don't you use var circles = GameElements.GetComponentsInChildren<Circle>(); instead of iterating in transforms to get the Circle component? In that way you know you iterate on valid objects. \$\endgroup\$ – arielsan Aug 28 '18 at 1:50
1
\$\begingroup\$

child.GetComponent(typeof(Circle)) is not finding a Circle component, and thus returning null. You don't check for null, you just assume success and call Init on the resulting reference.

This is probably happening because, as you note in your own answer, GetComponentsInChildren returns components of the given type in the invoking game object and its children.

Regardless, you may want write the loop in a way that you protect against a failure to find the Circle:

foreach (Transform child in allChildren) {
  CircleScript = child.GetComponent<Circle>();
  if (CircleScript != null) {
    CircleScript.Init();
  }
}

You can alternatively check if the child's game object is the GameElements object simply using ==. Both options are somewhat more robust than checking the name, since you may change the name elsewhere some day and forget to update this code.

\$\endgroup\$
0
\$\begingroup\$

It seems that foreach (Transform child in allChildren) { iterates the children and the original object itself. So, if I have 2 children, I get 3 iterations, the first being the parent.

I simply need to check the name isn't of the parent:

foreach (Transform child in allChildren) {
    // do whatever you want with child transform object here
    Debug.Log(child.name);
    if(child.name != "GameElements") {
        CircleScript = (Circle) child.GetComponent(typeof(Circle));
        CircleScript.Init();
    }
}
\$\endgroup\$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.