Destroy isn't deleting GO and Ienumator missingreferenceException

Hi all,

I’m relatively new to game dev and c# and starting on my 2nd game and coming across a strange error as I’m pretty much using the exact same code that is working for the players minions, but isn’t working for the enemies.

I have a script called PlayerMinion(for the player) and the enemies he is facing called Enemy.

The code is almost identical but for some reason the enemy code is coming up with errors

  IEnumerator CheckTargetAndHp2()
    {
        while (true)
        {
            yield return new WaitForSecondsRealtime(0.5f);


            if (hp <= 0)
            {
                Destroy(gameObject);
            }
            if (target == null)
            {
                anim.SetBool("attack", false);
                attacking = false;
            }
        }

    }

NullReferenceException: Object reference not set to an instance of an object
Enemy+c__Iterator0.MoveNext () (at Assets/Enemy.cs:58)
UnityEngine.SetupCoroutine.InvokeMoveNext (IEnumerator enumerator, IntPtr returnValueAddress) (at C:/buildslave/unity/build/Runtime/Export/Coroutines.cs:17)

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.
UnityEngine.GameObject.GetComponent[PlayerMinion] () (at C:/buildslave/unity/build/artifacts/generated/common/runtime/UnityEngineGameObjectBindings.gen.cs:38)
Enemy.AttackTarget () (at Assets/Enemy.cs:48)
UnitAttackCollided.OnStateExit (UnityEngine.Animator animator, AnimatorStateInfo stateInfo, Int32 layerIndex) (at Assets/UnitAttackCollided.cs:38)

The code also isn’t deleting the enemies but is deleting the playerminions. Like I say the code is pretty much identical except for the movement direction so it doesn’t make sense to me why it would work for one but no the other

I would change the second ‘if’ to ‘else if’ ; I think that should solve the issue (one of them?). If the gameObject gets destroyed, it won’t try to access the animator.
Because you’re new – Destroying a gameObject occurs at the end of the frame.

Since it seemed like you were expressing some other problems, would you like to add those, if this part is resolved with this change?
I mean, I got a bit lost in what you were saying :slight_smile: What isn’t deleting and was that code posted already or it’s somewhere else? :slight_smile:

Hi methos5k thanks for the reply.

Tried changing the if to an else if and it is still the same.

The Gameobjects the enemy script is attached to. What Im finding really strange is that the code is pretty much identical to the script attached to gameobjects called playerminions and it works fine on them.

The code that isn’t working is the ienumator code posted above.

What started this coroutine?

This is a while(true) loop, so it will keep looping endlessly until something stops it. What’s your exit condition?

Actually, destorying a UnityObject just flags it for deconstruction. it could be destroyed immediately or several frames later. this is because the Object data is stored on the C++ side and C# and C++ can’t be fully synced. so when the object is truely destroyed is inconsistent. and depending on how you check for null you might get a wrong answer, (which is happening here).

@SprayNpraY The fact that its working on minions and not enemies can simply be coincidence (as in your minions may break later as well), be sure to check that code and confirm. Instead of checking if any UnityEngine object is null (including GameObjects), cast it to a boolean and check if its false. if any unityobject casts to false then that means the instance is null or flagged to be destroyed and shouldn’t be used. The “==” operator for UnityObjects are strongly typed so they won’t always get used as you intended if you represent your variables as more abstract types, like interfaces.

casting to boolean isn’t 100% foolproof (if you implement your own boolean casting operators) but its leagues more reliable than the “==” operator. This Null Exception and the “fake null” object is a common topic on the forums and in nearly all of them casting to bool to check for null solves the OP issues.

so instead of:

if(target == null)

use:

if(!target)
//or
if(!(bool)target)

as for your error:

            if(!gameobject) break;
 
            if (hp <= 0)
            {
                Destroy(gameObject);
            }
            if (target == null)
            {
                anim.SetBool("attack", false);
                attacking = false;
            }

though its weird how the coroutine is even running after it was destroyed

1 Like

I did not know that about the bool cast; that’s interesting. I thought I had read that destruction happened at the end of the frame, and while I knew the parts about the c++ vs C#, I thought the ‘==’ was overridden in way to return this result after the frame’s end*. Interesting to learn. :slight_smile:
So, it’s possible, in this scenario that he could “yield break” from the IEnumerator after the Destroy, too, I think…?

The coroutine is called in the start function then keeps continuously looping until the object is destroyed.

Hi JoshuaMckenzi thanks for such a detail response.

I don’t fully understand your suggestions as I’m still learning C# with the == being strongly typed why exactly does that effect it. I have implemented your suggested change so the if statement checks for !target

It works for the playerminion but again isnt working for enemy.

