My enemies have 3 attacking states; anticipation, attack, recovery. Each attack animation has all 3 of these states.
But I also have some code that relies on when the enemy goes from anticipation to attack for example, and ofc I want that to be the same frame my animation goes from anticipation to attack.
Atm I set these values in my enemy inspector, so let’s say I change the animation so anticipation now ends on frame 12 instead of frame 8. Now I also have to change my anticipationTime float in the enemy inspector from 8 to 12.
this drives me a bit nuts, I hate having to change in 2 places. Is there a smarter way to do this?
One caveat with animation events is that, depending on your state machine, animation state can be short-cutted and then the animation events might not fire.
One example I came across- I had an “attack begin” and “attack end” event. These would fire off at different times when the player is attacking and the attacking animation is playing. If the player is attacked while they are attacking, though, the animation state machine would jump straight to the “getting hit” animation, and so the attack animation would never finish and the “attack end” event would never fire. This may never be a problem for you, but something to keep in mind.
Yeah, this is why its plan B I use triggers a lot for vfx, sound, etc. But try to be rly careful about using them for anything that involves game logic.
I could always add an animation behaviour that resets the states on behaviour exit, there are so many ways to solve this scenario Im just trying to find the cleanest least error prone one
While animations events are the usual way to fix this I always recommend against them for a variety of reasons. The biggest being what was already mentioned about the events not even being reliable. Think of them as tools for other related effects like synced sound effects and not something that you interact with core gameplay mechanics. They are also not so great for performance as they generate garbage. Not as big a problem as before if you are using the new incremental GC but garbage is garbage and since Unity doesn’t compact afterward it will eventually cause problems with fragmented memory the longer the game runs no matter what. Finally, it means your gameplay code is now often tied very hard into the animations of your game which makes it harder to adapt. You likely won’t be able to use it in future projects, procedual changes or mass changes to large sets of data will be harder or maybe even impossible. And adapting for networking will be a nightmare.
My usual approach is to simply use some kind of timing system that drives both the gameplay mechanics and the animation so that everything syncs perfectly yet doesn’t tie you down when you want to adapt it to something else.
Yeah SMBehaviours are great but would mean I need to split my anticipation, attack, reccovery into 3 different animations. Which might not be horrible just a bit more animator work.
It can literally be anything you want. I often do it using Beahvior Trees since they are naturally designed for handling the passage of time. But even a simple delayed invoke or coroutine would suffice (not my preferred choice personally due to their performance issues at scale though). Even just a simple Update cycle that calls a set of functions when the correct times are hit before disabling itself can work. Just programmatically determine how fast your a animation needs to play and then queue up a sequence of actions to take with time delays between them so that they sync with the right point in the animation.
EDIT: Fixed all of the mistakes my phone likes to make when I’m ‘typing’ with it.