You could implement something using the Update method like e.g.
public class ActiveSelfWatcher : MonoBehaviour
{
private Dictionary<ActiveSelfProvider, bool> _lastActiveSelfState = new Dictionary<ActiveSelfProvider, bool>();
private void OnObjectBecameActive(GameObject obj)
{
Debug.Log($"{obj.name} became active!", this);
}
private void OnObjectBecameInactive(GameObject obj)
{
Debug.Log($"{obj.name} became inactive!", this);
}
private void Update()
{
// Iterate through all registered instances of ActiveSelfProvider
foreach(var provider in ActiveSelfProvider.Instances)
{
// pre-cache the GameObject reference
var obj = provider.gameObject;
// pre-cache the current activeSelf state
var currentActive = obj.activeSelf;
if(!_lastActiveSelfState.TryGetValue(provider))
{
// we don't know this provider until now
// TODO here you have to decide whether you want to call the events now once for this provider or not
// TODO otherwise it is only called for providers you already know and changed their state
}
if(currentActive != _lastActiveSelfState[provider])
{
// the state is not the one we stored for this instance
// => it changed its states since the last frame
// Call the according "event"
if(currentActive)
{
OnObjectBecameActive(obj);
}
else
{
OnObjectBecameInactive(obj);
}
}
// store the current value
_lastActiveSelfState[provider] = currentActive;
}
}
}
This is your watcher class you currently already have anyway.
Then on all the objects you want to be able to watch you use
public class ActiveSelfProvider : MonoBehaviour
{
private static readonly HashSet<ActiveSelfProvider> instances = new HashSet<ActiveSelfProvider>();
public static HashSet<ActiveSelfProvider> Instances => new HashSet<ActiveSelfProvider>(instances);
private void Awake()
{
// register your self to the existing instances
instances.Add(this);
}
private void OnDestroy()
{
// remove yourself from the existing instances
instances.Remove(this);
}
}
If this is "efficient enough" for you use case you would have to test ;)
If you want to go super fancy, someone once made a Transform Interceptor .. a quite nasty hack which on compile time overrules parts of the Unity built-in Transform property setters to hook in callbacks.
One probably could create something like this also for SetActive ;)
Note: Typed on smartphone but I hope the idea gets clear