as for the coroutine still running for some reason the gameobject isn’t being destroyed even though the condition is being met for the object to be removed. Which I think you addressed above with it being checked not being met properly through c++ or something (I don’t fully understand your explanation as its outside of my current knowledge). How can I fix this

Thanks.

if you Debug.Log for hp <= 0 does it print there?
If so, add ‘break;’ in there.

For some weird reason I just removed some debug logs within the coroutine and some minor changes it is now randomly working it doesn’t make any sense to me how I’ve fixed it lol.

Another issue I’m having now is once an enemy or a playerminion is destroyed if the enemy or minion is already within the boxcollider they go past it without changing the target.

Whats the best way of being able to change the target to an opposing unit thats closest by that the unit has already collided with, if that makes sense. Heres a screen shot that may help make more sense of what Im trying to code.

Also with the minion and enemy code being almost identical would it be worth creating a parent object for them both to inherit from?

3059670--229840--Defense.png

Hm. Well, glad you kinda got it working. I wouldn’t worry about inheriting anything for the moment, until you’re sure you’ve got this smoothed out and working; no sense in complicating a situation that’s already partially broken.
:slight_smile:
I don’t know the logic you’re looking for, but if you have no target, then a trigger/collision should give you a new target… if you have 2 targets that are really close, is it really that important to change to a new one if you already have one? :slight_smile:

1 Like

its flagged for destruction at the end of the frame. if you, for example call Destroy(gameObject) inside Update that gameObject is still usable for the rest of that frame. then its labeled as a fake null for the next frame and unusable. and some time later C++ eventually releases the data and it becomes a true null.

The Base class UnityEngine.Object has == operators that does comparison from a UnityEngine.Object to another UnityEngine.Object. Monobehaviours and ScriptableObjects both derive from UnityEngine.Object, but you can write a Monobehaviour that also implements a certain interface, a monobehaviour “EnemyScript” implementing ITargetable, for example.

If you store a EnemyScript instance inside a variable ITargetable target, you won’t have access to the same == operators. operators are statically defined and you can’t provide operators that includes interfaces, and even if you could UnityEngine.Object wouldn’t have those specific operators. So when you call “target == null”, the compiler implictily converts that to (ITargetable)target == (ITargetable)null. And UnityEngine.Object doesn’t have a comparison between these two types. what what would happen instead is that the compiler will fallback to using the System.Object == operator (since everything derives from System.Object). which will not return the same thing.

hold a list of opponents that enter the box collider, remove them onexit, when there is no primary target find the next valid enemy in the list, cleaning out any entries that return false (as fake nulls)

1 Like

I see… So, that was very close/the same to what I had thought I knew. That’s good. :slight_smile:

I’ve got it all to work now thank you very much. The code is idenical now other than the movement direction and one targets the other so now Im wanting to implement inheritence so I only need to make changes to one script.

However I’ve never used inheritence within unity and abit unsure the best way of going about it. For example for the attack method how can I make it so the script component it is searching for is the correct one depending on which child inherits the method.

 public void AttackTarget()
    {
        if (target)
        {
        target.GetComponent<Enemy>().hp -= damage;
        }
    }

Or something I’m even more unsure of is getting the collider to detect the correct unit type/script based on which child inherits it

    private void OnTriggerEnter2D(Collider2D collided)
    {
        if (collided.tag == "Enemy")
        {
            opponentCollidedList.Add(collided.gameObject);
            if (!target)
            {
                target = collided.gameObject;
            }
            ChangeState(UnitState.Attacking);

        }
    }

one of two ways, the two classes can inherit from a common interface or a common abstract class. you then call getcomponent for either that interface or that abstract class. interface is better recommended in a general case as they grant a little bit more flexibility. Though there can be times when abstract classes will work as well (for unity it mostly depends if you want some common data to be serialized).

public interface IDamagable
{
    void Damage(float damage);
}

public interface ITargetable
{
    bool Targetable{get;set;}
    Faction Faction{get;set;}
}

public class TargetingBehaviour: Monobehaviour
{
    public List<Faction> targetableFactions;
    private List<IDamagable> targets = new List<IDamageable>();

    protected IDamagable  m_PrimaryTarget;
    public virtual IDamagable PrimaryTarget
    {
        get
        {
            if((bool) m_PrimaryTarget && targets.Contains(m_PrimaryTarget))
                return m_PrimaryTarget;

            if(targets.Count<1) return null;

            targets = targets
                .Where(t=>(bool)t)
                // you can add your sorting here if you want
                .ToList();

            m_PrimaryTarget = targets.FirstOrDefault();

            return m_PrimaryTarget;
        }
    }

