I’ve been in charge of cleaning up a project that was performing extremely badly and what the Profiler identified as the worst offender was our Animators.
Our game is in 2D. All we are using mechanim for is changing frames of SpriteRenderers. The previous developer assumed that Unity’s own system would be far superior to any ad hoc solution. And so did we. Whilst trying desperately to get the game up to 60 FPS in heavily animated areas we decided to try swapping out the Animators for a simple script like this:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
[RequireComponent(typeof(SpriteRenderer))]
public class Anim : MonoBehaviour {
public Data data;
public SpriteRenderer spriteRenderer;
public bool playing = true;
public bool looped = true;
public float frame;
private int f;
private int totalFrames;
// Use this for initialization
void Start () {
totalFrames = data.frames.Count;
if(totalFrames == 0) playing = false;// sanity check
}
// Update is called once per frame
void Update () {
if(playing) {
frame += Time.deltaTime * data.frameRate;
if(frame >= totalFrames) {
frame -= totalFrames;
if(!looped) {
playing = false;
return;
}
}
if(f != (int)frame) {
f = (int)frame;
spriteRenderer.sprite = data.frames[f];
}
}
}
public void Play() {
frame = 0;
playing = true;
}
public void Play(Data data) {
this.data = data;
totalFrames = data.frames.Count;
frame = 0;
playing = true;
if(totalFrames == 0) playing = false;// sanity check
}
[System.Serializable]
public class Data {
public List<Sprite> frames;
public float frameRate = 8;
}
}
Our FPS shot back up to 60.
So there’s a serious problem with using Animator for 2D games. Certainly there could be more of a problem with the way we were using it. But just exchanging it for a script that called Update() every frame was far less expensive in CPU.
Are there ways to use Animator to bring it up to the speed of this script?
If there isn’t then us 2D developers are stuck with this script. This version is simple and portable, but are there ways to improve it or have you created your own version. If we’re not wrong and Animator is indeed terrible for 2D, could Unity give us a 2D version of Animator that we can use instead of writing our own?
The 30 FPS nightmare case was on Android (Moto G5S Plus), on Nintendo Switch we were losing 15-30 FPS. On PC this was much less noticeable but we were still losing frames.
Let me be clear in saying that the previous project lead had an extremely optimistic take on how many Animators a scene could support. We had a level that was broken into sub-rooms and despite only interacting with one sub-room at a time, the rest of the level was animating lots of things. It was a disaster scenario.
But even after doing all sorts of optimisation tricks, the only thing to restore our FPS to full was removing as many Animators as possible. (And replacing them with a script similar to the one above.)
I’m open to the possibility that Animator interacts negatively with the Profiler - but then this means it’s impossible to do profiling accurately with Animators. All I know for sure is that what sat at the top of the Profiler was the Animator Director, and once I removed as many Animators as possible (especially for simple frame loops) we got a significant speed boost.
I will try to do some more research, but I wanted to start a discussion to see if others have had similar experiences.
Probably how you were using them to be honest, which you never talked about or showed. In general, using a manager or ECS would reduce the time taken even further.
Can you show the code you were using to interact with all those animators?
This was covered in Unite Berlin 2018 best practices. Summary: only choose an Animator over an Animation component or a simple script if you need its extra features.
I have a “Billboard” Component on a lot of GameObject’s and not implementing Update(), but having a dedicated manager that calls “Update” for me on those Billboards, just like the blog post describes, caused a nice performance improvement as well.
It’s probably something the new C# Job System can do even better.
Why would you think that complex beast that is mecanim would perform better than manually stepping though a sprite frame by frame? I mean you can go further (e.g. animating in the shader), but what you have is basically the raw instructions for animating.
That said you don’t mention how many animations you have, I’ve never seen any problem with 20-30 mecanim animations on screen even on low end platforms. Imagine something like an RTS would be a different story…
We had in excess of 100 animations. In a 2D game this is quite normal for us, there are many animated background elements, bespoke particles, various enemies, etc. Our studio is famed for detailed pixel art and animation.
Why would I use Unity when I could write my own engine in C++? Why would I think that Unity could do a better job of animation than I?
Many of them weren’t interacting. Just simple animation loops. No code. Otherwise the script I posted would have been of no use - note that the script just plays a loop of frames. It accepts an Anim.Data, but that wasn’t what gave us our FPS back.
At some point he says “let me dispel a rumour now, you should not be afraid to use the legacy animation system”
Oh, really? Because all communication from Unity seems to be to stay away from the animation system. (even the manual)[quote]
This component is retained in Unity for backwards-compatibility only. For new projects, please use the Animator component
[/quote]
And even more annoyingly, they have been refusing to fix bugs for it (bugs, btw, that they introduced when mecanim first arrived), because it’s legacy and not supported any more.
And now they decided that LOL JK if you care about performance, use the legacy stuff?
Are you kidding me?
Remove legacy from the title, update your manuals and support the thing then.
It’s not a rumour, ALL your communication suggests that we should move on from the Legacy Animation component, you CAN NOT remember it exists and actually suggest it to people only when we complain about how terrible the Animator is, but otherwise treat it like it doesn’t exist.
Because somehow these statements, all from Unity, are not compatible
(emphasis on yet)[quote]
This component is retained in Unity for backwards-compatibility only. For new projects, please use the Animator component
[/quote]
The guy is Ian Dundore.of Unity. What he is says it that the old Animation component is for simple cases much faster than Mecanim and should be used for that tasks (esp. when you work for a mobile app). This is at odds with statement by the Unity documentation.
No yeah, I figured it out, it’s in a quantum state of being Legacy. It depends on the observer.
If you ask for a bug fix “Nah, it’s legacy, use Mecanim!”
And then after many days/months of work to transition to Mecanim If you complain that Mecanim is slow, magically the animation component is not Legacy any more and I should have been using it the whole time!
I consider the advice about legacy to be terrible so I’ll just be polite and stop here:
If it’s legacy don’t use it
if it’s depreciated don’t use it
If Unity intends us to keep using something, don’t mark it as legacy. Wake up.
OK cool. Because typically people use Play to play a state on an animator and there’s a fast and slow way of doing that.
Animator is overkill for simple things. It’s designed for handling huge jobs, large rigs. It’s not designed for doing hundreds of tiny jobs. It’s designed to scale well for hundreds of hard jobs due to the initial overhead.
Also, you should use a manager class instead of individual updates to shave more time off. You just basically fell into the Unity trap where learn materials or videos will suggest the easiest and non-optimal way to achieve something. This is usually going to be the best advice for most of Unity’s non professional or hobbyist customers.
Actually I am a huge grump and used to avoid using any of Unity’s solutions. It was the previous project lead that had a ridiculously optimistic view that anything Unity made “shouldn’t be a problem”. Nowadays I try to take a hybrid approach and use features or re-write those features with pragmatism being the main goal.
And yes, my script using Update() is bad form. What’s surprising is that you can have 100s of said scripts, all calling Update() and they’re still faster than Animator. When you’re doing emergency optimisation, it’s a great solution.
I would however love to see a more thought-out 2D-Animation system. One that can register itself with a manager to deal with the Update() problem, I invite people to propose solutions.
Like me then. I’m a massive grump at most things. However, Unity’s Animator is ridiculously well optimised for what it should be used for, and it’s original design: dealing with ambitious and complex rigs and blending. That’s all multi threaded but there is an initial cost that’s probably more than the 100s of minor rotations or lerps you’d want to do, so it’s more about tools for job.
Here, you used a tank to drive to the supermarket. I don’t think that’s your fault though.
I think neither blindly use anything “canonical” for everything nor the “don’t use anything from them”-approach are right. I think the right thing to do is to read/watch/investigate as much as you can regarding the tools you want to use and make your own decisions.
Ian Dundore is one of the Unity guys who stand on the stage and reliably critical to their own work. All the time. It worth your time to watch all of his presentations about various aspects of Unity.
But as he always says: trust no one and accept performance advice from no one (even from him, although he and his team do a great job), make your own measurement.
It’s more about, if you want us to be using something, don’t put “Legacy” in front of it. Call it something else and stand behind it.
And I really hate that Unity keeps insisting that they don’t have a gap in their animation feature set. First it was “Mecanim is close enough” in terms of performance (it wasn’t). Then it was “what gap? we have the legacy animation, which is awesome btw”.
I remember being excited when they released the Simple Animation component. But it wasn’t fast. And the dev said on the matter:
It’s not the point, huh?
So dear Unity.
Should I be using Legacy Animation?
If yes, why is it called Legacy?
If not, what can I use for simple animations that performs almost equally fast?