Bootstrap

Unity Playable API 基本介绍

AnimationPlayableUtilities

实现高级实用工具方法,以简化PlayableAPI播放动画的使用。

 实际上就是把一些复杂的调用封装在了内部实现中,仅提供一些更为友好的调用方式。

以PlayClip为例:

    public static AnimationClipPlayable PlayClip(
      Animator animator,
      AnimationClip clip,
      out PlayableGraph graph)
    {
      graph = PlayableGraph.Create();
      AnimationPlayableOutput output = AnimationPlayableOutput.Create(graph, "AnimationClip", animator);
      AnimationClipPlayable animationClipPlayable = AnimationClipPlayable.Create(graph, clip);
      output.SetSourcePlayable<AnimationPlayableOutput, AnimationClipPlayable>(animationClipPlayable);
      graph.SyncUpdateAndTimeMode(animator);
      graph.Play();
      return animationClipPlayable;
    }

FrameData

此结构包含在Playable.PrepareFrame中接收的帧信息。

  • deltaTime: 帧间时间
  • effectiveParentSpeed: graph遍历阶段,到该Playable的parent Playable时的累积速度(accumulated speed)
  • effectivePlayState: 播放到当前Playable的累积播放状态(play state)
  • effectiveSpeed: 播放到当前Playable的累积速度
  • effectiveWeight: 播放到当前Playable的累积权重
  • evaluationType: PlayableGraph.PrepareFrame函数被调用的方式
  • frameId: 当前帧的id
  • output: The graph遍历阶段初始的PlayableOutput
  • seekOccurred: Indicates that the local time was explicitly set.
  • timeHeld: bool型变量,表示local time不会再增长,因为它播放完了,而且extrapolation mode设置为了Hold,应该就是播放一次的意思
  • timeLooped: bool型变量,表示local time wrapped,而且extrapolation mode设置为了Loop,应该是循环播放的意思
  • weight: 当前playable的权重

通常用在PlayableBehaviour类的某些虚函数中,提供接收的帧信息

 public abstract class PlayableBehaviour : IPlayableBehaviour, ICloneable
  { 
    [Obsolete("OnBehaviourDelay is obsolete; use a custom ScriptPlayable to implement this feature", false)]
    public virtual void OnBehaviourDelay(Playable playable, FrameData info)
    {
    }

    public virtual void OnBehaviourPlay(Playable playable, FrameData info)
    {
    }

    public virtual void OnBehaviourPause(Playable playable, FrameData info)
    {
    }

    public virtual void PrepareData(Playable playable, FrameData info)
    {
    }

    public virtual void PrepareFrame(Playable playable, FrameData info)
    {
    }

    public virtual void ProcessFrame(Playable playable, FrameData info, object playerData)
    {
    }
}

关于EvaluationType

该选项会决定一个Graph以何种方式被执行:

Evaluate:graph会以调用PlayableGraph.Evaluate([DefaultValue(“0”)] float deltaTime)函数的方式进行Update
Playback:graph会在runtime调用PlayableGraph.Play函数之后开始运行,然后会随Update或FixedUpdate函数的频率进行Update

Notification

Implements interfaces:INotification

描述

Playable 通知的默认实现。

在PlayableSystem中传递一条Notification。

using UnityEngine;
using UnityEngine.Playables;
class ExamplePlayableBehaviour : PlayableBehaviour
{
    private static readonly Notification s_BlendNotification = new Notification("BlendComplete");
    private float m_lastWeight = 0;

    public override void PrepareFrame(Playable playable, FrameData info)
    {
        if (m_lastWeight < 1 && info.effectiveWeight == 1)
        {
            info.output.PushNotification(playable, s_BlendNotification, m_lastWeight);
        }
        m_lastWeight = info.effectiveWeight;
    }
}

它是用在了PlayableOutputExtensions中的PushNotification方法中:

    public static void PushNotification<U>(
      this U output,
      Playable origin,
      INotification notification,
      object context = null)
      where U : struct, IPlayableOutput
    {
      output.GetHandle().PushNotification(origin.GetHandle(), notification, context);
    }

与之相关联的还有以下几个方法:

    public static INotificationReceiver[] GetNotificationReceivers<U>(
      this U output)
      where U : struct, IPlayableOutput
    {
      return output.GetHandle().GetNotificationReceivers();
    }

    public static void AddNotificationReceiver<U>(this U output, INotificationReceiver receiver) where U : struct, IPlayableOutput
    {
      output.GetHandle().AddNotificationReceiver(receiver);
    }

    public static void RemoveNotificationReceiver<U>(this U output, INotificationReceiver receiver) where U : struct, IPlayableOutput
    {
      output.GetHandle().RemoveNotificationReceiver(receiver);
    }

