使用PlayableAPI自定义动画系统(简单版)


一.基本要素

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. 参考资料:


三.代码及注释

一共两个脚本(CustomAnimationControllerCustomAnimationBeahavior

关注要点
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);
            }
        }
    }
}

四.效果预览

效果预览

  • 3
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值