Animation States

Summary

Control animation states from a Reactor server using entity properties as animation parameters linked to animation transitions in an animation controller.

Setup

  1. Import 4 animations. Idle, Walk, Run, and Cheering and configure the following properties on all animations
Loop Time = Checked
Root Tranform Rotation
  Based Into Pose = Checked
  Based Upon = Body Orientation

Root Tranform Position Y
  Based Into Pose = Checked
  Based Upon (at Start) = Original

Root Tranform Position XZ
  Based Into Pose = Checked
  Based Upon (at Start) = Original
  1. Create an animation controller and add the imported animations. Add a float parameter named Speed and a bool parameter named Cheering to the animation controller. Add transitions between the animation states with conditions based on the two parameters:
Idle (Linked from Entry)
  Transition To Walk, exit time disabled, Speed > 0.01 condition.
  Transition To Cheering, exit time disabled, Cheering = True condition.

Walking
  Transition To Idle, exit time disabled, Speed < 0.01 condition.
  Transition To Run, exit time disabled, Speed > 1 condition.
  Transition To Cheering, exit time disabled, Cheering = True condition.

Running
  Transition To Walk, exit time disabled, Speed < 1 condition.
  Transition To Cheering, exit time disabled, Cheering = True condition.

Cheering
  Transition To Idle, exit time disabled, Cheering = False condition.
  1. Creat an NPC GameObject from the idle animation asset. Set the NPC animator controller reference to the animation controller created above.

  2. Add a Reactor ksEntityComponent to the NPC and uncheck the IsPermanent property. Add a Reactor client entity script named ceAnimator to the NPC. This script listens for changes on entity property 0 which we use for the Speed and property 1 which we use for Cheering. When the property change events fire, they set the corresponding value in the NPC animator.

using UnityEngine;
using KS.Reactor;
using KS.Reactor.Client.Unity;

public class ceAnimator : ksEntityScript
{
    private Animator m_animator;

    public override void Initialize()
    {
        m_animator = GetComponent<Animator>();
        Entity.OnPropertyChange[0] += ChangeSpeedProperty;
        Entity.OnPropertyChange[1] += ChangeCheerProperty;
    }

    public override void Detached()
    {
        Entity.OnPropertyChange[0] -= ChangeSpeedProperty;
        Entity.OnPropertyChange[1] -= ChangeCheerProperty;
    }

    private void ChangeSpeedProperty(ksMultiType oldValue, ksMultiType newValue)
    {
        if (m_animator != null)
            m_animator.SetFloat("Speed", newValue.Float);
    }

    private void ChangeCheerProperty(ksMultiType oldValue, ksMultiType newValue)
    {
        if (m_animator != null)
            m_animator.SetBool("Cheering", newValue.Bool);
    }
}

Add a Reator server entity script named seAnimator to the NPC. This script sets the entity property 0 (Speed) value and the entity property 1 (Cheering) property during an update loop. The script changes the speed during the update loop and periodically sets and unsets the cheering property. This is just an example script, actual scripts used in games will drive animation states in different ways.

using KS.Reactor.Server;

public class seAnimator : ksServerEntityScript
{
    private float m_cheerDuration = 0f;
    private float m_cheerTime= 10f;
    private float m_speed = -1f;
    private bool m_increaseSpeed = true;

    public override void Initialize()
    {
        Room.OnUpdate[0] += Update;
    }

    public override void Detached()
    {
        Room.OnUpdate[0] -= Update;
    }

    private void Update()
    {
        // Ping pong speed up and down to switch between idle, walking and running
        if (m_speed < -1.0f)
            m_increaseSpeed = true;
        else if (m_speed > 2.0f)
            m_increaseSpeed = false;

        m_speed += 0.5f * (m_increaseSpeed ? Time.Delta : -Time.Delta);
        Entity.Properties[0] = m_speed;

        //Start Cheering
        m_cheerTime -= Time.Delta;
        if (m_cheerTime <= 0)
        {
            m_cheerTime = 10.0f;
            m_cheerDuration = 2.0f;
            Entity.Properties[1] = true;
        }

        // Stop Cheering
        if (m_cheerDuration > 0)
        {
            m_cheerDuration -= Time.Delta;
            if (m_cheerDuration <= 0)
            {
                Entity.Properties[1] = false;
            }
        }
    }
}