【Unity】【Playables API】再利用可能で使いまわせるようなPlayableを設計する

UnityのPlayables APIで独自のPlayableを作るときには再利用可能な設計にしておくと便利です。
この記事ではこのような再利用時に便利なカスタムPlayableの作り方を紹介します。

Playables API?

Playables APIの基礎については以下の記事にまとめていますので、必要に応じて参照してください。

light11.hatenadiary.com

再利用のためにはPlayable Behaviourを使う

まず、単純にAnimationClipを生成するだけのPlayableを作ってみます。
普通に作るならAnimationPlayableを直接Playable GraphにつなぐだけでOKです。
しかし今回は再利用可能なPlayableを作るため、Playable Behaviorを使います。

using UnityEngine;
using UnityEngine.Animations;
using UnityEngine.Playables;

public class AnimationClipPlayableBehaviour : PlayableBehaviour
{
    private AnimationClipPlayable _clipPlayable;
    private Playable _parentPlayable;
    public PlayableGraph Graph { get { return _parentPlayable.GetGraph(); } }

    public static ScriptPlayable<AnimationClipPlayableBehaviour> CreatePlayable(PlayableGraph graph)
    {
        var scriptPlayable = ScriptPlayable<AnimationClipPlayableBehaviour>.Create(graph, 1);

        // PlayableBehaviourを初期化
        var behaviour = scriptPlayable.GetBehaviour();
        behaviour._parentPlayable = scriptPlayable;

        return scriptPlayable;
    }

    public void SetClip(AnimationClip clip)
    {
        // AnimationClipPlayableを生成
        _clipPlayable = AnimationClipPlayable.Create(Graph, clip);
        // ParentからすべてのInputをはがす
        for (int i = 0; i < _parentPlayable.GetInputCount(); i++) {
            _parentPlayable.DisconnectInput(i);
        }
        // くっつける
        _parentPlayable.SetInputCount(1);
        _parentPlayable.SetInputWeight(0, 1.0f);
        Graph.Connect(_clipPlayable, 0, _parentPlayable, 0);
    }

    public override void PrepareFrame(Playable scriptPlayable, FrameData info)
    {
        if (!_clipPlayable.IsValid()) {
            return;
        }

        _clipPlayable.SetTime(_clipPlayable.GetTime() + info.deltaTime);
    }
}

AnimationClipPlayableの前にPlayableBehaviourを挟む形になります。

f:id:halya_11:20190613213746p:plain

Playable Graphにつなぐ

それではこれをPlayable Graphにつないでみます。

using UnityEngine;
using UnityEngine.Animations;
using UnityEngine.Playables;

public class PlayableExample : MonoBehaviour
{
    [SerializeField]
    private AnimationClip _clip;

    void Awake()
    {
        var graph = PlayableGraph.Create("Example Graph");
        AnimationPlayableOutput.Create(graph, "Animation", GetComponent<Animator>());
        var playable = AnimationClipPlayableBehaviour.CreatePlayable(graph);
        playable.GetBehaviour().SetClip(_clip);
        graph.GetOutput(0).SetSourcePlayable(playable);
        graph.Play();
    }
}

AnimationClipをセットして再生するとアニメーションが再生されます。

f:id:halya_11:20190613213940g:plain

またこの時のPlayable Graphは次のようになります。

f:id:halya_11:20190613214012p:plain

再利用する

それでは次に前々節で作ったPlayableを再利用して二つインスタンス化し、それらをブレンドしてみます。
PlayableBehaviourでラップしているため、以下のようにPlayableBehaviour.Create()を呼ぶだけで簡単に再利用することができます。

using UnityEngine;
using UnityEngine.Animations;
using UnityEngine.Playables;

public class PlayableExample : MonoBehaviour
{
    [SerializeField]
    private AnimationClip _clip1;
    [SerializeField]
    private AnimationClip _clip2;

    [SerializeField, Range(0.0f, 1.0f)]
    private float _blendRate;

    private AnimationMixerPlayable _mixer;

    void Awake()
    {
        var graph = PlayableGraph.Create("Example Graph");
        AnimationPlayableOutput.Create(graph, "Animation", GetComponent<Animator>());

        // AnimationMixerPlayableを生成してOutputに繋ぐ
        _mixer = AnimationMixerPlayable.Create(graph, 2);
        graph.GetOutput(0).SetSourcePlayable(_mixer);

        // 1個目のPlayableを生成してmixerに繋ぐ
        var playable1 = AnimationClipPlayableBehaviour.CreatePlayable(graph);
        playable1.GetBehaviour().SetClip(_clip1);
        _mixer.ConnectInput(0, playable1, 0);

        // 2個目のPlayableを生成してmixerに繋ぐ
        var playable2 = AnimationClipPlayableBehaviour.CreatePlayable(graph);
        playable2.GetBehaviour().SetClip(_clip2);
        _mixer.ConnectInput(1, playable2, 0);

        graph.Play();
    }

    private void Update()
    {
        // ブレンド率に応じてウェイトを設定
        _mixer.SetInputWeight(0, 1.0f - _blendRate);
        _mixer.SetInputWeight(1, _blendRate);
    }
}

クリップを設定して再生してBlend Rateを変えると、アニメーションがブレンドされることが確認できます。

f:id:halya_11:20190613214929g:plain

Playable Graphは以下のようになっています。

f:id:halya_11:20190613214943p:plain

まとめ

このようにPlayable Behaviourを使うとPlayableを再利用可能な設計にできます。
今回のような簡単な例ではあまり効果はありませんが、複雑なPlayable Graphを組み立てるときにはこのような実装が必要になってくるかと思います。

関連

light11.hatenadiary.com