Game Object not self destroying after Destroy(gameObject)

Here’s a video that shows what’s happening: Click Here (YouTube)

I don’t know why this is happening. I suspect it might have something to do with using a UnityEvent that Invokes a function within a component attached to the same Game Object as the script that calls that event, but I have no clue on how that works or how I should fix it. I tried disabling the HealthManager script before destroying the Game Object; no luck. Tried calling Destroy(gameObject) every frame if health gets to 0; no luck, got a “GameObject you are trying to access has been destroyed” error. And why does my code work almost every time, but it just randomly fails (that’s what really bugs me out)? Does anyone have an idea of how to fix this?
I got this in the middle of a game jam, so it’s really stressful :confused:

Here are the pieces of code highlighted in the video:
(HealthManager.cs)

using System;
using System.Collections;
using System.Collections.Generic;
using System.Security.Cryptography;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.SceneManagement;

public class HealthManager : MonoBehaviour
{
    public float maxHealthPoints;
    public float healthPoints;
    public float defense = 1;
    public GameObject hitParticles;
    public GameObject deathParticles;
    public bool isDead;
    public HealthBar healthBar;

    public UnityEvent onDeath;

    private void Start()
    {
        if (maxHealthPoints == 0)
            maxHealthPoints = healthPoints;

        if (healthBar)
        {
            healthBar.SetMaxHealth(maxHealthPoints);
            healthBar.SetHealth(healthPoints);
        }
    }

    public void ReceiveDamage(float amount)
    {
        healthPoints -= amount / defense;
        if (healthBar)
            healthBar.SetHealth(healthPoints);
        if (healthPoints <= 0)
        {
            Destroy(Instantiate(deathParticles, transform.position, Quaternion.identity), 1);
            healthPoints = 0;
            isDead = true;
            onDeath.Invoke();
        }
        else
            Destroy(Instantiate(hitParticles, transform), 1);
    }

    public void ReceiveHealth(float amount)
    {
        healthPoints += amount;
        if (healthPoints > maxHealthPoints)
            healthPoints = maxHealthPoints;
        if (healthBar)
            healthBar.SetHealth(healthPoints);
    }
}

(E2.cs - Enemy Behaviour)

using System;
using System.Collections;
using System.Collections.Generic;
using Pathfinding;
using Pathfinding.Util;
using UnityEngine;
using UnityEngine.Events;

// Enemy 2: Runs towards player with a knife. Low Health, Mid Damage, Mid Speed, Low Defense, Mid Range.

public class E2 : MonoBehaviour
{
    public int scorePoints;
    
    public string targetTag;
    public float angleOffset;
    
    private Item knifeItem;
    private Knife knife;
    private AIPath _aiPath;
    private AIDestinationSetter _aiDestination;

    private GameObject target;

    private void Start()
    {
        _aiPath = GetComponent<AIPath>();
        _aiDestination = GetComponent<AIDestinationSetter>();
        
        knifeItem = GetComponentInChildren<Item>();
        knife = GetComponentInChildren<Knife>();
    }

    void Update()
    {
        target = GameObject.FindWithTag(targetTag);
        if (target)
        {
            if (Vector3.Distance(transform.position, target.transform.position) <=
                transform.localScale.y / 2 + knife.range)
            {
                _aiPath.enabled = false;

                Vector3 dir = target.transform.position - transform.position;
                float angle = Mathf.Atan2(dir.y, dir.x) * Mathf.Rad2Deg + angleOffset;
                transform.rotation = Quaternion.AngleAxis(angle, Vector3.forward);

                knife.attack = true;
            }
            else
            {
                _aiPath.enabled = true;
                _aiDestination.target = target.transform; // For when the target changes.
                knife.attack = false;
            }
        }
    }

    public void OnDeath()
    {
        PlayerPrefs.SetInt("lastScore", PlayerPrefs.GetInt("lastScore") + scorePoints);
        
        knife.attack = false;
        knife.canAttack = true;
        Item iog = Instantiate(knifeItem.selfPrefab, transform.position, transform.rotation).GetComponent<Item>();
        iog.UpdatePickupbleTrigger(true);
        iog.UpdateActionCollider(false);
        iog.UpdateMainBehaviour(false);

        Destroy(gameObject);
    }
}

Hi!

I couldn’t find the issue within your script, however I would like to point out that moment in your video:


So, what happens is that you are killing other type of enemies and at the same time your future undestroyable enemy loses its sword.


It can be coincidence, but as we can see here:


Your death animation is still playing (the explosive one), but it fails to Destroy even though animation played twice (2-nd and 4-th).

Therefore I assume next thing: for some reason sometimes by destroying one of your enemies your another enemy loses(?) its sword, so when you Invoke Death it gets called, but it throws an error here:

 Item iog = Instantiate(knifeItem.selfPrefab, transform.position, transform.rotation).GetComponent<Item>();

Where it should create prefab of your sword therefore the Destroying never reaches since code stops.


You can test it out by commenting out for a time the whole iog section in OnDeath() and I assume you will not encounter the issue.


I hope it will help you.

You can try instantiating particles not with transform but with transform.position with quaternion.identity.

It can be because when a gameobject is destroyed, info about transform is lost, but its position is still there untill all of the behaviour attached to that object is executed.

@UDN_7bcbe08e-783e-45c6-a9b2-4e942df1984b

Ok, I figured it out. I’m really sorry if you’re having this problem and are reading this thread, because in my case it was just due to my stupidity :confused:
Every item on my game has a “isPickedUp” bool. When that bool stays false for too long, the item self destructs, so that the items that were dropped on the ground clean themselves up. When the player picks an item up (or throws it away) the variable is updated. I, however, forgot to do so with the enemies. So every enemy would lose their item if they survived long enough.
I would like to thank and apologize @ADiSiN and @Dev1910 for their time.