- Home /
What's the best workaround for disabled colliders not firing OnTriggerExit events?
I realize that disabled colliders do not trigger OnTriggerExit.
This is an issue for me because when the main character in my game dies, his collider is disabled until he respawns. Another case is with object pooling where a slain enemy is disabled, but if it was in a collider that was tracking it and it respawns elsewhere, the object it was in will still think it is in there.
So far my workaround has been having objects such as the player or enemies keeping a list of functions that holds all of the OnTriggerExit methods of colliders they are in, and having all of those functions called and the list cleared upon their deaths/disabled state.
Another possible technique I've considered is instead of disabling the collider right away, maybe I could move it to a space way outside of the rest of the game world and then disable it after the next FixedUpdate, to ensure that OnTriggerExit is called first. This seems kind of hacky to me but looks much better in the code than the workaround I mentioned above.
Does anyone have any better ideas of how to deal with this issue? Maybe I am missing a more elegant solution. I'd love to hear your input.
Answer by etopsirhc · Sep 12, 2016 at 06:20 AM
simplest solution would be to add void OnDisable() to the object you want to disable, then force it to call OnTriggerExit on itself so it does exit before it gets disabled.
I don't believe this would solve the problem. Let's say that the object we want to disable is touching some other objects. When the object is disabled, we want those other objects to realize it is no longer inside of them, and call their OnTriggerExit methods. So the issue is not resolved by the disabled object calling its own OnTriggerExit function, but ins$$anonymous$$d calling the OnTriggerExit functions of the objects it is touching. I'm able to work around this as I mentioned above, but I was looking for a cleaner method.
Answer by Masterio · Sep 12, 2016 at 08:20 AM
[1.] Personally i am using this solution (i've hope it is clear):
I have variable in player game logic:
_isDead = false;
if it is true then scripts stops , if i place in code 'if statement' like the:
if(Player.isDead)
{return;}
It stops executing all AI on dead player body.
[2.] If you want to use interfaces you can create one for this task.
. . .
public interface IPlayerRespawn
{
void OnPlayerDie();
}
next i wrote example classes (added some debug functions you can check how it works on kill):
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class Player_Test : MonoBehaviour
{
private static List<IPlayerRespawn> _iPlayerRespawns = new List<IPlayerRespawn>();
#if UNITY_EDITOR
public bool _debugKill = false;
void Update()
{
if(_debugKill)
{
_debugKill = false;
Kill();
}
}
#endif
void Kill()
{
ExecuteIPlayerRespawn();
}
/// <summary>
/// Registers the IPlayerRespawn implementation.
/// </summary>
public static void RegisterIPlayerRespawn(IPlayerRespawn iPlayerRespawn)
{
_iPlayerRespawns.Add(iPlayerRespawn);
}
// Executes all registered instances.
private static void ExecuteIPlayerRespawn()
{
foreach(IPlayerRespawn i in _iPlayerRespawns)
{
i.OnPlayerDie();
}
}
}
and example enemy class:
using UnityEngine;
using System.Collections;
public class Enemy_Test : MonoBehaviour, IPlayerRespawn
{
void Start()
{
// just place it in start or awake
Player_Test.RegisterIPlayerRespawn(this);
}
private void SomeMethodToExecute()
{
Debug.Log("Enemy "+gameObject.name+" executed.");
}
#region IPlayerRespawn implementation
public void OnPlayerDie()
{
SomeMethodToExecute();
// you can add (f.e.) back to spawn position, recover hp etc.
}
#endregion
}