I am wanting to fire events at certain times in my animation, but I noticed that events will only fire if the animation is actually playing (which makes sense) – but I also want to set my Animator state to “Cull Completely” for the culling mode because it saves me a large amount of performance.
Ideally, I’d like to be able to fire events in sync with the animation timings, even if the animation is culled. This way, when units are offscreen, they still fire events. As it stands now, if my units/characters are not currently being viewed by the player, they don’t fire their events at all.
There is one way I can see off the bat: Separating the Event Animations from the Regular Animations.
It’s possible to have multiple Animators on different levels of your object, and in more recent versions of Unity, you can have Animators that only have state. It’s also possible to create custom animations that don’t move anything, just contain event triggers.
So you could potentially have a “mirrored” Animator potentially on the same gameobject, although this has repercussions with GetComponent<>() and assigning things in the editor) that has the same states and parameters, with only “event” versions of your animations, and it does not culled.
The main difficulty in using such a system would be ensuring that when an object being animated in this manner gets culled/unculled, the main Animator gets resynced properly so there’s no discernable difference.
This is still technically an animator componenent and will definately still have overhead, you may want to profile with this route to see if the savings are tangible.
There will be overhead for 2 animators when operating normally, but overall you’ve just moved the events into another statemachine.
Animation Layers - It may be possible to do this with Animation Layers instead of 2 animators. One layer contains the main animations, one contains the event versions, another contains the main animations. Instead of culling completely, the regular animation layer is weighted to 0 or masked out completely (and therefore isn’t processed much, if at all. I believe a 0 weighted layer is skipped entirely).
Either way you slice it, this seems like a better way than having events driven by a separate scripting system entirely.
Those are very interesting points, thanks recursive. You’re right, I’ll have to do some testing to see if there is any overhead on using two Animators, and if so, how much.
Also, I’m wondering now about the Culling Mode of “cull update transforms” now? In the documentation it says this mode simply doesn’t play any of the IK info and it doesn’t update bone positions etc, but I’m wondering if the animation events still play in this mode? I tried testing it last night, but I forgot to do it in-depth in one of my play-tests, so I was just wondering if you might know. If the animation events do still play in this mode, but it saves me performance, that might be all that I need. If the events don’t play though, then I’ll have to try what you suggested above.
As you stated, how could I make sure my “GetComponent<>()” references get the correct Animator? And how do you “resync” an Animator. These seem like things that may not even be worth the amount of effort needed to make them happen. But I’ll have to decide ultimately.
I can’t really test the how the animation culling works atm, as I’m mostly in a 2D/UI based project at this time, if your testing reveals the events fire anyway, then my suggestions are a moot point.
As for the GetComponent<> call, you would probably have to either use manually assigned references, or use GetComponents(), if the AnimatorControllers have the same parameters and states, then you can pipe the same commands and settings to both.
Resyncing the animator would probably involve forcing the normal animator into a matching state and immediately jumping to the correct playtime when the animator becomes visible.
I’m still more of a fan of the layer-based solution, as it involves only one animator and no syncing, but I’d still check to see if events are fired even if Culling is enabled.= before going down this route.
If you get a chance to test, let me know what the results are.