一.基本要素
1.ClipPlayable:对于一个动画系统来说,ClipPlayable可理解为AnimationClip,如下图1所示,又被称为输入节点。
2.MixerPlayable:控制ClipPlayable融合,又称为功能节点,如下图2所示。
3.BhaviorPlayable:控制ClipPlayable播放、暂停等行为,又称为功能节点,如下图3所示。
注:以上三个要素可统称为Playable。
4.Output:输出节点,它将多个Playable融合后的最终结果输出到指定组件,如Animator组件,如下图4所示。
5.PlayableGraph:可包含多个由Output为根节点的树形结构。
二.说明
1. 上图为可视化工具PlayableGraph Visualizer。下载及使用方法如下:
1.从 GitHub 代码仓库下载与您的 Unity 版本对应的 PlayableGraph Visualizer。
2.通过选择 Window > (Analysis) > PlayableGraph Visualizer 打开该工具。
3.使用GraphVisualizerClient.Show(PlayableGraph graph, string name)
来注册您的图。
注意:
1.另一种安装方式:(Unity中) Window > Package Manager > 左上角"+" > Add package from gitURL > 输入"com.unity.playablegraph-visualizer"。
2.注册后才能在PlayableGraph Visualizer窗口中显示。
2. 以下示例为参照官方文档及博客制作,文档以及博客中已包含详细的步骤和说明,所以本篇只对代码添加较为详细的注释,以供参考,为方便大家查找,文档及博客地址将在下面贴出。
3. 参考资料:
三.代码及注释
一共两个脚本(CustomAnimationController
和CustomAnimationBeahavior
)
关注要点:
1.各个要素如何创建。
2.各个要素如何连接。
3.PlayableBehaviour
的声明周期函数。
using UnityEngine;
using UnityEngine.Animations;
using UnityEngine.Playables;
//绑定Animator组件
[RequireComponent(typeof(Animator))]
public class CustomAnimationController : MonoBehaviour
{
private PlayableGraph graph;
public AnimationClip[] animationClips;
void Start()
{
//创建Graph
graph = PlayableGraph.Create("Custom Animation Controller");
graph.SetTimeUpdateMode(DirectorUpdateMode.GameTime);
GraphVisualizerClient.Show(graph);
//创建BeahaviorPlayable
ScriptPlayable<CustomAnimationBeahavior> scriptPlayable = ScriptPlayable<CustomAnimationBeahavior>.Create(graph);
CustomAnimationBeahavior playableBeahavior = scriptPlayable.GetBehaviour();
playableBeahavior.Initialize(animationClips, scriptPlayable, graph);
//创建PlayableOutput
AnimationPlayableOutput output = AnimationPlayableOutput.Create(graph, "Animation Output", GetComponent<Animator>());
output.SetSourcePlayable(scriptPlayable, 0);
graph.Play();
}
private void OnDestroy()
{
graph.Destroy();
}
}
using UnityEngine;
using UnityEngine.Animations;
using UnityEngine.Playables;
public class CustomAnimationBeahavior : PlayableBehaviour
{
//当前动画的下标
private int currentClipIndex = -1;
//距离下一个剩余的时间
private float timeToNextClip;
//混合器(MixerPlayable)
private AnimationMixerPlayable mixer;
public void Initialize(AnimationClip[] clips, Playable behaviorPlayable, PlayableGraph graph)
{
//1.设置行为(BehaviorPlayable)的子节点数
//2.创建混合器(MixerPlayable)
//3.连接行为(BehaviorPlayable)和混合器(MixerPlayable)
//4.设置行为(BehaviorPlayable)的权重,也就是将其设置为播放状态
behaviorPlayable.SetInputCount(1);
mixer = AnimationMixerPlayable.Create(graph, clips.Length);
graph.Connect(mixer, 0, behaviorPlayable, 0);
behaviorPlayable.SetInputWeight(0, 1);
//根据传入动画列表中的动画个数创建可播放动画片段(ClipPlayable),并将其与混合器(MixerPlayable)连接
for (int clipIndex = 0; clipIndex < mixer.GetInputCount(); ++clipIndex)
{
AnimationClipPlayable tempPlayable = AnimationClipPlayable.Create(graph, clips[clipIndex]);
graph.Connect(tempPlayable, 0, mixer, clipIndex);
mixer.SetInputWeight(clipIndex, 1.0f);
}
}
//每一帧执行
public override void PrepareFrame(Playable playable, FrameData info)
{
//混合器(MixerPlayable)子节点空为空则返回
if (mixer.GetInputCount() == 0)
{
return;
}
//下一个动画的播放时间(也是当前动画的剩余时间)
timeToNextClip -= (float)info.deltaTime;
//1.到了该播放下一个动画的时间,设置下一个应播放动画的索引
//2.若下一个动画的索引数超出子节点动画总数,则设置为第一个动画,也就是循环播放所有动画
//3.设置动画播放的初始位置
if (timeToNextClip<= 0.0f)
{
currentClipIndex++;
if (currentClipIndex >= mixer.GetInputCount())
{
currentClipIndex = 0;
}
AnimationClipPlayable currentClip = (AnimationClipPlayable)mixer.GetInput(currentClipIndex);
currentClip.SetTime(0);
timeToNextClip = currentClip.GetAnimationClip().length;
}
//从混合器(MixerPlayable)子节点中查找下一个应播放动画的索引,设置权重(权重为1时表示播放动画),播放动画
for (int clipIndex = 0; clipIndex < mixer.GetInputCount(); ++clipIndex)
{
if (clipIndex ==currentClipIndex)
{
mixer.SetInputWeight(clipIndex, 1.0f);
}
else
{![Playable.gif](https://upload-images.jianshu.io/upload_images/26892131-388ed6c9a784d802.gif?imageMogr2/auto-orient/strip)
mixer.SetInputWeight(clipIndex, 0.0f);
}
}
}
}