#MissingReferenceException, I need help

1 messages · Page 1 of 1 (latest)

tulip pond
#

So I have this project that I am basically done with, by that, I mean that I have everything that is required, but something is screwing up. I was tasked to make a GUI where one element changes the game's speed, and it works when running the game for the first time, however as soon as I destroy an enemy object (it spawns another one) and then I try adjusting the speed, the missing reference exception occurs, and I don't know where it's coming from.

clever pumice
tulip pond
#

Forgive me, I'm still fairly new to unity, but I've tried looking at the console to see what was up, and I see some scripts mentioned within the error. I have an idea as to why it's happening, but I don't necessarily know code wise.

clever pumice
#

If you're posting in #archived-code-general , you're expected to be able to do some debugging.

Either way, can't help you without more details(error message, cod, etc..)

tulip pond
#

I see, I'll get to the details. When the game is built, everything is already in the level except the enemy prefab, so there's a level controller that spawns in the enemy. When the enemy gets hit by a ray-cast from the player clicking, it destroys the game object, which I would assume is where since in one of the other scripts or methods refers to that initial game object, that's why it's freaking out.

#

I'll send in the scripts I believe are at fault now

#

This one is the level controller

using System.Collections.Generic;
using UnityEngine;

public class LevelController : MonoBehaviour
{
    [SerializeField] private GameObject enemyPrefab;

    private GameObject enemy;

    private List<GameObject> enemies = new List<GameObject>();

    private int score = 0;

    private Playercontroller playerMovementController;

    void Start()
    {
        playerMovementController = FindObjectOfType<Playercontroller>();
    }

    void Update()
    {
        if (enemy == null)
        {
            enemy = Instantiate(enemyPrefab) as GameObject;
            enemy.transform.position = new Vector3(11f, 1.5f, -10f);
            enemies.Add(enemy);
            float angle = Random.Range(0, 360);
            enemy.transform.Rotate(0, angle, 0);
        }
    }

    public void SetScore (int newScore)
    {
        score = newScore;
    }

    public int GetScore()
    {
        return score;
    }

    public void UpdateMovementSpeedOfAllAis(float newSpeed)
    {
        foreach(GameObject enemyAI in enemies)
        {
            WanderingAI AIMovementController = enemyAI.GetComponent<WanderingAI>();
            AIMovementController.SetSpeed(newSpeed);
        }
    }

    public void UpdatePlayerSpeed(float newSpeed)
    {
        playerMovementController.SetSpeed(newSpeed);
    }

}
#

This script is used for when the enemy object gets hit with a ray-cast

using System.Collections.Generic;
using UnityEngine;

public class ReactiveTargets : MonoBehaviour{

    [SerializeField] LevelController gameController;

    [SerializeField] UIController ui;

    void Start()
    {
        gameController = FindObjectOfType<LevelController>();
        ui = FindObjectOfType<UIController>();
    }


    public void ReactToHit()
    {
        WanderingAI Behavior = GetComponent<WanderingAI>();
        if (Behavior != null)
        {
            Behavior.SetAliveStatus(false);
        }
        int newScore = gameController.GetScore() + 1;
        gameController.SetScore(newScore);
        ui.UpdateScoreText(newScore.ToString());
        StartCoroutine(Die());
    }

    IEnumerator Die()
    {
        transform.Rotate(-75, 0, 0);
        
        yield return new WaitForSeconds(1.5f);

        Destroy(this.gameObject);

    }

}
clever pumice
tulip pond
#

The error was "MissingReferenceException: The object of type 'GameObject' has been destroyed but you are still trying to access it.
Your script should either check if it is null or you should not destroy the object."

clever pumice
#

You're omitting the most important information

#

The error message tells you what line of code threw the error.

#

Without it, it's basically useless

tulip pond
#

The thing is that it shows a whole bunch of details

clever pumice
#

It also contains a stack trace of what led to that call.

