“True King” Development – Fixing an Animation Bug and Understanding Unity3D’s “Update” System

Anyone who has played my last two games will have noticed a bug I never properly fixed, one that is unique to my animation system. The 3D camera can be moved freely, but doing so quickly will see the character’s frames not keeping up with it, resulting in a temporarily odd appearance. A month ago, I finally got around to finding the problem.

An example of what happens when the camera is moved too quickly in “True King”

I have to give special credit to both Unity3D’s editor (for allowing some debugging visualization options, albeit not easily accessible) and the open-source “ScreenToGif” program for allowing me to easily capture my computer screen to see the effect in slow motion. Both an animated GIF and some freeze frames are shown below. The conclusion turned out to be exactly what you would think it was: the character frames have to be “looking at” (perpendicular to) the camera at all times, but they always seem to be one frame behind, especially noticeable when there are bigger movements from one frame to another.

Animation of “look at” bug.

Example frame 01.

Example frame 02.

Example frame 03.

Example frame 04.

I apologize, you may need to view the above images outside this blog article to see it better, due to the width limitations of this site and potentially of your computer screen. And the second red line in the images points to a second character: from the center of each visible character frame to where they “think” they need to look (should be the camera’s position).

It was reassuring to know the problem was this simple. I assumed previously it might be for other optimization reasons, and that the only fix would be to restrict the camera from moving too quickly in the first place. But capturing video made it clear: the frames “look at” the camera’s previous position, not its newest position. And yes, I use the simple “transform.LookAt(Vector3 position)” function to update each frame. Is it possible this function was to blame? No, it was just an issue with update order.

Unity3D conveniently uses a series of standard functions that the engine will call upon to initialize or update “objects” in a game scene. These functions include “void Awake()“, “void Start()“, “void Update()“, “void FixedUpdate()“, “void LateUpdate()“, among others. These functions are documented here and their order of execution here. If you have a lot of objects that follow independent logic, it’s common to implement these functions to take care of them. And while Unity3D has long been a single-threaded program (although some limited multi-threading seems to be recently included, exactly how that is utilized is difficult to find without personal testing… you could also manually set scripts to use multiple threads with mixed results), in theory, the design of these functions would make it easier to optimize them with multi-threading in mind behind the scenes.

As per common practice, I have the camera update on “LateUpdate,” to take into account any movements and physics that occur on the central focus character during “Update“. I have character frames update their rotation during “Update.” Surely, this explains the issue: “LateUpdate” occurs after “Update” in each frame, so the rotation of each character frame is always one frame out of date. But how to resolve it? I could redesign the logic to have character frames rotate on “LateUpdate,” but there is no way to ensure it occurs after the camera’s “LateUpdate.” I could also move the camera’s logic to “Update,” but this causes other issues (and, don’t quote me on this, but even after swapping the two logic points between “Update” and “LateUpdate,” the core issue still seemed to occur, contradicting Unity3D’s intention and documentation).

Unity3D’s editor also includes a handy menu to force script execution order. This can be found under “Edit -> Project Settings -> Script Execution Order” as of version 5.3. In theory, this is meant to give more control, allowing the developer to set certain scripts a specific index that defines their execution order (not overriding the above functions, but perhaps handy if two scripts each have a “LateUpdate()” function).  However, even this did not work for me despite all logic rearranging I tried: I don’t know if this is specifically a limitation on MonoBehavior functions, or if the ordering is preferred rather than guaranteed by the build.

Seemingly out of options, I went to a last resort that worked: creating a single scene manager script that explicitly controls everything.

Logic design before: no particular order (set by Unity for best optimization).

Logic design after: explicitly controlled ordering.

If you have ever made games before engines were readily available, or if you have used game engines or frameworks that don’t have an object-oriented GUI like Unity3D, you would be used to creating a class as the main entry point when a game starts, controlling what to load, what to unload, what logic to call and when to execute it. That’s effectively what I had to do. I created a WorldManager.cs file to be the only script still using MonoBehavior functions, and internally, calling other scripts in the order I tell it to. I personally don’t like resorting to this, but it seems to be a widely-considered best practice online, even with Unity.

And it works! There are a couple other animation glitches due to my own design (ie: updating animation frames at 12 fps for an old-school feel), but it doesn’t look as bad as it used to. I’d swear the game doesn’t perform quite as well (the engine can’t try to optimize execution order or multi-thread anything on its own now), but the effect is minimal and hard to notice.

Anyway, my conclusion is to try to make your own tools or scripts to override Unity’s when possible, to give yourself control where you need it, but also being aware of optimizations being lost if you don’t use Unity’s default design.