Playable

Implements interfaces:IPlayable

Playable对象是可自定义的运行时对象,可以连接在一起,并包含在PlayableGraph中以创建复杂的行为。

Playable对象可用于创建复杂而灵活的数据评估树。Playable对象是可以连接在一起的节点,之后每个可玩对象可以设置其每个子项的"权重"或"影响"。同一图形的可玩内容包含在PlayableGraph中。

一个PlayableGraph可以有多个输出,也称为
 "players",它们实现了IPlayableOutput。可播放输出获取其源可播放的结果,并将其应用于场景中的对象。例如,AnimationPlayableOutput链接到图中的可播放节点("源可播放")和场景中的Animator。播放图形时,Animator将应用图形评估产生的动画姿势。可播放输出的数量与不同的可玩类型一样多:AnimationPlayableOutputAudioPlayableOutputTexturePlayableOutputScriptPlayableOutput,等等...

ScriptPlayable<T>是一种特殊的可玩性。它的主要作用是成为"定制"的可玩性。它是一个模板化结构,必须派生自
 PlayableBehaviour。这些自定义的 PlayableBehaviour 允许在图形评估中的特定时刻编写行为(请参阅PlayableBehaviour.PrepareFramePlayableBehaviour.ProcessFrame)。Playable脚本的一个很好的例子是控制TimelinePlayable的时间轴可播放。它创建并链接在一起,负责tracks和clips的内容。

当播放PlayableGraph时,将遍历每个 PlayableOutput 。在此遍历期间,它将在每个可玩对象上调用 PrepareFrame 方法。这允许Playable"为下一次evaluation做好准备"。在 PrepareFrame 阶段,每个可玩对象都可以修改其子级(通过添加新输入或删除其中一些输入)。这使Playable能够在运行时在Playable tree中"生成"新的子分支。这意味着可玩树不是静态结构。它们可以随着时间的推移而适应和变化。

一旦准备工作完成,PlayableOutputs 就负责处理结果,这就是为什么他们也被称为"players"。在AnimationPlayableOutput的情况下,Animator负责处理graph。在ScriptPlayableOutput的情况下,PlayableBehaviour.ProcessFrame将在每个 ScriptPlayable 上被调用。
注意:您可以在任何实现 IPlayable 的结构上使用 PlayableExtensions 方法。

PlayableAsset

Implements interfaces:IPlayableAsset , 继承自ScriptableObject

一种asset文件类,可以用于在runtime instantiate出来一个Playable

  • public double duration: playable对应资源的播放时间(seconds)
  • public IEnumerable outputs:A description of the outputs of the instantiated Playable.
  • // 会根据owner,在graph里创建一个Playable,返回这个Playable对应的Root Playable(因为这个可能是一个Tree型的Playable)
  • public Playables.Playable CreatePlayable(Playables.PlayableGraph graph, GameObject owner);

PlayableBehaviour

Implements interfaces:IPlayableBehaviour

Description

PlayableBehaviour是每个自定义Playable脚本派生自的基类。

PlayableBehaviour可用于将用户定义的行为添加到PlayableGraph中。可玩行为必须是连接到输出的PlayableGraph分支的一部分才能处于活动状态。

namespace UnityEngine.Playables
{
    // 此类代表一个ScriptPlayable拥有的行为
    [RequiredByNativeCode]
    public abstract class PlayableBehaviour : IPlayableBehaviour, ICloneable
    {
        public PlayableBehaviour();

        public virtual object Clone();
        
        // 由于对应的Playable是在PlayableGraph里执行的, 这里提供了一大堆回调函数
     
     	// Obsolete
        public virtual void OnBehaviourDelay(Playable playable, FrameData info);
        
        // 当ScriptPlayable被暂停或播放时的回调
        public virtual void OnBehaviourPause(Playable playable, FrameData info);
        public virtual void OnBehaviourPlay(Playable playable, FrameData info);

		// PlayableGraph开始或暂停的回调
        public virtual void OnGraphStart(Playable playable);
        public virtual void OnGraphStop(Playable playable);
        
	      // 当ScriptPlayable被摧毁或创建时的回调
        public virtual void OnPlayableCreate(Playable playable);
        public virtual void OnPlayableDestroy(Playable playable);

