Locomotion

This page is part of the 3D Game Kit example

The character has several animations that can be blended to allow movement at any speed as well as to turn quickly when needed.

Mecanim

The Mecanim character's LocomotionSM state is a Sub State Machine containing a main Locomotion Blend Tree to allow for movement at any speed, left and right quick turn animations, and the Idle state mentioned on the Idle page:

Animancer

With Animancer, all the state logic is defined in the LocomotionState script which handles everything that applies while the character is moving along the ground except for things that also apply in other states as well (such as the Character.OnAnimatorMove method described on the Movement page). It uses a Mixer State in place of the Blend Tree used by Mecanim:

using Animancer;
using Animancer.Units;
using System;
using UnityEngine;

public sealed class LocomotionState : CharacterState
{
    [SerializeField] private LinearMixerTransition _LocomotionMixer;
    [SerializeField] private ClipTransition _QuickTurnLeft;
    [SerializeField] private ClipTransition _QuickTurnRight;
    [SerializeField, MetersPerSecond] private float _QuickTurnMoveSpeed = 2;
    [SerializeField, Degrees] private float _QuickTurnAngle = 145;

    private AnimatedFloat _FootFall;

    private void Awake()
    {
        _QuickTurnLeft.Events.OnEnd =
            _QuickTurnRight.Events.OnEnd =
            () => Character.Animancer.Play(_LocomotionMixer);

        _FootFall = new AnimatedFloat(Character.Animancer, "FootFall");
    }

    public override bool CanEnterState => Character.IsGrounded;

    private void OnEnable()
    {
        Character.Animancer.Play(_LocomotionMixer);
    }

    private void FixedUpdate()
    {
        if (Character.CheckMotionState())
            return;

        Character.UpdateSpeedControl();
        _LocomotionMixer.State.Parameter = Character.ForwardSpeed;

        UpdateRotation();
        UpdateAudio();
    }

    private void UpdateRotation()
    {
        if (!_LocomotionMixer.State.IsActive)
            return;

        if (!Character.GetTurnAngles(Character.Brain.Movement, out var currentAngle, out var targetAngle))
            return;

        if (Character.ForwardSpeed > _QuickTurnMoveSpeed)
        {
            var deltaAngle = Mathf.DeltaAngle(currentAngle, targetAngle);
            if (Mathf.Abs(deltaAngle) > _QuickTurnAngle)
            {
                var turn = deltaAngle < 0 ? _QuickTurnLeft : _QuickTurnRight;

                if (turn.State == null || turn.State.Weight == 0)
                {
                    Character.Animancer.Play(turn);
                    return;
                }
            }
        }

        Character.TurnTowards(currentAngle, targetAngle, Character.CurrentTurnSpeed);
    }

    [SerializeField] private UnityEvent _PlayFootstepAudio;
    private bool _CanPlayAudio;
    private bool _IsPlayingAudio;

    private void UpdateAudio()
    {
        const float Threshold = 0.01f;

        var footFallCurve = _FootFall.Value;
        if (footFallCurve > Threshold && !_IsPlayingAudio && _CanPlayAudio)
        {
            _IsPlayingAudio = true;
            _CanPlayAudio = false;

            _PlayFootstepAudio.Invoke();
        }
        else if (_IsPlayingAudio)
        {
            _IsPlayingAudio = false;
        }
        else if (footFallCurve < Threshold && !_CanPlayAudio)
        {
            _CanPlayAudio = true;
        }
    }
}

Movement Moving the character's position.
Turning Turning the character's rotation.