0

I'm trying to learn how to count enemies and remove them from a list if they die. so i have this script which essentially counts the amount of enemies at void start() the issue i'm having though is: when i call the method from a script which removes an enemy from the list i get a Null reference exception error. this is the method i'm trying to call

public void KilledEnemy(GameObject Enemy)
{
    if (Enemies.Contains(Enemy))
    {
        Enemies.Remove(Enemy);
    }

    Debug.Log(Enemies.Count + " Enemies Left");

}

for clarification this is the code with the list.

public class Level1Control : MonoBehaviour
{

    public GameObject Exit;

    public List<GameObject> Enemies = new List<GameObject>();

    public static Level1Control instance;

    // Start is called before the first frame update
    void Start()
    {
        Enemies.AddRange(GameObject.FindGameObjectsWithTag("Enemy"));
        Debug.Log(Enemies.Count + " Enemies Left");
    }

    public void KilledEnemy(GameObject Enemy)
    {
        if (Enemies.Contains(Enemy))
        {
            Enemies.Remove(Enemy);
        }

        Debug.Log(Enemies.Count + " Enemies Left");

    }


    public bool AreOpponentsDead()
    {
        if (Enemies.Count <= 0)
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    private void Update()
    {
        AreOpponentsDead();
        if (AreOpponentsDead() == true)
        {
            OpenDoor();
            Debug.Log("Dead");
        }


    }

    public void OpenDoor()
    {

    }
}

the way i attempt to call the function is like this (this is the entirety of the code in this script:

 public GameObject thisEnemy;

private void OnCollisionEnter(Collision collision)
    {
        if(collision.gameObject.CompareTag("Bullet"))
        {
            Level1Control.instance.KilledEnemy(thisEnemy);
            this.gameObject.SetActive(false);
        }
    }

any help is greatly appreciated.

Edit

ok so thanks to the wonderful people who took the time out of their day to help me the problem was solved!

i added this to my level1control script:

private void Awake()
    {
        instance = this;
    }
11
  • 1
    Do you ever set the value of Level1Control.instance? Commented Nov 9, 2020 at 21:51
  • @Paramecium13 the instance variable is there so i can call the script. if thats what you meant? sorry i'm very new to unity and programming in general. Commented Nov 9, 2020 at 21:54
  • 2
    Does this answer your question? What is a NullReferenceException, and how do I fix it? Commented Nov 9, 2020 at 22:07
  • 1
    This might also be of interest: Unity singleton manager classes, although it would be unconventional design to have a singleton for each level, judging by the name Level1Control. Commented Nov 9, 2020 at 22:12
  • 1
    The question does not say which line produces the null reference exception but I can infer it's on the line Level1Control.instance.KilledEnemy(thisEnemy); and Level1Control.instance is null. Commented Nov 9, 2020 at 22:15

2 Answers 2

1

It appears that you never assign a value to Level1Control.instance, as such, anytime you try to call a method on it, it will throw an exception.

To fix this, I recommend that you create a constructor for Level1Control that contains instance = this;. Alternatively, you could put that line in the Start method.

Sign up to request clarification or add additional context in comments.

4 Comments

Thank you very much!
Ouuwwwwwwch. Certainly this "sort of works" but it will almost certainly fail instantly and catastrophically :) At worst @HarounAhmad just add an "ordinary" global to do this. (So, just a class which >>> IS NOT <<< a component!!! A simple two-line c# class.)
@Fattie yeah, this isn't a good practice. I'd probably do something like have the enemy class look at the current level entity and see if it has a Level1Control component or maybe have the enemy publish an event that the Level1Control can listen to. But I don't know enough about Unity to say how to do that.
fortunately scoring etc. is dead easy, you just need a (say) Scoring monobehavior, which there is only one of (and of course it is DDOL). this is 1 line of code and two clicks, you just have to know the usual scene idiom in a game engine such as unity. stackoverflow.com/a/35891919/294884
1

As a general rule, you should DEFINITELY NOT be using statics in Unity (unless you are really expert).

It's almost always really meaningless to use a static in a game object environment.

On top of that, the idea of using a static to "point to something similar to an instance of a component using itself" is really, really problematic in Unity.

(Again, if you're a lights-out Unity expert you may do something like that perhaps just during development, but it's really not the way to go!)

Note that, you may just want to have "a global" ..

... note that that WOULD NOT !!! be a component / monobehavior !!! ...

which you could use.

(Of course, just in general in programming it usually sucks to use globals. But it is far "less of a problem" than using a static on a component in an ECS system!!!)

Hence,

public class Settings
{
    public static int buildNumber = 302;
    public static bool quickDevOption = false;
    public static int quickHitCountMap4 = 3;
}

Note that it IS NOT a component / monobehavior!!

It is vanilla c# and has NO CONNECTION to Unity's frame-based, scene-based, system

Please note that what you really want is an ordinary old preload scene, like a manager. This is perfectly easy, one line of code:

https://stackoverflow.com/a/35891919/294884

I strongly encourage you to remove that static from the MonoBehavior!

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.