Well, and what if I have multiple colliders? Now I have to disable all of them, keep track of them, etc. Observer solves all of it: it would allow us to subscribe to specific colliders and not just to all of them, then if we want to subscribe to all of them, we could to it in a rigidbody, or if not I’m sure there could be another way to do it: like a separate component AllColliders, idk. But the observer would solve all the issues with the current system: inability to subscribe to a specific collider on a game object, inability to unsubscribe from the events.
It’s not more performant in the long run if you’re cleaning your code: subscribing and unsubscribing to events when it’s needed. In the end you end up with a much, much more performant system than with messages, because you’re not calling a bunch of empty functions when they aren’t needed, you’re only calling functions that are absolutely should be running. Imagine you have 1000 objects, they’ll have many, many different events. With the messages you’re calling all 1000 of them no matter what. With the observer you’ll probably be calling around 200 out of them at any point in time.
I ended up implementing the Observer on my own, anyway, because I need multiple colliders doing multiple things and then reporting back to the main object. So, I have this hierarchy:
MainCharacterGameObject
AttackColliderGameObject
ReceiveHitColliderGameObject
Then, in the each of collider’s game objects I have BoxCollider2D and then my own component that looks like this:
public class ColliderReporter : MonoBehaviour {
public delegate void CollisionEventDelegate(Collider2D Other, GameObject OwningGameObject);
public event CollisionEventDelegate OnOverlappingStarted;
public event CollisionEventDelegate OnOverlappingEnded;
[HideInInspector] public Collider2D Collider;
void Awake() {
Collider = GetComponent<Collider2D>();
}
[UsedImplicitly]
void OnTriggerEnter2D(Collider2D Other) {
OnOverlappingStarted?.Invoke(Other, GetOtherOwningGameObject(Other));
}
[UsedImplicitly]
void OnTriggerExit2D(Collider2D Other) {
OnOverlappingEnded?.Invoke(Other, GetOtherOwningGameObject(Other));
}
GameObject GetOtherOwningGameObject(Collider2D Other) {
var ColliderReporter = Other.GetComponent<ColliderReporter>();
GameObject OwningGameObject = ColliderReporter ? ColliderReporter.gameObject.transform.parent.gameObject : Other.gameObject;
return OwningGameObject;
}
public void EnableCollider() {
Collider.Enable();
}
public void DisableCollider() {
Collider.Disable();
}
}
This way I can subscribe and unsubscribe to collisions in the main game object component and immediately get access to the actual owning game object of the other colliders, not the empty game object the collider lives on.
Well, this system was made using the recommendations on this forum to make empty child game objects with colliders to be able to have different colliders on different channels and detect which one was hit in the main game object. We obviously don’t want those child game objects know about the parent, so I made this component and prefabs, so I can quickly put those hurt/hit boxes on different game objects and report to the main game object. Works well-enough for now.
But, of course, all of those issues wouldn’t exist if Unity allowed us to have SceneComponents like Unreal with relative transforms and allowed to detect collisions on different colliders separately, and implemented Observer pattern on the colliders. This way we’d be able to have a bunch of colliders on the same game object with relative transforms, and we’d be able to just subscribe to the events on those colliders. The system would be many times simpler than what we have to work with right now: a whole hierarchy of whole game objects with a separate collider component on each, and a separate collision detection component on each, because how else are you going to get the events from the colliders?
That’s not new programmer-friendly at all. This is the exact opposite. Like yeah if you need just one collider it’s simpler, but once you finish tutorials, in around 2 hours you’ll want multiple colliders on your character and now you have to build the system above, there is no way around it. Meanwhile, with the observer, it’s just as easy, just subscribe on Awake: BoxCollider2D.OnColliderTrigger2D += BoxCollider2D_OnColliderTrigger2D;
. This is very easy, and it scales so well, unlike this way with messages.
They can keep the current system working and add a new one with proper C# events. Everyone who wants to work with the current system can continue working with it. But then people who want can work with the better system, as I described above.
Well, for Unity messages, there are multiple fixes for this problem that I found so far:
We can override SystemBase: SystemBase overview | Entities | 1.3.8
And then we can also override Player Loop: How to create an early and a super late update in Unity - C# and Unity development
That will work for Awake, Start, Update and all the other events like that, from what I understand. But I’m not sure how we could only call collisions only on enabled objects.