How to handle enemy dying inside trigger collider?

I’ve created a simple target management system that keeps a list of enemies inside the player’s trigger collider. The first item in the list is the current target and the target lock is placed in this gameobject… and so on.

The problem is when an enemy dies inside the trigger collider. It doesn’t produce an OnTriggerExit event and so never leaves the target’s list. So how do I tell my player that that enemy no longer exists?

Any advice greatly appreciated.

I’m not sure why I cant get the above working… Anyway, I’ve put the effort into really learning about events and delegates, by watching and reading as many different tutorials as possible. All thanks to @garcialuigi pointing me in the right direction. To finally understand it now (at least at a fundamental level) is hugely rewarding and feels great!

So, for anyone following and looking to do similar, here’s the trimmed final code that is tested and working.

// EnemyHealth.cs with unrelated stuff removed

public class EnemyHealth : MonoBehaviour 	
{
	// Set up a delegate called onDeathAction which passes on the enemy GameObject.
	// ie tell it which enemy has died
	public delegate void OnDeathAction(GameObject enemy);

	// Set up the event called OnDeath to be published, using the delegate OnDeathAction
	public static event OnDeathAction OnDeath; 

	...
	
	public void TakeDamage(int amount)
	{

		...

		if (currentHealth <= 0) 
		{
			// if OnDeath has subscribers. 
			// ie functions in other classes registered to listen for the event
			if(OnDeath != null)
			{
				// Announce enemy death to subscibers
				OnDeath(this.gameObject);
			}
			...
		}
	}	
}

and

// PlayerTargeting.cs with unrelated stuff removed

public class PlayerTargeting : MonoBehaviour {

	// set up variable for new list
	public List<GameObject> acquiredTargets;

	// set up variable for selected target
	public GameObject selectedTarget; 

	void Awake ()
	{
		// create new targets list
		acquiredTargets = new List<GameObject>();
	}


	void OnTriggerEnter(Collider col)
	{
		//if collision tagged as enemy and target is not already in targets list
		if (col.tag == "Enemy" && !acquiredTargets.Contains (col.gameObject))
		{
			// add target to targets list
			acquiredTargets.Add (col.gameObject);		

			// Register EnemyDied function with OnDeath event in EnemyHealth
			// ie Do EnemyDied() when OnDeath event occurs
			EnemyHealth.OnDeath += EnemyDied;


			// Refresh Targets list
			// makes sure selected target = acquiredtargetslist[0]
			UpdateSelectedTarget();

		}
	}
	
		
	void OnTriggerExit(Collider col)
	{
		//if collision tagged as enemy and target is not already in targets list
		if (col.tag == "Enemy" && acquiredTargets.Contains (col.gameObject)) 		
		{ 
			// remove target from list
			acquiredTargets.Remove (col.gameObject);		

			// Unregister EnemyDied function with OnDeath event in EnemyHealth
			// ie Don't do EnemyDied() when OnDeath event occurs
			EnemyHealth.OnDeath  -= EnemyDied;

			// Refresh Targets list
			UpdateSelectedTarget();
		}
	}


	
	public void EnemyDied(GameObject enemy) /* Note the same parameters as the delegate */
	{
		// if dead target is in list
		if(acquiredTargets.Contains(enemy))
		{
			// Remove dead target from targets list
			acquiredTargets.Remove(enemy);
		}

		// Refresh Targets list
		UpdateSelectedTarget();
	}
}

Hope this helps someone!

Thanks,
Dave

Seems right IMO that the enemy doesn’t exited the trigger, he is still there, doesn’t matter that he is dead.
I think you need to tell your player that the enemy is dead in another way.

  • With a flag, state;
  • You can predict that the enemy will die when attacking it;
  • You can register your player to a callback(delegate) in the enemy, or in some manager. When the enemy dies, it dispatch this delegate, then the player will know that a specific enemy just died.

Lets try one example, could be something like this.
But I believe that there is a lot of ways you could do what you want.
You can have a central manager script, where enemies call a method to tell that they died.
Etc.

Delegate is a function pointer. Awesome to work with, dependency injection, lambda expressions, functional programming. I recommend you learning it, might not be the best option for now, but of course you will need it in other cases. :slight_smile:

public class EnemyHealth
{
	// Action<T> is a built in C# generic delegate
	public Action<EnemyHealth> GotKilled;
	
	public void TakeDamage()
	{
		...
		if(damageKilled)
		{
			isDead = true;
		
			// If there is someone registered in the Action/delegate
			if(GotKilled != null)
			{
                             // Tell that I died
				GotKilled(this);
			}
		}
	}
}

public class PlayerTargeting
{
	private void OnTriggerEnter(Collider other)
	{
		...
		// Register
		enemyTriggered.GotKilled += EnemyGotKilled;
		...
	}
	
	private void OnTriggerExit(Collider other)
	{
		...
		// Unregister
		enemyTriggered.GotKilled -= EnemyGotKilled;
		...
	}
	
	private void EnemyGotKilled(EnemyHealth enemyHealthKilled)
	{
		// Remove from list, etc
	}
}