この新しい API は、ツール・エフェクト・その他さまざまなゲームプレイ機構の作成を、データソースをツリー状の形式で整理することによって行えるようにしたものです。
ツリー状の構造のおかげで、複数のデータソースをミックス/ブレンド/修正し、それらを単一の出力から再生することが可能になります。例えば現時点では、 Playable API はアニメーショングラフに対応していますので、 Mecanim をスクリプトで扱うことも可能になります。
現時点で Playable API が対応しているのはアニメーショングラフのみですが、ジェネリック API ですので将来的にはオーディオ、ビデオ、スクリプト、またカスタムの Playable にも対応できる可能性があります。
これらのコード例を表現している Unity のプロジェクトは、こちらでダウンロードできます。 PlayablesExamples.zip
下記の MonoBehaviour は、 1 つのノードを持つ簡単なツリーを生成します。このノードが1つのクリップを再生します。
このスクリプト内には新しいタイプのオブジェクトが2つ含まれています。 ひとつは AnimationClipPlayable です。これはジェネリックの AnimationPlayable から派生しており、 アニメーションクリップ をラップすることで、グラフを再生する Playable API の AnimatorControllerPlayable との互換性を持たせるものです。
これらは、Play() 操作によって繋がれます。これは、AnimationClipPlayable をツリーのルートとして設定し、ツリーの出力を「アニメーションプレイヤー」(ここでは アニメーターコントローラー)に接続することによって成されます。この結果ツリーが再生可能になります。
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);
}
}
AnimationMixerPlayable は、2つあるいはそれ以上の AnimationClipPlayable をブレンドしたり、他の(それ自体が他のクリップをブレンドする)ミキサーをブレンドしたりすることができます。 SetInputs() の方式は、下層の AnimationClipPlayable ノードを暗黙的に作成します。(この方式は、AnimationPlayable の配列を直接取得することもあります。)
各クリップのブレンド中のウェイトは、SetInputWeight() で動的に調節できます。ブレンドツリーが生成されて、ひとつのアニメーションから別のアニメーションへ、徐々にスムーズに変化します。
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);
}
}
AnimationClipPlayable が AnimationClip をラップするのと同じように、AnimatorControllerPlayable も アニメーターコントローラー をラップできます。これによって、別の AnimationPlayable とブレンドさせることが可能になります。
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);
}
}
デフォルトでは、ツリーの再生のすべてのタイミングは PlayableController の Play() 方式によって制御されています。ただし、より詳細に制御したい場合は、Playable のローカルタイムを具体的に設定することも可能です(ローカルタイムは子ノードに伝播されます)。例えばこの参考例では、再生を一時停止し、キーボードの矢印を使って手動でアニメーションを早送り・巻き戻ししています。
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;
}
}
上記と同様、ツリーの状態あるいはブランチも、Playable.state のパラメーターを調整して設定できます。状態はノードのすべての子に(子のそれ以前の状態がどうであったかに関わらず)伝播されます。(【注】子ノードを手動で一時停止しているときに親を Playing 状態にすると、子も Playing 状態になります。)
これらのコード例を表現している Unity のプロジェクトは、こちらでダウンロードできます。 PlayablesExamples.zip