Null reference error when enemy unit dies

i’m getting a nullreferenceerror like such after i kill an enemy unit and end my turn: MissingReferenceException: The object of type ‘TextMeshProUGUI’ 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.
UnitWorldUI.UpdateActionPointsText () (at Assets/Scripts/Unit/UnitWorldUI.cs:36)
UnitWorldUI.Unit_OnAnyActionPointsChanged (System.Object sender, System.EventArgs e) (at Assets/Scripts/Unit/UnitWorldUI.cs:24)
Unit.TurnSystem_OnTurnChanged (System.Object sender,

i checked the scene heirarchy and that enemy unit seems to have been properly destroyed. i have temporarily fixed it by adding in a unit ==null check in the unitworldui class but it seems to be hacky; i’m not why the unitworldui is still running for the destroyed gameobject. not sure where else to check why that instance of the class is still alive. can it have something to do with unsubscribed event handlers in c#?

Look at your UnitWorldUI script. It is referencing a TextMeshProUGUI object that was on the destroyed enemy unit.

yes, that unitworldscript is attached to the unit that was destroyed. i’m not sure why it’s still alive. is this topic not directly attached to the course? first time using this

How are you destroying the enemy unit? It seems the UnitWorldUI script is still around, so it’s trying to update the action points text

the unit calls destroy(gameobject) on itself when its health reaches zero

I believe this is exactly what is happening. I think the Unit is still subscribed to the TurnSystem.OnTurnChanged event. Be sure to unsubscribe to this event when the Unit is destroyed.

i’ve added
TurnSystem.Instance.OnTurnChanged -= TurnSystem_OnTurnChanged; but still get a similar error. i notice that in the gitlab for the finished project there aren’t any such unsubscribe statements. how are event handlers subscription disposed of in the source code?

Paste in your UnitWorldUI.cs and we’ll take a closer look.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
using System;

public class UnitWorldUI : MonoBehaviour
{
[SerializeField] private TextMeshProUGUI actionPointsText;
[SerializeField] private Unit unit;
[SerializeField] private Image healthBar;
[SerializeField] private HealthSystem healthSystem;

private void Start()
{
    Unit.OnAnyActionPointsChanged += Unit_OnAnyActionPointsChanged;
    healthSystem.OnDamage += HealthSystem_OnDamage;
    UpdateActionPointsText();
}

private void Unit_OnAnyActionPointsChanged(object sender, EventArgs e)
{
    UpdateActionPointsText();
}

private void HealthSystem_OnDamage(object sender, EventArgs e)
{
    UpdateHealthBar();
}

private void UpdateActionPointsText()
{
    if(unit == null)
    {
        //this is a fukkin HACK
        //do i just get rid of this ? its not my intended final ui anyways
        //TODO:
        return;
    }
    if (unit.IsEnemy())
    {
        actionPointsText.enabled = false;
    }
    else
    {
        actionPointsText.enabled = true; //could flip flop depending on status effect?
    }
    actionPointsText.text = unit.GetActionPoints().ToString();
}

private void UpdateHealthBar()
{
    healthBar.fillAmount = healthSystem.GetHealthNormalized();
}

}

This is actually a very strange issue but the issue is not in your end, it should indeed be causing an error because it is accessing a null reference.
I have no idea why it did not cause an error on my end, I am testing it right now in the final build of the course and it works without an error despite the fact that the TextMeshProUGUI reference is null just like it should.
The unit is also null but for some reason also does not cause an error on my end.
I really have no clue what is going on, that code should be throwing an error just like you’re seeing, no idea why it doesn’t happen on my end.

What Unity version are you using? Including the hotfix version? Maybe it’s a strange bug in Unity 2022.1.0f1 which is fixed in a later hotfix version.

The correct code should be to unsubscribe from the static event when that object is destroyed

    private void OnDestroy() 
    {
        Unit.OnAnyActionPointsChanged -= Unit_OnAnyActionPointsChanged;
    }
1 Like

i’m using 2021.1.28f1

so for future reference, any time there i subscribe to event handlers on an object that should be destroyed, i should implement the ondestroy lifecycle method and unsub from all event handlers?

There’s no need to unsubscribe when both the event publisher and listener die at the same time.

For example in that case that script is also listening to the event on the HealthSystem, but that one does not cause issues because the HealthSystem object will be destroyed at the same time as the UnitWorldUI

The issue happens when the listener dies but the publisher keeps on living, which is the case with the static event on the Unit class.
When a Unit dies, that UnitWorldUI is destroyed, but the Unit class still exists, there are still other alive units, and when one of those makes a move and modifies the Action Points the Unit class will fire the static event to all the listeners including the one that has already been destroyed.

If you were instead listening to a non-static event on the Unit related to that specific UnitWorldUI, then in that case there would be no need to unsubscribe because both that specific Unit and that specific UnitWorldUI would both die at the same time.

1 Like

Privacy & Terms