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将应用图形评估产生的动画姿势。可播放输出的数量与不同的可玩类型一样多:AnimationPlayableOutput, AudioPlayableOutput, TexturePlayableOutput, ScriptPlayableOutput,等等...
ScriptPlayable<T>是一种特殊的可玩性。它的主要作用是成为"定制"的可玩性。它是一个模板化结构,必须派生自 PlayableBehaviour。这些自定义的 PlayableBehaviour 允许在图形评估中的特定时刻编写行为(请参阅PlayableBehaviour.PrepareFrame和PlayableBehaviour.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