In my current project I am using CSharp events in order to tell all moving objects in the scene how far the player moved. The objects only move by the amount the player moved, otherwise they stand still. My question is, is that a performant way of dealing with this or is it a total performance killer?
Would it be faster if every object asks the amount the player moved in their update - or does it not matter?
I find it very nice to decouple things and I’m pretty happy with events in general, just not sure if I should broadcast the information every frame to every object?
Thanks!
You could profile it I guess. How many objects are we talking about? Update() is itself quite slow when there’s large numbers of objects involved. It’s probably comparable or even slightly better than Update()
And as usual there’s only one way to find out. Scale it up in large numbers, build a development build and attach the profiler. You shall find your answer.
That sounds really promising. There should be around 300 objects in a scene and it must be smooth on mobile.
By “CSharp Events” I guess you talk about ordinary delegates? If that’s the case there’s no easy answer because there are several aspects you have to consider. From a pure execution point of view they are fast and as PraetorBlue said probably a bit faster than Unity’s own Update callback. However the setup / change cost when you subscribe / unsubscribe to / from a multicast delegate is quite high and gets higher the more listeners are subscribed to the same delegate.
So if you just set up the events once and they are kept like this everything should be fine. However frequent subscriptions and unsubscriptions are quite expensive and produce quite a bit of garbage. If you have a large number of listeners using a custom List<System.Action>
is usually better.
In your particular case, it makes sense to have that data “served on a platter”. So it’s more data-oriented. If you have an “evaluator” who reserves some space, then uses this space to serve player-oriented data for any other object, you can rely on everyone else having “their eyes” set to the same repository, which massively increases the likelihood of having certain data in a near cache.
If you’re extensively benchmarking, you may try this approach, see if it works. Creating events is a killer for this task, redirecting method pointers (delegates) is better, however having data constantly sit at the center of everything, without ever reallocating or having to clean garbage might be the winner.
What bunny83 said with regards to events is true, and I like the brutal simplicity of keeping a list of generic delegates, however not having that list in the first place is even better.
Regarding the sub/unsub logistics, if you do want a quick-firing custom event system, you can always build a custom solution based on bunny83’s concept. The key change would be to let it auto-recycle memory without de/allocating in the runtime. And obviously you’d want to sub listeners before heavy duty.