0

EDIT: I'm not confused about what a null error indicates, I know that my list is null. I'm just unsure of why it would be null in this case, or why setting my list to public suddenly fixes this.

So, I'm trying to make a function that will add an object to a list if it meets the conditions. The function takes in the tag it's checking for, and the specific list it'll add it to if possible. The reason I'm doing this, is because I have two lists, and I'd rather only need one function for both.

This works all well and good, but I'm having an issue where it doesn't...really seem to work unless the lists are set to public? Which I'd rather not do if I can help it. I don't understand why, since it handles the private gameObject reference just fine, and that's declared in the same spot, and the function is inside the same class, yet trying to call this function while the lists are private just gives me a null object reference error, which I've narrowed down to the list being null in this case, not the object?

This isn't really a big deal, since I can just change around a few things to avoid having the lists public, but I'm just really confused as to why this is happening? I've tried explicitly passing by ref, but that gave the same issues.

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

public class ClickHandler : MonoBehaviour
{
    GameObject clickedMob = null;

    List<GameObject> selectedMinions;
    List<GameObject> selectedHostiles;

    void Update ( )
    {

        if ( Input.GetButtonDown("Click"))
        {
            switch (clickState)
            {
                case NextClickAction.Nothing:
                    { }
                    break;

                case NextClickAction.TargetFriendly:
                    {

                       hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero);

                        if ( hit )
                        {
                            if ( hit.transform != null )
                            {
                                clickedMob = hit.transform.gameObject;
                                CheckObject("Minion", selectedMinions);
                            }
                        }
                    }
                    break;

                case NextClickAction.TargetHostile:
                    {
                        hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero);

                        if ( hit )
                        {
                            if ( hit.transform != null )
                            {
                                clickedMob = hit.transform.gameObject;
                                CheckObject("Hostile", selectedHostiles);
                            }
                        }
                    }
                    break;

                default:
                    {
                        Debug.Log("why do you have an enum this big");
                        DeactivateClick();
                        Debug.LogError("Enum set outside of index. Returned to 0.");
                        break;
                    }
            }

        }
    }   //  end of update

    private void CheckObject ( string tag , List<GameObject> mobList)
    {
        if ( clickedMob.CompareTag(tag) )
        {
            if ( clickedMob.GetComponent<Animator>() != null )
            {
                ClickedMobAnimator = clickedMob.GetComponent<Animator>();

                switch (ClickedMobAnimator.GetBool("Selected"))
                {
                    case true:
                        ClickedMobAnimator.SetBool("Selected", false); // Setting the object to have a little box around it when it's selected.

                        mobList.Remove(clickedMob);
                        Debug.Log(mobList.Count + " " + clickedMob);
                        break;

                    case false:
                        ClickedMobAnimator.SetBool("Selected", true);
                        mobList.Add(clickedMob); 
                        Debug.Log(mobList.Count + " " + clickedMob);
                        break;
                }
            }

        }
    }

Output of this code:

NullReferenceException: Object reference not set to an instance of an object
ClickHandler.CheckObject (System.String tag, System.Collections.Generic.List'[T] mobList) (at Assets/Scripts/ClickHandler.cs:119)

And I know the object isn't what's null in this case, because I had a debug log print the object. It's there.

Sheep
  • 3
  • 1
  • 5
  • 1
    You need to actually create a `new List` - otherwise the default value stays `null`. (Unity automatically creates it for `public` member variables for the Editor) – UnholySheep Apr 18 '20 at 20:20
  • 1
    Does this answer your question? [What is a NullReferenceException, and how do I fix it?](https://stackoverflow.com/questions/4660142/what-is-a-nullreferenceexception-and-how-do-i-fix-it) – devNull Apr 18 '20 at 20:22
  • @devNull Not exactly. Either that, or I'm not looking at it quite right. My issue isn't that it's null, but more specifically, why it's only null when the list is private. By my knowledge, it shouldn't make a difference as everything is inside the same class, right? – Sheep Apr 18 '20 at 20:32
  • @UnholySheep First off, hello there, fellow sheep! :P And I'm not entirely sure what you mean by that? Like, make a temporary list inside the function, and return it, or something else? – Sheep Apr 18 '20 at 20:35
  • @UnholySheep OH MY GOSH, I completely forgot that step! I knew it was something simple, thank you soo much! It's fixed now. ^^ – Sheep Apr 18 '20 at 20:38
  • So um...how do I close the question? Do I just edit UnholySheep's solution at the top for anyone else that has this specific issue? Sorry, I've never actually asked a question here before. >~<; – Sheep Apr 18 '20 at 20:39

1 Answers1

1

Since your lists are nonpublic and also nonserialized fields you can't assign them from inspector to create new list instance automaticaly, so in your ClickHandler script add Awake method where you instantiate them as new list objects.

void Awake() {
    selectedMinions = new List<GameObject>();
    selectedHostiles = new List<GameObject>();
}

or you can do same thing at declaration time

List<GameObject> selectedMinions = new List<GameObject>();
List<GameObject> selectedHostiles = new List<GameObject>();
Chestera
  • 667
  • 2
  • 13
  • 22
  • 1
    I decided to go with the latter, and it worked for me. I'm a bit embarrassed to have forgotten that step, but glad that I didn't have to spend the afternoon trying to figure this out on my own this time. Thank you. – Sheep Apr 18 '20 at 21:39