Legacy Documentation: Version 5.3
Using Blender and Rigify
Custom Playables

Playable API

Important: The Playables API is currently included as an experimental feature, and is part of the “experimental” namespace. This means any scripts you create using these features might not be compatible with future versions of Unity.

This new API provides a way to create tools, effects or other gameplay mechanisms by organizing and evaluating data sources in a tree-like structure.

This tree-like structure allows you to mix/blend/modify multiple data sources and play them through a single output. For example, in its current form, the Playable API supports animation graphs, providing the capacity to interact with Mecanim via scripting.

Even though the Playable API is currently limited to animation graphs, it is a generic API that could in the future be applied to Audio, Video, Scripts and custom Playables.

You can download a Unity project demonstrating these code examples here: PlayablesExamples.zip

How To Use

Playing a single clip on a GameObject

The following MonoBehaviour creates a simple tree with a single node, which plays a single clip.

Two new types of objects are introduced in this script: - The AnimationClipPlayable, which derives from the generic AnimationPlayable, and wraps an AnimationClip in order to make it compatible with the Playable API - an AnimatorControllerPlayable which knows how to play graphs.

The Play() operation connects them together by setting the AnimationClipPlayable as the root of the tree, and connecting the tree’s output to an “animation player”, which in this case is the Animator Component. The tree can then be played.

using UnityEngine;
using UnityEngine.Experimental.Director;

[RequireComponent(typeof(Animator))]
public class PlayAnimation : MonoBehaviour
{
    public AnimationClip clip;

    void Start()
    {
        // Wrap the clip in a playable
        var clipPlayable = new AnimationClipPlayable(clip);

        // Bind the playable to the player
        GetComponent<Animator>().Play(clipPlayable);
    }
}

Creating an animation blend tree programmatically

We now introduce the AnimationMixerPlayable, which can blend two or more AnimationClipPlayables, or blend other mixers which themselves blend other clips, etc. The SetInputs() method will create the underlying AnimationClipPlayable nodes implicitly (the method can also take an array of AnimationPlayables directly).

The weight of each clip in the blend is adjusted dynamically via SetInputWeight(), creating a blend tree that smoothly changes from one animation to the other over time.

using UnityEngine;
using UnityEngine.Experimental.Director;

[RequireComponent(typeof(Animator))]
public class MixAnimation : MonoBehaviour
{
    public AnimationClip clip1;
    public AnimationClip clip2;

    private AnimationMixerPlayable m_Mixer;

    void Start()
    {
        // Create the mixer and connect it to clips
        // (AnimationClipPlayables are created implicitly)
        m_Mixer = new AnimationMixerPlayable();
        m_Mixer.SetInputs(new[] { clip1, clip2 });

        // Bind the playable graph to the player
        GetComponent<Animator>().Play(m_Mixer);
    }

    void Update()
    {
        // Adjust the weight of each clip in the blend tree based on time
        float weight = (Time.time % 10) / 10;
        Debug.Log(weight);
        m_Mixer.SetInputWeight(0, 1 - weight);
        m_Mixer.SetInputWeight(1, weight);
    }
}

Blending AnimatorController

Just like the AnimationClipPlayable wraps an AnimationClip, the AnimatorControllerPlayable can wrap an AnimatorController, allowing us to blend them with other AnimationPlayables.

using UnityEngine;
using UnityEngine.Experimental.Director;

[RequireComponent(typeof(Animator))]
public class BlendAnimatorController : MonoBehaviour
{
    public AnimationClip clip;
    public RuntimeAnimatorController animController;
    AnimationMixerPlayable mixer;

    void Start()
    {
        // Wrap the clip and the controller in playables
        var clipPlayable = new AnimationClipPlayable(clip);
        var controllerPlayable = new AnimatorControllerPlayable(animController);
        mixer = new AnimationMixerPlayable();
        mixer.SetInputs(new AnimationPlayable[] { clipPlayable, controllerPlayable });

        // Bind the playable graph to the player
        GetComponent<Animator>().Play(mixer);
    }

    void Update()
    {
        // Adjust the weight between the clip and the controller based on time
        float weight = (Time.time % 10) / 10;
        Debug.Log(weight);
        mixer.SetInputWeight(0, 1 - weight);
        mixer.SetInputWeight(1, weight);
    }
}

Controlling the timing of the tree manually

By default, the Play() method on the PlayableController handles all the timing of the tree playback. However, for additional control, it is possible to explicitly set the local time of a Playable (local time will be propagated to children nodes). For instance, in this example, we pause the playback, and advance and rewind the animation manually using the keyboard arrows.

using UnityEngine;
using UnityEngine.Experimental.Director;

[RequireComponent(typeof(Animator))]
public class PlayWithTimeControl : MonoBehaviour
{
    public AnimationClip clip;

    private Playable root;
    private const float speedFactor = 1f;

    void Start()
    {
        root = new AnimationClipPlayable(clip);

        // Bind the playable to the player
        GetComponent<Animator>().Play(root);

        root.state = PlayState.Paused;
    }

    void Update()
    {
        // Control the time manually based on the input
        float horizontalInput = Input.GetAxis("Horizontal");
        root.time += horizontalInput * speedFactor * Time.deltaTime;
    }
}

Controlling the play state of the tree

Similarly, the state of the tree, or a branch of the tree, can be set by changing the Playable.state parameter. The state will propagate to all children of the node, regardless of their previous state. (Keep in mind that if a child node was explicitly paused, setting a parent to Playing state will also set this child to Playing state).

Example Project

You can download a Unity project demonstrating these code examples here: PlayablesExamples.zip

Using Blender and Rigify
Custom Playables