This document is about: QUANTUM 2
SWITCH TO

Custom Animator

Level 4
Available in the Gaming Circle and Industries Circle
Circle

Introduction

Quantum’s deterministic animator works by baking information from Unity’s Mecanim Controller. It imports many configurations such as the States, the Transitions, the Motion clips and so on.

The main advantage of using it is that it can control animations to be 100% in sync across machines. Animations will snap to the correct state and clip time accordingly to the predict-rollback. So it provides very accurate tick based animations, which is something that is usually needed on Fighting and some Sports games because the animations should be perfectly in sync between all client simulations.

Due to this addon's dependencies on Unity's Mecanim and the lack of a new animation tool on Unity, we decided to stop improving the addon. Be aware that if using this tool might require the team to change the code based on your game's animation needs.

Because of that, we decided to have the Animator as open source code that you can import into your quantum.code project and change it.

This document explains how the Custom Animator should be imported and used into your own projects.

This package was lastly tested with Quantum SDK 2.1.0 A1 Nightly Build 659

Known issues/Limitations

The CustomAnimator, as it comes by default, has these known limitations:

  1. No support for hierarchical states;
  2. No support for Unity’s animation events;
  3. No support for states with no motion (no animation clip set);
  4. No support for the Layers menu, which means that it's not possible to mix animations between more than one layer, such as using Avatar Masks, Blending and so on;
  5. When using Blend Trees, it is mandatory to have the blending value between [-1, 1], on both 1D and 2D Blend Trees;
  6. No support for Root Motion on 3D Transforms/PhysicsBody.

Importing the Custom Animator package

  1. Download the Custom Animator here;
  2. Unzip it and put the content of the folders QuantumCustomAnimator_state and QuantumCustomAnimator_systems wherever your prefer on your quantum.code project;
  3. The package comes with a partial implementation of the Frame.InitUser method, which is responsible for initializing the CustomAnimatorUpdater. If your project already have a partial implementation of the same method, please just make sure to include a call to the InitializeAnimatorUpdater method inside your own InitUser, and do not import the Frame.User.cs file from this package;
  4. With everything included in your solution, build your quantum.code project;
  5. On Unity, import the file QuantumCustomAnimator.unitypackage to the project;

This completes the initial steps to have it all building and running. Now, in order to actually use the component, assets and baking tools, here are the instructions:

Using the custom Animator

  • To use the component, add it directly to an Entity Prototype on Unity. Otherwise, it is possible to create a new instance of the CustomAnimator component and add it to the entity directly via code:

C#

var customAnimator = new CustomAnimator();
f.Set(fighter, customAnimator);
  • On Unity, create a new data asset of type CustomAnimatorGraph. This is the asset responsible for storing information related to Unity's Mecanim controller. When using Entity Prototypes to setup your custom animator, it is possible to reference the Animator Ggraph asset in the Inspector, on the AnimatorGraph field. An alternative is to load the graph asset via code:

var animatorGraphAsset = f.FindAsset<CustomAnimatorGraph>(assetGuid);

  • Initializing the CustomAnimator component: when using Entity Prototypes and defining the CustomAnimatorGraph as described above, it is not needed to initialize the component as it is already done using a Reactive Callback, on the CustomAnimatorSystem class. It can though alternatively be initialised via code:

C#

CustomAnimator.SetCustomAnimatorGraph(&knight->CustomAnimator, animatorGraphAsset);
f.Set(fighter, customAnimator);
  • Similarly to how it is done on Unity, use Getters and Setters in order to read/write to the Animator:

C#

// Getters
CustomAnimator.GetBoolean(frame, &fighter->Animator, "Defending");
CustomAnimator.GetFixedPoint(frame, &fighter->Animator, "Direction");
CustomAnimator.GetInteger(frame, &fighter->Animator, "State");

// Setters
CustomAnimator.SetBoolean(frame, &fighter->Animator, "Defending", true);
CustomAnimator.SetInteger(frame, &fighter->Animator, "Direction", 25);
CustomAnimator.SetFixedPoint(frame, &fighter->Animator, "Speed", FP._1);
CustomAnimator.SetTrigger(frame, &fighter->Animator, "Shoot");
  • It is important to notice that Unity’s Trigger parameters works like Booleans here. So, in order to trigger some param, you need to use the SetBoolean(&fighter→Animator, "MyTrigger", true) to set it to true, and a SetBoolean(&fighter→Animator, "MyTrigger", false) on the next tick so the trigger isn’t activated again. The package already includes a system to be run before the animation system, which sets every trigger parameter to false every tick. Just insert this code new CustomAnimatorResetTriggersSystem(), into your SystemSetup.cs file;

  • Every AnimatorState has an AssetRef that you can use in order to make references to custom assets. You can extend the baking process on Unity, grabbing even more information from the Unity's animator, save these information on you custom asset and reference it on the state, so you can read it on the simulation. You can, for example, create assets which has hitbox/hurtbox information baked in the form of FPAnimationCurves. You can save Unity events names/time into the asset so on the simulation you know when some animation event happens, etc;

  • On your SystemSetup.cs file, insert this line of code after your own systems:

C#

new CustomAnimatorSystem(),
  • On Unity, create the Custom Animator Graph asset, from the context menu: Create/Quantum/CustomAnimatorGraph;

This is how it looks like on its default state:

custom animator default
  • Reference an Unity’s Animator Controller asset using the Controller field and hit the Import Mecanim Controller button. You should then see the animations information filled, such as the states, transitions, parameters and so on:
custom animator baked
  • Open your EntityView class, and add this field:

    C#

    public CustomQuantumAnimator CustomQuantumAnimator;
    
  • Add the component CustomQuantumAnimator to the GameObjects that will be animated. Of course, it needs to have an EntityPrefabRoot on it, so make the reference to the component that you just added, using the field that you created on the instruction above;

custom animator game object
  • Open your EntitiyViewUpdater class and, on its OnUpdateView method, it has a foreach loop iterating over the active views. It should now include the custom animator updating, so this is how your foreach should look like:

C#

// Iterate over all view instances and update components using only entities from current frame.
foreach (var kvp in _activeViews) {
    // ... updates 2D and 3D transforms

    // At the end of the foreach, add this.
    // This is responsible for actually animating the entity views
    if (instance.CustomQuantumAnimator)
    {
        if (game.Frames.Predicted.Unsafe.TryGetPointer<CustomAnimator>(instance.EntityRef, out var animator))
        {
            instance.CustomQuantumAnimator.Animate(game.Frames.Current, animator);
        }
    }
}
  • The last step is to add a Unity's Animator component to your object. It can be placed on the same object which has the EntityPrefabRoot or it can be placed on a child object:
custom animator mecanim controller

Now that you have done the replacements on your quantum code, the replacements needed on the Unity side, and you have your CustomAnimatorGraph with information baked directly from a Unity's Mecanim controller, you are ready to go.

Parts of the code already comes with simple comments. On the Quantum side you’ll find everything related to the internal state machine itself, such as the AnimatorConditions, which are used on the AnimatorTransitions, the AnimatorVariables (parameters), Layers, Motions and so on.

On the Unity side, you will find the code related to drawing the custom editor for the Custom Animator Graph asset, and all of the code responsible for the baking process, which you can surely extend in order to bake more data into your animator asset, such as FPAnimationCurves for collision information, animation events from Unity and so on.

Back to top