clever pumice
tulip pond
#
LevelController.UpdateMovementSpeedOfAllAis (System.Single newSpeed) (at Assets/Scripts/LevelController.cs:48)
SettingsPopup.OnChangePlayerSpeed (System.Single speed) (at Assets/Scripts/SettingsPopup.cs:31)
UnityEngine.Events.InvokableCall`1[T1].Invoke (T1 args0) (at <acc21e65c0ae4adf80ac80bfa5d3f603>:0)
UnityEngine.Events.UnityEvent`1[T0].Invoke (T0 arg0) (at <acc21e65c0ae4adf80ac80bfa5d3f603>:0)
UnityEngine.UI.Slider.Set (System.Single input, System.Boolean sendCallback) (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/UI/Core/Slider.cs:519)
UnityEngine.UI.Slider.OnMove (UnityEngine.EventSystems.AxisEventData eventData) (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/UI/Core/Slider.cs:657)
UnityEngine.EventSystems.ExecuteEvents.Execute (UnityEngine.EventSystems.IMoveHandler handler, UnityEngine.EventSystems.BaseEventData eventData) (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/ExecuteEvents.cs:120)
UnityEngine.EventSystems.ExecuteEvents.Execute[T] (UnityEngine.GameObject target, UnityEngine.EventSystems.BaseEventData eventData, UnityEngine.EventSystems.ExecuteEvents+EventFunction`1[T1] functor) (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/ExecuteEvents.cs:262)
UnityEngine.EventSystems.EventSystem:Update() (at Library/PackageCache/com.unity.ugui@1.0.0/Runtime/EventSystem/EventSystem.cs:385)```
#

This was from the console

clever pumice
#

This is the stack trace that led to the error. You can see the latest calls in the stack from top to bottom.

#

Notice how the first thing is get component. That's the call that threw the error.

tulip pond
#

So the first line of the stack trace is what causes this sort of domino effect?

clever pumice
#

The next thing is a line of code from your script - LevelController.UpdateMovementSpeedOfAllAis on line 48

clever pumice
clever pumice
tulip pond
#

The line would be WanderingAI AIMovementController = enemyAI.GetComponent<WanderingAI>(); so it has to be within another script

clever pumice
#

You can use the debugger or debug logs to further investigate what is being null and why.

tulip pond
#

Also I'm starting to understand the stack trace a little more, now that I'm starting to see that the cs:XX refers to a specific line

clever pumice
#

Seeing how it's called from an event(further in the stack trace), I can assume that you don't unsubscribe from an event when an object is destroyed.

#

Actually, nevermind that. Just had a look at the code and it's probably not that.
I'd guess that you just don't remove the destroyed enemy from the enemies list.

tulip pond
#

Here's that wanderingAI script that the other thing is calling:

#
using System.Collections.Generic;
using UnityEngine;

public class WanderingAI : MonoBehaviour
{
    public float obstacleDetectionRange = 5.0f;
    public float movementSpeed = 3.0f;

    [SerializeField] GameObject FireballPrefab;
    GameObject spawnedFireball;

    bool isAlive;

    void Start()
    {
        isAlive = true;
    }


    void Update()
    {
        if (isAlive)
        {
            transform.Translate(0, 0, movementSpeed * Time.deltaTime);

            Ray ray = new Ray(transform.position, transform.forward);

            RaycastHit hit;

            bool objectWasHit = Physics.SphereCast(ray, 0.75f, out hit);

            if (objectWasHit)
            {
                GameObject hitObject = hit.transform.gameObject;
                if (hitObject.GetComponent<PlayerCharacter>())
                {
                    if (spawnedFireball == null)
                    {
                        spawnedFireball = Instantiate(FireballPrefab);
                        spawnedFireball.transform.position = 
                            transform.TransformPoint(Vector3.forward * 1.5f);
                        spawnedFireball.transform.rotation = transform.rotation;
                    }
                }
                
                else if (hit.distance < obstacleDetectionRange)
                {
                    float angle = Random.Range(-110, 110);
                    transform.Rotate(0, angle, 0);
                }
            }
        }
    }

    public void SetAliveStatus (bool status)
    {
        isAlive = status;
    }

    public void SetSpeed(float newSpeed)
    {
        movementSpeed = newSpeed;
    }

}
#

Looking at this, I'm not sure if it is this script that is the problem

#

Because this only really controls the enemy's movement and shooting a projectile if the ray-cast from them hits the player object

#

The one thing I can see as being a contributor to the problem is the movementSpeed line, since that one was a new addition for this project

#

Which to give context, most of my class was just watching videos of the professor just making the game and just following along

tulip pond
clever pumice
tulip pond
#

I'm not sure how to do that, sorry if that seems a bit annoying or more of a "This should be obvious" type of thing

#

I just realized where the list is, now to figure out how to modify said list into removing the destroyed enemy

clever pumice
# tulip pond I just realized where the list is, now to figure out how to modify said list int...

There are many ways. Either check in your level controller wether any enemies in the list have been destroyed(became null), and if so remove them from the list, or manage the destruction of the enemy in the LevelController so that you can also remove it from the list, or raise an event in the enemy class when it's destroyed. The LevelController then can subscribe to that event to remove the destroyed enemy from the list.

tulip pond
#

There's that conditional statement of if(enemy == null), so I'm not sure the first option would be the best, but that's what I'm thinking.

#

Unless I make another conditional statement to check if the destroy method was used

clever pumice
#

It doesn't check the enemies in the list.

tulip pond
#

This part in the level controller

    {
        if (enemy == null)
        {
            enemy = Instantiate(enemyPrefab) as GameObject;
            enemy.transform.position = new Vector3(11f, 1.5f, -10f);
            enemies.Add(enemy);
            float angle = Random.Range(0, 360);
            enemy.transform.Rotate(0, angle, 0);
        }```
#

If there are no enemies in the level already, spawn a new one at those coordinates

clever pumice
clever pumice
#

Here's a question for you: let's say you spawn 2 enemies. Then one enemy is being destroyed. What would your enemies list contain?

tulip pond
#

I want to say that there would be one enemy, because one of the other enemy objects got destroyed

#

But that doesn't remove them from the list, no?

clever pumice
#

That would be magic and very undesirable behavior

tulip pond
#

Okay, so destroying the enemy just gets rid of the object in the game space, but not the list

clever pumice
#

It destroys the underlying object. References are not part of the object.

#

If you place a tag/label (reference) on a box that contains an apple saying that there's an apple inside, then remove the apple from the box, the lable won't go anywhere. It would just point to an empty box.

tulip pond
#

So I put the enemy list to public, and yeah, it doesn't remove the enemy

tulip pond
#

So I'm attempting to modify the code, but I have no idea how I can implement the list.RemoveAt(index) method. I've tried putting it in the Die() corroutine, but I end up with a null reference exception, I tried putting it in it's own method, but didn't work. All I know is I want to get rid of the specific enemy when it gets hit

clever pumice
tulip pond
#

I did it, with a bit of a hiccup, but I don't care

#
    {
        transform.Rotate(-75, 0, 0);
        
        yield return new WaitForSeconds(1.5f);

        gameController.enemies.RemoveAt(0);

        Destroy(this.gameObject);

    }```
#

All I did was add this before destroying the game object, and no errors

#

The only nitpick I will say is that the new enemies don't keep the same speed as the previous one when killed