    private void OnTriggerEnter(Collider2D collider)
    {
        var target =  collider.GetComponent<ITargetable>();

        if(!target || !target.Targetable) return;
        if(!targetableFactions.Contains(target.Faction)) return;

        var damagable = target.GetComponent<IDamagable>();

        if(!damagable) return;
        if(targets.Contains(damagable)) return;

        targets.Add(damagable);
    }

    private void OnTriggerExit(Collider2D collider)
    {
        var damagable = target.GetComponent<IDamagable>();

        if(!damagable || !targets.Contains(damagable)) return;

        targets.Remove(damagable);
    }
}

I tend to write my scripts with a single purpose so this script only focus on what it can target, it doesn’t attack anything on its own. all it does is handle what you should be targeting right now.

Faction would typically be a ScriptableObject Class that entities can choose to align to. You could extend this even further if you wanted a faction system similar to Fallout/Elder Scrolls games (where an entity is a part of multiple factions). instead of using factions you could simply check against tag is also possible but I find tags pigeon hole your implementation (in that the tag now tightly controls diplomacy between entities making it difficult to be used for other things).

Then your minions and enemies will both have a TargetingBehaviour “component” as a reference. With this targeting behaviour script your Enemy and PlayerMinion scripts simply compose it (a has-a relationship, not an is-a relationship). This is Composition (where one object is composed of other objects, i.e. Has-A relationship) and when you can try and favor composition over inheritance. Enemy and PlayerMinion scripts sound like they are much much more than simple targeting. so instead of inheriting from a TargetingBehaviour they simply have a public reference to it as a sibling component and are composed of it.

public Class Enemy: Monobehaviour
{
    public TargetingBehaviour targetingBehaviour;

    // other code in Enemy script

    public void AttackTarget()
    {
        if(!targetingBehaviour) return;
        var target = targetingBehaviour.PrimaryTarget;

        if(!(target as Monobehaviour)) return;

        target.Damage(damage);
    }
}

So your enemy script doesn’t care how its picking its targets, it just attacks any targets its been given. same for PlayerMinion. When you get right down to it and you make a multitude of scripts with a single purpose and then one script to compose them together, you’ll find that the differences between Enemy and PlayerMinion scripts start to vanish until they both become the exact same script just referencing different components to do the dirty work. The uniqueness between Minion and enemy is not the script itself, but the components its referencing, or simply just the different data in said components. you could just take an enemy and hit it with a spell that just switches its targetableFactions in its TargetingBehaviour and suddenly its a minion.

1 Like

What you have written looks really good but I’m struggling to understand some of it even after re going over some interface tutorials.

for example why is this protected for
protected IDamagable m_PrimaryTarget;

I’m assuming Faction is a class I’d have to create and if so how do Implement it so there are different factions.

 Faction Faction{get;set;}

With the Targeting behavioru script I don’t understand what the !targeting behaviour is checking for isnt that just an instance of a TargetingBehaviour script it doesnt make sense to me why its being intialized in the first place.

