1. Playable是什么
Playable是一组API,可以用来组合、混合、修改多个数据源,然后通过一个输出,将这些数据源处理完的结果播放出来。
2. 简单使用:播放单个动画
PlayableGraph的AnimationOutput依然是基于Animator组件的,不过你可以不用关心它了。
主要实现目的是可以不创建animationcontroller,用代码实现其中的一些功能
using UnityEngine;using UnityEngine.Animations;using UnityEngine.Playables; public class PlayClipOnObject : MonoBehaviour { public AnimationClip myClip; private PlayableGraph graph; void Start () { PlayAnimation(gameObject, myClip); } public void PlayAnimation (GameObject target, AnimationClip clip ) { graph = PlayableGraph.Create(); var animator = target.AddComponent<Animator>(); var clipPlayable = AnimationClipPlayable.Create(graph, clip); var animOutput = AnimationPlayableOutput.Create(graph, "some name" , animator); animOutput.SetSourcePlayable(clipPlayable); graph.Play(); } void OnDestroy () { if (graph.IsValid()) graph.Destroy(); } }
创建步骤:
创建Graph
playableGraph = PlayableGraph.Create();
创建Ouput
var playableOutput = AnimationPlayableOutput.Create(playableGraph, "Animation" , GetComponent<Animator>());
为clip创建针对的Playable对象
var clipPlayable = AnimationClipPlayable.Create(playableGraph, clip);
设置playable对象到Output中
playableOutput.SetSourcePlayable(clipPlayable);
让Graph执行play
Playable Output类型
为了避免GC,所有类型都是使用struct实现的。
构建PlayableGraph一般有如下的流程:
创建一个PlayableGraph,方法是PlayableGraph.Create(“graph的名字”)
创建输出节点,常用的有
AnimationPlayableOutput.Create(playableGraph, "name" , GetComponent<Animator>()); AudioPlayableOutput.Create(playableGraph, "name" , GetComponent<AudioSource>());
还可以创建自定义的输出节点
创建各种playables。所有的Playable都有一个静态的Create()方法,用来创建playable实例。需要注意的是自定义的PlayableBehaviour需要使用
ScriptPlayable<T>.Create(playableGraph);
来创建。
AnimationClipPlayable.Create(playableGraph, animationClip); AudioClipPlayable.Create(playableGraph, audioClip, true ); ScriptPlayable<T>.Create(playableGraph);
连接playable和output:PlayableOutput.SetSourcePlayable()
playable之间的连接:PlayableGraph.Connect()。
播放graph:PlayableGraph.Play()
如果graph不再使用,记得销毁:PlayableGraph.Destroy()。调用这个方法后会销毁所有的playbles和output。
3. 替代AnimationController
创建混合树AnimationMixerPlayable,实现AnimationController之间连线控制功能:
using UnityEngine;using UnityEngine.Playables;using UnityEngine.Animations;using UnityEngine.Experimental.Animations;[RequireComponent(typeof(Animator)) ] public class PlayAnimationSample : MonoBehaviour { public AnimationClip clip0; public AnimationClip clip1; PlayableGraph playableGraph; private AnimationMixerPlayable m_Mixer; public float tranTime = 2 ; private float leftTime; void Start () { playableGraph = PlayableGraph.Create("测试" ); playableGraph.SetTimeUpdateMode(DirectorUpdateMode.GameTime); var playableOutput = AnimationPlayableOutput.Create(playableGraph, "Animation" , GetComponent<Animator>()); m_Mixer = AnimationMixerPlayable.Create(playableGraph, 2 ); AnimationClipPlayable clipPlayable0 = AnimationClipPlayable.Create(playableGraph, clip0); AnimationClipPlayable clipPlayable1 = AnimationClipPlayable.Create(playableGraph, clip1); playableGraph.Connect(clipPlayable0, 0 , m_Mixer, 0 ); playableGraph.Connect(clipPlayable1, 0 , m_Mixer, 1 ); m_Mixer.SetInputWeight(0 ,1 ); m_Mixer.SetInputWeight(1 ,0 ); playableOutput.SetSourcePlayable(m_Mixer); playableOutput.SetSortingOrder(0 ); leftTime = tranTime; playableGraph.Play(); } void Update () { leftTime = Mathf.Clamp(leftTime - Time.deltaTime, 0 , 2 ); float weight = leftTime / tranTime; Debug.Log("weight:" +weight); m_Mixer.SetInputWeight(0 , 1 - weight); m_Mixer.SetInputWeight(1 , weight); } void OnDestroy () { playableGraph.Destroy(); } }
5. 实现自定义的PlayableBehaviour
实现
1.继承 PlayableBehaviour
2.在初始化函数中传入graph, playable对象,分别为每个动画创建Playable并添加到mixer中,设置weight
调用
1.使用ScriptPlayable.Create创建自定义的Playable对象
2.从Playable中获取behaviour并利用此behaviour调用初始化函数
using System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEngine.Animations;using UnityEngine.Playables;public class CustomPlayable : PlayableBehaviour { private int m_CurrentClipIndex = -1 ; private float m_TimeToNextClip; private Playable mixer; public void Initialize (AnimationClip[] clipsToPlay, Playable owner, PlayableGraph graph ) { owner.SetInputCount(1 ); mixer = AnimationMixerPlayable.Create(graph, clipsToPlay.Length); graph.Connect(mixer, 0 , owner, 0 ); owner.SetInputWeight(0 , 1 ); for (int clipIndex = 0 ; clipIndex < mixer.GetInputCount() ; ++clipIndex) { graph.Connect(AnimationClipPlayable.Create(graph, clipsToPlay[clipIndex]), 0 , mixer, clipIndex); mixer.SetInputWeight(clipIndex, 1.0f ); } } override public void PrepareFrame (Playable owner, FrameData info ) { if (mixer.GetInputCount() == 0 ) return ; m_TimeToNextClip -= (float )info.deltaTime; if (m_TimeToNextClip <= 0.0f ) { m_CurrentClipIndex++; if (m_CurrentClipIndex >= mixer.GetInputCount()) m_CurrentClipIndex = 0 ; var currentClip = (AnimationClipPlayable)mixer.GetInput(m_CurrentClipIndex); currentClip.SetTime(0 ); m_TimeToNextClip = currentClip.GetAnimationClip().length; } for (int clipIndex = 0 ; clipIndex < mixer.GetInputCount(); ++clipIndex) { if (clipIndex == m_CurrentClipIndex) mixer.SetInputWeight(clipIndex, 1.0f ); else mixer.SetInputWeight(clipIndex, 0.0f ); } } }
using System.Collections;using System.Collections.Generic;using UnityEngine;using UnityEngine.Animations;using UnityEngine.Playables;public class PlayCustomPlayableSample : MonoBehaviour { public AnimationClip[] clipsToPlay; PlayableGraph m_Graph; void Start () { m_Graph = PlayableGraph.Create(); var custPlayable = ScriptPlayable<CustomPlayable>.Create(m_Graph); var playQueue = custPlayable.GetBehaviour(); playQueue.Initialize(clipsToPlay, custPlayable, m_Graph); var playableOutput = AnimationPlayableOutput.Create(m_Graph, "Animation" , GetComponent<Animator>()); playableOutput.SetSourcePlayable(custPlayable); playableOutput.SetSourceInputPort(0 ); m_Graph.Play(); } void OnDisable () { m_Graph.Destroy(); } }
4. 工具: PlayableGraph Visiualizer
在场景中的Animator运行时,将自动映射动画到Visiualizer中显示
在创建好的PlayableGraph ,运行时也会在其中显示