Oh, that thing where you just get out of the way of writing regularly, and then it gets harder to go back to it the longer the hiatus lasts.
I might have decided to replay Dragon Age: Origins and its expansion pack and then moved on to Divinity: Original Sin: Enhanced Edition, which amounted to… well, rather a lot of time not spent working on my own game, I’ll tell you that. I didn’t have much of note to say about either, so I just didn’t say anything.
Now, though, after that holiday, it’s finally time to tackle a problem that’s been lurking at the heart of my engine for a long time now: its use of animations.
Fun With Animation Controllers
I started using Unity before they added the “Mecanim” system. When I began, getting a character to animate was pretty straight-forward; you just said “play this clip” and away it went. Except then they added Mecanim and renamed the old system to “Legacy”. Fearing deprecation, I made the jump really badly. (Ironically, the deprecation hasn’t actually come yet: we’re a good 7-8 major versions along since then and Legacy Animation is still there.)
Mecanim put the wind up me at the time because it’s more than just an animation system. It’s a whole finite state machine animation manager, where you can rig up gameplay logic that is synchronised with animations and make them transition between each other without intervention from your actual game engine.
Witchcraft, I cried. I found the function that let me cross-fade between states like the old days and left it to rot.
Needless to say, I have a slightly complicated use case for my animation system. Walking and running and jumping are all fairly straight-forward; the character code does its thing and tells the animator to play the clip, maybe fiddling with the speed a tiny bit along the way. Attacks, however, are something slightly more complex; complex and, naturally, the most fundamental part of the game.
A character’s attack for me is comprised of three segments: raise, swing and recover. In the raise segment, the weapon is pulled back to get ready to strike. In the swing segment, the weapon is being swung at the opponent — crucially, during this segment it will deal damage to any object that it touches (ideally, just like a real weapon being swung). In the recover segment, the blade is being pulled back to the normal standing pose, ready to go again.
The kicker for me has always been timing and synchronisation of those three segments. It turns out that, using Mecanim in that crap way, it was quite hard to determine what sequence was actually playing or when it finished. My glorious hackzord worked 99% of the time, but 1% of the times one animation would clash with another and the whole thing would get stuck. Stuck attack animations generally meant the attack “never finished”, meaning no attacks ever again. Game-breaker!
Mecanim, however, is actually designed to do this sort of thing. It just requires you to embrace it rather than fighting it. Story of my life, huh?
The layer between the raw animation clips and the outside world that always scared me was the Mecanim state machine. Rather than playing clips directly, you indirectly influence the animation state machine by way of parameters that cause transitions between states. Consider a trigger named StartWalking, and a transition from the Stand state to the Walk state that only fires when that trigger is activated. That might sound an awful lot like telling it to just play a damn clip, but it’s much more powerful; conditions can be stacked up and some simple things can be done without any external influence at all.
Consider my three-pronged attacks. Previously, I first had start the Raise sequence, then keep a close watch on its progress so that I could play the Swing sequence immediately on its completion, then repeat the process to play the Recover sequence at the right time. Keeping track of those timings was the root of all my pain.
Now, I send an attack trigger (and a Right/Left trigger to choose which arm to use), and let Mecanim do the rest. The Raise state has an exit condition that fires when it finishes, starting the Swing state, which has a custom behaviour attached that activates weapon impact detection on entry and deactivates it on exit, and so on. Suddenly my flaky, monolithic attack controller is chopped up and spread around a system that fundamentally guarantees the timings.
So now I feel much more confident that things aren’t going to blow up in my face when I start to add more units and animations. I’ve only got vertical slicing for all my melee attackers at the minute, but in my heart there should also stabs and cleaves for the hero at least…