and why is target being checked to not be a monobehaviour

 public void AttackTarget()
    {
        if(!targetingBehaviour) return;
        var target = targetingBehaviour.PrimaryTarget;
        if(!(target as Monobehaviour)) return;

Might be obvious to me if I had it explained in more detail but alot of these concepts I’m new to this is really helping me improve my programming though so thank you.

So you know “What” Targeting behaviour does, it chooses a target for you. But there was a possibility that you want to change exactly “how” it chooses its primary target. You can do that via writing a class that inherits from TargetingBehaviour. m_PrimaryTarget is simply a backing field that the class uses to track which target should be used. while the property PrimaryTarget is what is accessed by other classes. Notice that PrimaryTarget is virtual which means it can be overridden in inheriting classes, if it does it’d need access to m_PrimaryTarget.

If you wanted a more purist approach TargetingBehaviour would be an abstract class without the OnTriggerEnter, leaving it to the inheriting classes to handle how and when it chose its targets (with one example being through OnTriggerEnter). thats something thats up to you for how you want it implement it.

using UnityEngine;
[CreateAssetMenu(menuName = "ScriptableObjects/Faction")]
public class Faction: ScriptableObject{}

thats literally it. For the most part you’ll be using Faction Assets as an Enum, this allows your game designers to add in new factions later without having to recompile the code. You can choose to add more data to represent a faction like a string description field, but really the instances are made so that entities can associate their relationships with them. Save the file under “Faction.cs” then choose a folder via unity to create the assets (the [CreateAssetMenu] will make it appear under “Create>ScriptableObjects>Faction”.

Also I didn’t mention this, but your entities will also need a Monobehaviour that implements ITargetable so that TargetingBehaviour can work on them.

public class Targetable: MonoBehaviour, ITargetable
{

    [SerializeField] protected bool m_targetable;
    [SerializeField] protected Faction m_faction;

    public bool Targetable
    {
        get{return m_targetable;}
        set{m_targetable = value;}
    }
    public Faction Faction
    {
        get{return m_faction;}
        set{m_faction= value;}
    }
}

targetingBehaviour is something you can set (and usually will) via the inspector. In a sense this is called Injection (where an instance is given to the class instead of the class having to go look for that instance). You’ll see this a lot in my code, and I go with the first assumption that the input might not be valid,

While its the responsibility for an outside source (inspector) to give me the instance, its my(i.e. the class’s) responsibility to ensure that input is valid. there is a possibility that targetingBehaviour was never set or was destroyed. if so then (!targetingBehaviour) will return true and break early, preventing any null exception from being thrown. The exact reason for the data being invalid doesn’t matter, just that if it is invalid, don’t do anything.

If you remember in the previous code PrimaryTarget is represented as IDamagable not as a Monobehaviour. Here I was casting it to a monobhehaviour and then using Monobehaviours boolean cast to determine if the the instance is not null. This is actually a mistake in my part, in that the Enemy script is making assumptions of what type the PrimaryTarget is. you can have classes that implement IDamageable, but not inherit from Monobehaviour. in this sense the Enemy script was taking on more responsibility than it should by “knowing” PrimaryTarget is always a Monobehaviour. if you recall:

        get
        {
            if((bool) m_PrimaryTarget && targets.Contains(m_PrimaryTarget))
                return m_PrimaryTarget;
            if(targets.Count<1) return null;
            targets = targets
                .Where(t=>(bool)t)
                // you can add your sorting here if you want
                .ToList();
            m_PrimaryTarget = targets.FirstOrDefault();
            return m_PrimaryTarget;
        }

TargetingBehaviour.PrimaryTarget already handles “fake nulls” for you, it will only send you either a valid instance or a true null so enemy script can simplify its validation and also reduce some coupling it has with TargetingBehaviour:

public void AttackTarget()
    {
        if(!targetingBehaviour) return;

        var target = targetingBehaviour.PrimaryTarget;
        if(target == null) return;

        target.Damage(damage);
    }

A lot of it comes down to which script has what responsibility and how does working in unity affect that.

Mostly it boils down to a few coding principals. Look into S.O.L.I.D. programming to help you with a few important core software engineering principals. There are tons more principals but by following these five you usually end up also adhering to a few others. You’ll see that the code I wrote basically follows these concepts, with a couple of trade-offs due to working in the Unity environment.

1 Like

Going to try implementing these suggestions the best I can, I understand most of it but when I then goto try and implement it I feel lost everytime. Do you have anything aswell as S.O.L.I.D you recommend I go learn so I can understand these concepts better.

For example

using UnityEngine;
[CreateAssetMenu(menuName = "ScriptableObjects/Faction")]
public class Faction: ScriptableObject{}

I understand how to use an enum and tried that code in my game but I’m not sure how Id implement a enum and then how exactly I practically use it when its coded.

This trigger collider checks if target is a Targetable then if there the is already a damgable target to add the collided object?

 private void OnTriggerEnter(Collider2D collider)
    {
        var target =  collider.GetComponent<ITargetable>();
        if(!target || !target.Targetable) return;
        if(!targetableFactions.Contains(target.Faction)) return;
        var damagable = target.GetComponent<IDamagable>();
        if(!damagable) return;
        if(targets.Contains(damagable)) return;
        targets.Add(damagable);
    }

Also do you know where I can learn about injection that you mentioned above whenever I search for it, it comes up with a microsoft programme called unity rather than the game engine unity.

There are 1 or 2 other little areas I’m unsure of but don’t want to bombard you with 100 different questions at once. You should make youtube tutorials learning alot from this. I will have to play about with it I guess and see what I can figure out thanks again.

With the Faction Enum, its exactly the Extendable Enums pattern described in this video (around 23.38)

you’re creating an Asset file that represents a Faction and then your code will simply check if two references equal each other (as done in the OnTriggerEnter example)

an object that you Enter with must pass 5 tests before TargetingBehaviour will say that you are allowed to attack it.

  • It must have an ITargetable Component
  • It must be currently targetable
  • the faction the ITargetable belongs to must also be in the list of factions this script is assigned to target
  • It must have an IDamagable Component
  • it must not already exist in the list of valid targets

after passing all these tests the target will be added to the list of targets the entity will be allowed to attack, from there it will choose a primary target from that list of targets when asked for.

Injection, Dependency Injection(DI), or Inversion of Control(IOC) all mean the same thing. In fact the “D” in SOLID stands for Dependency Injection. and its a practice thats not specific to just Unity. so you’ll see it used a lot in several applications, not just unity.

1 Like