		// 类似于Update函数
        public virtual void PrepareData(Playable playable, FrameData info);
        public virtual void PrepareFrame(Playable playable, FrameData info);
        public virtual void ProcessFrame(Playable playable, FrameData info, object playerData);
    }
}
  

在下面的示例中,两个 AnimationClip 由两个 AnimationClipPlayable 控制,这两个动画剪辑由 AnimationMixerPlayable 混合。
自定义BlenderPlayable行为是每帧修改AnimationMixerPlayable的输入。

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

public class BlenderPlayableBehaviour : PlayableBehaviour
{
    public AnimationMixerPlayable mixerPlayable;

    public override void PrepareFrame(Playable playable, FrameData info)
    {
        float blend = Mathf.PingPong((float)playable.GetTime(), 1.0f);

        mixerPlayable.SetInputWeight(0, blend);
        mixerPlayable.SetInputWeight(1, 1.0f - blend);

        base.PrepareFrame(playable, info);
    }
}

public class PlayableBehaviourSample : MonoBehaviour
{
    PlayableGraph m_Graph;
    public AnimationClip clipA;
    public AnimationClip clipB;

    // Use this for initialization
    void Start()
    {
        // Create the PlayableGraph.
        m_Graph = PlayableGraph.Create();

        // Add an AnimationPlayableOutput to the graph.
        var animOutput = AnimationPlayableOutput.Create(m_Graph, "AnimationOutput", GetComponent<Animator>());

        // Add an AnimationMixerPlayable to the graph.
        var mixerPlayable = AnimationMixerPlayable.Create(m_Graph, 2, false);

        // Add two AnimationClipPlayable to the graph.
        var clipPlayableA = AnimationClipPlayable.Create(m_Graph, clipA);
        var clipPlayableB = AnimationClipPlayable.Create(m_Graph, clipB);

        // Add a custom PlayableBehaviour to the graph.
        // This behavior will change the weights of the mixer dynamically.
        var blenderPlayable = ScriptPlayable<BlenderPlayableBehaviour>.Create(m_Graph, 1);
        blenderPlayable.GetBehaviour().mixerPlayable = mixerPlayable;

        // Create the topology, connect the AnimationClipPlayable to the
        // AnimationMixerPlayable.  Also add the BlenderPlayableBehaviour.
        m_Graph.Connect(clipPlayableA, 0, mixerPlayable, 0);
        m_Graph.Connect(clipPlayableB, 0, mixerPlayable, 1);
        m_Graph.Connect(mixerPlayable, 0, blenderPlayable, 0);

        // Use the ScriptPlayable as the source for the AnimationPlayableOutput.
        // Since it's a ScriptPlayable, also set the source input port to make the
        // passthrough to the AnimationMixerPlayable.
        animOutput.SetSourcePlayable(blenderPlayable);
        animOutput.SetSourceInputPort(0);

        // Play the graph.
        m_Graph.Play();
    }

    private void OnDestroy()
    {
        // Destroy the graph once done with it.
        m_Graph.Destroy();
    }
}

PlayableBinding

描述

包含有关PlayableAssets输出的信息的结构。

PlayableAssets 使用PlayableBindings指定它支持的输出类型。
不要直接创建可播放绑定对象。使用提供的内置方法创建相应的PlayableOutput。例如,要为AnimationPlayableOutput创建 PlayableBinding,请使用AnimationPlayableBinding.Create。要为ScriptPlayableOutput创建可播放绑定,请使用ScriptPlayableBinding.Create

PlayableDirector

Inherits from:Behaviour

Implements interfaces:IExposedPropertyTable

Description

实例化一个PlayableAsset,控制Playable objects的playback

由于它本质上是可以挂载到游戏物体上,所以可以直接获取到对应的组件进行属性上的设置和方法的调用。

 

PlayableExtensions

Description

提供了实现IPlayable接口的扩展方法。

 

使用实例如下:

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

public class ExamplePlayableBehaviour : PlayableBehaviour
{
    void Start()
    {
        PlayableGraph graph = PlayableGraph.Create();
        AnimationMixerPlayable mixer = AnimationMixerPlayable.Create(graph, 1);

        // Calling method PlayableExtensions.SetDuration on AnimationMixerPlayable as if it was an instance method.
        mixer.SetDuration(10);

        // The line above is the same as calling directly PlayableExtensions.SetDuration, but it is more compact and readable.
        PlayableExtensions.SetDuration(mixer, 10);
    }
}

PlayableGraph

Description

使用 PlayableGraph 来管理 Playable的 创建和生命周期。

