Tutorial: Reusable Animators in Unity
Hello, everyone! Long time when I decided to make a dev diary(probably one I had before this one) I had the idea of padding up content with tutorials. At the time my idea was to focus on Lua tutorials, as I was working with LÖVE2D at the time and the language fascinates me, as much as I see it can be tricky to a newcomer(for a short summary: in Lua everything is a “table”, which is basically an object). But I never got to it and it’s been a while since I worked with Lua so, as much as the idea still sounds good, I kind of lost momentum.
Now here we are because I’ve finally answered myself on an issue I had with Unity: the way the Mecanim Animator component works. Let us begin!
Currently I’m working on a platformed game, and one can see that in these kinds of games most charters act more or less the same: they walk from side to side, and they can jump and fall to and from tall places. They’ll end up having similar animation types, and a similar state machine. Allow me to dial a bit back now.
What I mean with state machine is that the Mecanim animator implements a state machine with attributes that allow the character to change its animation based on what’s coming from outside(e.g. the horizontal speed changed) and what it was doing before(e.g. it was jumping, so the animation will not change to a ground one, but one that’s aerial). To wit, here’s the current animation machine I have set up for Fran, the protagonist:
To me its only defect it’s that it’s not bidirectional, so I have to do double transitions for everyone, and some attributes are not globally set so, for example, I have to go in each of those transitions and specify that the transition time is 0(basically so it doesn’t wait for the previous animation to end before starting a new one, making the character stay facing the wrong direction for a while when turning, for example).
The other big problem with Animator, though, is that it sets the animations themselves for each node, and that makes it basically attached to one actor only(it probably works a lot better when 3D models are involved; I’m talking of sprites here, though). Fran’s animations use Fran sprites, and Nippy’s animator uses Nippy sprites, so using the same animator means one will look like the other, and that doesn’t work very well…
One possible but clunky solution would be to change the Animation component in the object manually via script and set the animations as attributes, but besides that being a little hacky, it also loses the state machine quality of Mecanim, unless I implement a state machine of my own, and that’d be a waste of time, I think. There had to be a better solution, and, to my luck, there is.
It relies on one simple concept I didn’t known much about: Layers. To be more specific, Synced Layers.
Animator Layers are a concept I wasn’t familiar with and while I still haven’t found a good use for it yet, they basically allow you to have more than one machine running at once, and ideally these two machines will change different parts of your object. Say you have a segmented character, you can move its legs for moving while you can make it swing its arms or weapon for attacking while it walks. Two independent motions that can or not go on at the same time, so instead of having 3 different states for walking, attacking, walking while attacking, you deal with two changes independently.
Two of the attributes of layers are weight(I’ll get there) and syncing. If a layer is synced, it means it will mimic the state machine from another layer, which means if you add a new state or transition there, it’ll be copied instantly. So this means if I add a new mechanic to the characters(say, swimming) I don’t need to add new states to every damn Animator I have created in the project.
So the solution is to create one state machine for all the platform actors, and then create synced layers for each character:
With just one detail: with so many layers, how does the game know which to pick? That’s the simple part: you set the weight of the layer you want to the biggest possible. This means the animator will use that one as the highest priority and ignore everything else, so now the animations showing up are the ones you want, and not anything else!
As a plus, this same method can be used to deal with objects that change their appearance, using the same method of creating extra synced layers and changing the weight in realtime.
Frankly, I have no idea how this interacts with the intended use for layers, or how weights usually work. I believe for this specific issue(that I’m sure not to be the only person to have) this is the most practical issue, but of course, I could be wrong. The comments section are down there for any discussions to start and flourish.
Any way, I hope this can be of use to someone. After all, that’s what tutorials are for. :V