Skip to content

Animation Systems

Animator Controller

The Animator Controller is Unity's primary animation state machine. It manages states, transitions, parameters, layers, and blend trees.

States and Transitions

  • Each state plays an Animation Clip or Blend Tree
  • Transitions define conditions for switching between states
  • Use "Has Exit Time" for animations that must complete (attack finishers)
  • Disable "Has Exit Time" for instant transitions (idle to run)

Parameters

Control transitions from scripts using parameters:

private Animator _animator;

private void Awake()
{
    _animator = GetComponent<Animator>();
}

private void Update()
{
    _animator.SetFloat("Speed", _currentSpeed);
    _animator.SetBool("IsGrounded", _isGrounded);
}

public void Attack()
{
    _animator.SetTrigger("Attack");
}

Parameter types: SetFloat, SetBool, SetInteger, SetTrigger.

Triggers reset automatically after the transition fires. Bools persist until explicitly changed.

Blend Trees

Blend between multiple animations based on parameters: - 1D Blend Tree: walk to run based on speed - 2D Freeform: directional movement blending (strafe, forward, backward) - Direct: explicit weight control per child motion

Layers

Use layers for independent animation on different body parts: - Base Layer: locomotion (full body) - Upper Body Layer: aiming, shooting (override or additive blending) - Face Layer: facial expressions (additive)

Set layer weight with _animator.SetLayerWeight(layerIndex, weight).

Animation Events

Call methods from specific frames in an animation clip:

public void OnFootstep()
{
    _audioSource.PlayOneShot(_footstepClip);
}

public void OnAttackHit()
{
    DealDamageInRange();
}

Add events in the Animation window by selecting a frame and clicking "Add Event."

Root Motion vs Scripted Movement

  • Root Motion: Animation drives the transform. Enable "Apply Root Motion" on Animator. Good for realistic character movement where animation artists control locomotion.
  • Scripted Movement: Code drives the transform; animation is cosmetic. Disable "Apply Root Motion." Better for precise gameplay control.

Use OnAnimatorMove() to customize how root motion is applied:

private void OnAnimatorMove()
{
    Vector3 velocity = _animator.deltaPosition / Time.deltaTime;
    _rb.linearVelocity = new Vector3(velocity.x, _rb.linearVelocity.y, velocity.z);
}

Inverse Kinematics (IK)

Use OnAnimatorIK to adjust limb positions at runtime:

private void OnAnimatorIK(int layerIndex)
{
    if (_lookTarget)
    {
        _animator.SetLookAtWeight(1f);
        _animator.SetLookAtPosition(_lookTarget.position);
    }

    if (_rightHandTarget)
    {
        _animator.SetIKPositionWeight(AvatarIKGoal.RightHand, 1f);
        _animator.SetIKPosition(AvatarIKGoal.RightHand, _rightHandTarget.position);
    }
}

Requires a Humanoid avatar and an Animator Controller with IK Pass enabled on the layer.

DOTween / LeanTween

For procedural, code-driven animation:

// DOTween examples
transform.DOMove(targetPosition, 1f).SetEase(Ease.OutQuad);
transform.DOScale(Vector3.one * 1.5f, 0.3f).SetLoops(2, LoopType.Yoyo);
_canvasGroup.DOFade(0f, 0.5f).OnComplete(() => gameObject.SetActive(false));

// Sequences
DOTween.Sequence()
    .Append(transform.DOMove(pos1, 0.5f))
    .Append(transform.DOMove(pos2, 0.5f))
    .Join(transform.DORotate(new Vector3(0, 180, 0), 0.5f));

Use DOTween for UI animations, camera effects, and any animation that needs to be driven by game logic rather than pre-authored clips.

Timeline

Timeline is for cinematic sequences, cutscenes, and scripted events:

  • Activation Track: enable/disable GameObjects at specific times
  • Animation Track: play animation clips on specific objects
  • Audio Track: trigger audio clips with precise timing
  • Signal Track: fire events at specific points in the timeline
  • Cinemachine Track: control camera shots and transitions

Control playback from code:

[SerializeField] private PlayableDirector _director;

public void PlayCutscene()
{
    _director.Play();
}

public void SkipCutscene()
{
    _director.time = _director.duration;
    _director.Evaluate();
}

2D Sprite Animation

For 2D games, animate sprites using the Animator:

  1. Import a sprite sheet and set Sprite Mode to "Multiple"
  2. Use the Sprite Editor to slice individual frames
  3. Create an Animation Clip by dragging frames into the Animation window
  4. The Animator Controller manages state transitions between clips

Use SpriteRenderer.flipX for direction changes instead of duplicating animations.