PlayableGraph 也用来完成不同系统之间的连接,例如实现了IPlayableOutput的类, AnimationPlayableOutput or AudioPlayableOutput.

 

PlayableOutput

Implements interfaces:IPlayableOutput

PlayableOutputExtensions

Description

提供了对于实现了IPlayableOutput接口的扩展方法。

using UnityEngine;
using UnityEngine.Playables;

public class ExamplePlayableBehaviour : PlayableBehaviour
{
    void Start()
    {
        PlayableGraph graph = PlayableGraph.Create();
        ScriptPlayableOutput scriptOutput = ScriptPlayableOutput.Create(graph, "MyOutput");

        // Calling method PlayableExtensions.SetWeight on ScriptPlayableOutput as if it was an instance method.
        scriptOutput.SetWeight(10);

        // The line above is the same as calling directly PlayableExtensions.SetDuration, but it is more compact and readable.
        PlayableOutputExtensions.SetWeight(scriptOutput, 10);
    }
}

ScriptPlayable<T0>

Implements interfaces:IPlayable

Description

一个IPlayable实现,其中包含PlayableGraph的PlayableBehavior。 PlayableBehaviour可用于编写自定义Playble,以实现自己的 PrepareFrame 回调。

PlayableGraph的分支必须连接到要evaluated的output。

注意:您可以将PlayableExtensions方法与 ScriptPlayable 对象结合使用。

// ScriptPlayable是一个泛型类, 继承于IPlayable, 所以ScriptPlayable对象属于Playable
// 这里的T需要是class, 并且继承于IPlayableBehaviour, 且必须有无参的构造函数
public struct ScriptPlayable<T> : IPlayable, IEquatable<ScriptPlayable<T>> where T : class, IPlayableBehaviour, new()
{
    public static ScriptPlayable<T> Null { get; }

    public static ScriptPlayable<T> Create(PlayableGraph graph, int inputCount = 0);
    public static ScriptPlayable<T> Create(PlayableGraph graph, T template, int inputCount = 0);
    public bool Equals(ScriptPlayable<T> other);
    public T GetBehaviour();
    public PlayableHandle GetHandle();

	// 提供ScriptPlayable转为Playable的隐式转换
    public static implicit operator Playable(ScriptPlayable<T> playable);
    // 提供Playable转为ScriptPlayable的显式转换
    public static explicit operator ScriptPlayable<T>(Playable playable);
}

可以看出来,要想创建一个ScriptPlayable,首先需要定义这个脚本Playable的行为模式,它的行为模式用PlayableBehaviour类的对象来表示,在创建完该对象之后,就可以创建实际的ScriptPlayable对象了。

下面是创建自定义的PlayableBehaviour的方法:

public class MyCustomPlayableBehaviour : PlayableBehaviour 
{
	// Implementation of the custom playable behaviour 
	// Override PlayableBehaviour methods as needed 
}

接下来创建对应的ScriptPlayable的方法,好像一定要用统一的Create接口

//1. 需要使用ScriptPlayable<T>.Create的方法来统一创建ScriptPlayable
//2. 创建的时候需要指定对应的PlayableGraph

// 写法一, 调用myPlayable的Clone函数, 把它Copy一份传给ScriptPlayable
// 这也是为什么ScriptPlayable<T>的T必须要继承于ICloneable的原因
MyCustomPlayableBehaviour myPlayable = new MyCustomPlayableBehaviour();
ScriptPlayable<MyCustomPlayableBehaviour>.Create(playableGraph, myPlayable);

// 写法二, 省略了MyCustomPlayableBehaviour的创建, 里面会调用其默认构造函数创建对象
// 这也是为什么ScriptPlayable<T>的T必须要有无参的构造函数的原因
ScriptPlayable<MyCustomPlayableBehaviour>.Create(playableGraph);


使用对应的接口,可以从ScriptPlayable里重新获取其PlayableBehaviour对象:

ScriptPlayable<T> .GetBehaviour() 

ScriptPlayableBinding

Description

主要用来创建一个ScriptingPlayableOutput类型的静态类,只有一个静态方法Create

ScriptPlayableOutput

Implements interfaces:IPlayableOutput

Description

被用来作为PlayableGraph包含脚本的一种IPlayableOutput,

只有一个Create方法。
 

Interfaces

INotifications

INotificationReceiver

IPlayable

IPlayableAsset

IPlayableBehaviour

IPlayableOutput

Enumerations

DataStreamType

DirectorUpdateMode

DirectorWrapMode

PlayableTraversalMode

PlayState

;