0
\$\begingroup\$

I am trying to use nested classes and call functions in the base class of the script.

public class componentEnable : MonoBehaviour
{

private DisableMeshOnStart disableMeshOnStart_ = new DisableMeshOnStart();
private EnableCanvasOnStart enableCanvasOnStart_ = new EnableCanvasOnStart();

public DisableMeshOnStart[] disableMeshOnStartGroup;
public EnableCanvasOnStart[] enableCanvasOnStartGroup;

void Start()
{

    disableMeshOnStart_.OnStart();

   enableCanvasOnStart_.OnStart();

}

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

}


[Serializable]
public class DisableMeshOnStart
{
    public string groupTitle;
    public bool disableMeshOnStart_ = false;
    public GameObject[] disableMeshes;

    public void OnStart()
    {
        int howMany = disableMeshes.Length;
        Debug.Log(howMany);
        foreach (GameObject asset in disableMeshes)

        {
            if (disableMeshOnStart_ == true)
            {
                asset.GetComponent<MeshRenderer>().enabled = !true;
            }
        }
    }
}

[Serializable]
public class EnableCanvasOnStart
{

    public string groupTitle;
    public bool enableCanvasOnStart_ = false;
    public GameObject canvasUI;

    public void OnStart()
    {
        Debug.Log("hello");
        if (enableCanvasOnStart_ == true)
        {
            Debug.Log("beep");
            canvasUI.GetComponent<Canvas>().enabled = true;
        
       }
     }
   }
 }

There errors I get are:

NullReferenceException: Object reference not set to an instance of an object componentEnable+DisableMeshOnStart.OnStart () (at Assets/Scripts/V2/componentEnable.cs:41) componentEnable.Start () (at Assets/Scripts/V2/componentEnable.cs:19)

I am trying to understand why I cant call these functions properly. The game objects are assigned properly in the inspector.

If placed in a separate class, like so than it does work as expected.

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

public class Test : MonoBehaviour
{
   
        public string groupTitle;
        public bool disableMeshOnStart_ = false;
        public GameObject[] disableMeshes;

    public void Start()
    {
        OnStart();
    }
    public void OnStart()
        {
            int howMany = disableMeshes.Length;
            Debug.Log(howMany);
            Debug.Log("Forloop");
            foreach (GameObject asset in disableMeshes)

            {
                if (disableMeshOnStart_ == true)
                {
                    asset.GetComponent<MeshRenderer>().enabled = !true;
                }
            }
        }
    }

This script, with the help of answers in the thread, work as expected, but I would still like to understand how to create arrays of the classes:


public class ComponentEnable : MonoBehaviour
{

    [SerializeField]
    private EnableCanvasOnStart enableCanvasOnStart_ = new EnableCanvasOnStart();
    [SerializeField]
    private DisableMeshOnStart disableMeshOnStart_ = new DisableMeshOnStart();
   

    //private DisableMeshOnStart[] disableMeshOnStartGroup;
    //private EnableCanvasOnStart[] enableCanvasOnStartGroup;

    void Start()
    {

      disableMeshOnStart_.OnStart();

       enableCanvasOnStart_.OnStart();

    }
    [System.Serializable]
    public class EnableCanvasOnStart
    {

        public string groupTitle;
        public bool enableCanvasOnStart_;
        public GameObject canvasUI;

        public void OnStart()
        {
            Debug.Log("2");
            if (enableCanvasOnStart_ == true)
            {
                Debug.Log("beep");
                canvasUI.GetComponent<Canvas>().enabled = true;

            }
        }
    }
}



[System.Serializable]
    public class DisableMeshOnStart
    {
        public string groupTitle;
        public bool disableMeshOnStart_;
        public GameObject[] disableMeshes = new GameObject[0];

        public void OnStart()
        {
            Debug.Log("1");
            int howMany = disableMeshes.Length;
            foreach (GameObject asset in disableMeshes)
            {
                if (disableMeshOnStart_ == true)
                {
                    asset.GetComponent<MeshRenderer>().enabled = !true;
                }
            }
        }
    }
\$\endgroup\$
3
  • \$\begingroup\$ Are you sure the problem is with the fact that the classes are nested? Did you try moving them to a separate file and see if it works? -- NullReferenceException means that you're calling a method on a null reference. I think that either disableMeshes is null, or at least one of them doesn't have a MeshRenderer. How about putting some guard conditionals, or trace through the code? \$\endgroup\$ – Panda Pajama Nov 5 '20 at 2:46
  • 1
    \$\begingroup\$ Yeah, looks like the exception is thrown from within DisableMeshOnStart.OnStart() method. In fact, I think that this is the line that causes the problem: int howMany = disableMeshes.Length; - your disableMeshes is never initialized, so it's null, and you can't call Length on a null. \$\endgroup\$ – Filip Milovanović Nov 5 '20 at 3:54
  • \$\begingroup\$ so, if made into a separate class - this works as expected. I will attach the working code to the question \$\endgroup\$ – cyo Nov 5 '20 at 4:01
0
\$\begingroup\$

There's an important difference between your working and non-working versions.

In your working version, Test is a MonoBehaviour, directly visible to the Unity serializer. So it will automatically fill-in any public or [SerializeField] arrays and lists with empty (but non-null) versions if you don't provide values yourself.

In your non-working version, you declared disableMeshOnStart_ as private, meaning you forbid the serializer from seeing or modifying its contents. So it can't get at the disableMeshes array to populate it with values, and it keeps the value you gave it, which was null since you never assigned to it in a field initializer or constructor.

The game objects are assigned properly in the inspector.

No, they are not, because disableMeshOnStart_ is not shown in the inspector at all. You might be getting mixed up and looking at the disableMeshOnStartGroup instead, since that one is public and visible to the serializer... just not used by your code anywhere we can see.

So, a few fixes:

  1. Declare disableMeshOnStart_ as public or with a [SerializeField] attribute to allow the serializer to populate it. This will also allow it to show up in your Inspector so you can assign one or more meshes to disableMeshes, so it's not just an empty array.

  2. Add your own initializer like public GameObject[] disableMeshes = new GameObject[0]; so that you're guaranteed it has a non-null value when you try to use it.

  3. Check whether the reference is null before trying to use it.

\$\endgroup\$
2
  • \$\begingroup\$ I updated the script to a working version with your help, and that is very much appreciated. I am still wondering how I can create arrays of those classes as to be able to make the script more useful to me. In this situation I would need to attach the script multiple times to a single gameobject each time I want to use it on a grouping of components. \$\endgroup\$ – cyo Nov 10 '20 at 18:15
  • \$\begingroup\$ Want to ask that as a new Question? \$\endgroup\$ – DMGregory Nov 10 '20 at 18:40

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.