I see there are soooooo many humans encounter this issue whose did feedback to the Unity devs already. But while it is actually possible, they get a response of “no, we cannot”. I mean they are the one who should be responsible for solving that issue. Not us! I won’t be surpised if someone just come out and say “this is not an issue, it is expected!” and after developing a game when they face this issue, they probably waste their time by syncing a custom system with Unity’s system…
Stop it. Keep it real. This is solvable and it should been solved.
After hours like i said, I actually implemented my own system due to that “by design” problem. This is what happens when you use external physics engine after all, suffer the consequences
As Melv said:
You know what, it is working so good. I will also implement for OnCollisionEnter too. They also have a problem about not getting called in children. These things are headache. Shouldnt be there. Unity should have some extension package that actually implements those things by their self since they have the internal access. If you dont perform an execution that depends on order, this will work perfect as needed.
There are really more to talk about but uh i am bored about internal bugs and non-sense “oh they cannot, oh we cannot” sentences.
I am not grateful for wasting time to implement those…
I ended up needing this again and I made my own script for it.
You just need to subscribe during OnTriggerEnter and unsubscribe during OnTriggerExit.
No need to do it OnDisable.
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// If you need a trigger to know when its detected Colliders are disabled, use this class.
/// The callback is called when the Collider is disabled.
/// The typical usecase is to subscribe actions during OnTriggerEnter, and unsubscribe actions during OnTriggerExit.
/// But it can be used in other cases.
/// The caller needs not unsubscribe during OnDestroy/OnDisable, as the class will automatically clean up invalid subscriptions.
/// </summary>
public class OnDisableListener : MonoBehaviour
{
/// <summary>
/// Tracks the action and the subscriber GameObject for event cleanup purposes.
/// </summary>
public struct Subscription
{
public Action<Collider> Action;
public GameObject Subscriber;
public Subscription(Action<Collider> action, GameObject subscriber)
{
Action = action;
Subscriber = subscriber;
}
}
// List to store the subscribed actions along with the subscriber GameObject
private readonly List<Subscription> Subscriptions = new();
private Collider Collider;
private void Awake()
{
Collider = GetComponent<Collider>();
if (Collider == null)
{
Debug.LogError("OnDisableListener is attached to a GameObject without a Collider component.");
}
}
/// <summary>
/// This should be called OnTriggerEnter to start listening for when the Collider is disabled.
/// </summary>
public void Subscribe(Action<Collider> _action, GameObject _caller)
{
Subscriptions.Add(new Subscription(_action, _caller));
}
/// <summary>
/// This can be called to manually stop listening before the Collider is disabled.
/// </summary>
public void Unsubscribe(Action<Collider> _action, GameObject _caller)
{
Subscriptions.RemoveAll(sub => sub.Action == _action && sub.Subscriber == _caller);
}
public void Unsubscribe(GameObject _caller)
{
Subscriptions.RemoveAll(sub => sub.Subscriber == _caller);
}
private void OnEnable()
{
StartCoroutine(CleanupCoroutine());
}
private void OnDisable()
{
StopCoroutine(CleanupCoroutine()); // Stop the coroutine when the object is disabled
OnDisableLogic();
}
/// <summary>
/// When the object is disabled, all listeners are notified and the subscription list is cleared.
/// </summary>
private void OnDisableLogic()
{
// Call the action for all active subscribers
foreach (var sub in Subscriptions)
{
if (sub.Subscriber != null)
{
sub.Action?.Invoke(Collider);
}
}
Subscriptions.Clear();
}
private IEnumerator CleanupCoroutine()
{
while (true)
{
CleanUpInactiveSubscribers();
yield return new WaitForSeconds(5f); // Adjust time as needed
}
}
/// <summary>
/// Periodically cleans up inactive or destroyed subscribers.
/// </summary>
private void CleanUpInactiveSubscribers()
{
Subscriptions.RemoveAll(sub => sub.Subscriber == null || !sub.Subscriber.activeInHierarchy);
}
}
public static class OnDisableListenerExt
{
public static void OnDisable_Subscribe(this Collider _col, Action<Collider> _action, GameObject _caller)
{
var disableListener = _col.GetComponent<OnDisableListener>() ?? _col.gameObject.AddComponent<OnDisableListener>();
disableListener.Subscribe(_action, _caller);
}
public static void OnDisable_Unsubscribe(this Collider _col, Action<Collider> _action, GameObject _caller)
{
var disableListener = _col.GetComponent<OnDisableListener>() ?? _col.gameObject.AddComponent<OnDisableListener>();
disableListener.Unsubscribe(_action, _caller);
}
public static void OnDisable_UnsubscribeAll(this Collider _col, GameObject _caller)
{
var disableListener = _col.GetComponent<OnDisableListener>() ?? _col.gameObject.AddComponent<OnDisableListener>();
disableListener.Unsubscribe(_caller);
}
}