概述
本篇介绍Playables应用示例
PlayableGraph可视化工具
PlayableGraph Visualizer可以实现Playable Graph的可视化,这个可是我们的辅助利器 Git地址: https://github.com/Unity-Technologies/graph-visualizer 使用步骤: 1. 下载工具 2. 在Unity中通过Window-Analysis-PlayableGraph Visualizer打开工具 通过GraphVisualizerClient.Show(PlayableGraph graph, string name)接口打开我们的Graph(或者运行也会查找出所有的Graph)
其中线条的颜色深度代表了混合权重
示例1:简单播放一个动画
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Animations;
[RequireComponent(typeof(Animator))]
public class PlayAnimationSample : MonoBehaviour
{
public Animator animator;
public AnimationClip clip;
PlayableGraph playableGraph;
void Start()
{
if (animator == null)
animator = GetComponent<Animator>();
playableGraph = PlayableGraph.Create("PlayAnimationSample");
playableGraph.SetTimeUpdateMode(DirectorUpdateMode.GameTime);
AnimationClipPlayable playable = AnimationClipPlayable.Create(playableGraph, clip);
AnimationPlayableOutput playableOutput = AnimationPlayableOutput.Create(playableGraph, "Animation", animator);
playableOutput.SetSourcePlayable(playable);
playableGraph.Play();
}
void OnDestroy()
{
playableGraph.Destroy();
}
}
我们还可以使用AnimationPlayableUtilities.PlayClip()非常方便的播放动画
using UnityEngine;
using UnityEngine.Animations;
using UnityEngine.Playables;
[RequireComponent(typeof(Animator))]
public class PlayAnimationUtilitiesSample : MonoBehaviour
{
public Animator animator;
public AnimationClip clip;
PlayableGraph playableGraph;
void Start()
{
if(animator==null)
animator = GetComponent<Animator>();
AnimationPlayableUtilities.PlayClip(animator, clip, out playableGraph);
}
void OnDestroy()
{
playableGraph.Destroy();
}
}
示例2:混合动画
我们可以使用AnimationMixerPlayable来混合两个动画片段
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Animations;
[RequireComponent(typeof(Animator))]
public class MixAnimationSample : MonoBehaviour
{
public Animator animator;
public AnimationClip clip0, clip1;
public float weight;
PlayableGraph graph;
AnimationMixerPlayable mixerPlayable;
void Start()
{
if (animator == null)
animator = GetComponent<Animator>();
graph = PlayableGraph.Create("MixAnimation");
var playableOutput = AnimationPlayableOutput.Create(graph, "Animation", animator);
mixerPlayable = AnimationMixerPlayable.Create(graph, 2);
playableOutput.SetSourcePlayable(mixerPlayable);
AnimationClipPlayable clipPlayable0 = AnimationClipPlayable.Create(graph, clip0);
AnimationClipPlayable clipPlayable1 = AnimationClipPlayable.Create(graph, clip1);
graph.Connect(clipPlayable0, 0, mixerPlayable, 0);
graph.Connect(clipPlayable1, 0, mixerPlayable, 1);
graph.Play();
}
void Update()
{
weight = Mathf.Clamp01(weight);
mixerPlayable.SetInputWeight(0, 1f - weight);
mixerPlayable.SetInputWeight(1, weight);
}
void OnDestroy()
{
graph.Destroy();
}
}
示例3:混合Clip和Controller
我们还可以混合Clip和Controller,混合的是Clip和当前Controller播放的动作
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Animations;
[RequireComponent(typeof(Animator))]
public class RuntimeControllerSample : MonoBehaviour
{
public Animator animator;
public AnimationClip clip;
public RuntimeAnimatorController controller;
public float weight;
PlayableGraph playableGraph;
AnimationMixerPlayable mixerPlayable;
void Start()
{
if(animator==null)
animator = GetComponent<Animator>();
playableGraph = PlayableGraph.Create("RuntimeControllerSample");
AnimationPlayableOutput playableOutput = AnimationPlayableOutput.Create(playableGraph, "AnimationOutput", animator);
mixerPlayable = AnimationMixerPlayable.Create(playableGraph, 2);
playableOutput.SetSourcePlayable(mixerPlayable);
AnimationClipPlayable clipPlayable = AnimationClipPlayable.Create(playableGraph, clip);
AnimatorControllerPlayable controllerPlayable = AnimatorControllerPlayable.Create(playableGraph, controller);
playableGraph.Connect(clipPlayable, 0, mixerPlayable, 0);
playableGraph.Connect(controllerPlayable, 0, mixerPlayable, 1);
playableGraph.Play();
}
void Update()
{
weight = Mathf.Clamp01(weight);
mixerPlayable.SetInputWeight(0, 1.0f - weight);
mixerPlayable.SetInputWeight(1, weight);
}
void OnDestroy()
{
playableGraph.Destroy();
}
}
在这里,我们可以看到Controller的Graph会复杂很多,还多了AnimationPose和AnimationLayerMixer节点,所以如果我们播放的动画比较简单的时候,我们可以自己定义PlayableGraph,不用Animator的Controller
示例4:多种输出
同时播放动画和音乐
using UnityEngine;
using UnityEngine.Animations;
using UnityEngine.Playables;
using UnityEngine.Audio;
[RequireComponent(typeof(Animator))]
[RequireComponent(typeof(AudioSource))]
public class MultiOutputSample : MonoBehaviour
{
public Animator animator;
public AudioSource audioSource;
public AnimationClip animationClip;
public AudioClip audioClip;
PlayableGraph playableGraph;
void Start()
{
if (animator == null)
animator = GetComponent<Animator>();
if (audioSource == null)
audioSource = GetComponent<AudioSource>();
playableGraph = PlayableGraph.Create("MultiOutputGraph");
AnimationPlayableOutput animationPlayableOutput = AnimationPlayableOutput.Create(playableGraph, "AnimationPlayableOutput", animator);
AudioPlayableOutput audioPlayableOutput = AudioPlayableOutput.Create(playableGraph, "AudioPlayableOutput", audioSource);
AnimationClipPlayable animationClipPlayable = AnimationClipPlayable.Create(playableGraph, animationClip);
AudioClipPlayable audioClipPlayable = AudioClipPlayable.Create(playableGraph, audioClip, true);
animationPlayableOutput.SetSourcePlayable(animationClipPlayable);
audioPlayableOutput.SetSourcePlayable(audioClipPlayable);
playableGraph.Play();
}
void OnDestroy()
{
playableGraph.Destroy();
}
}
示例5:控制播放状态
using UnityEngine;
using UnityEngine.Animations;
using UnityEngine.Playables;
[RequireComponent(typeof(Animator))]
public class PauseSubGraphAnimationSample : MonoBehaviour
{
public Animator animator;
public AnimationClip clip0;
public AnimationClip clip1;
PlayableGraph playableGraph;
AnimationMixerPlayable mixerPlayable;
void Start()
{
if (animator == null)
animator = GetComponent<Animator>();
playableGraph = PlayableGraph.Create("PauseSubGraphAnimation");
AnimationPlayableOutput playableOutput = AnimationPlayableOutput.Create(playableGraph, "AnimationPlayableOutput", animator);
mixerPlayable = AnimationMixerPlayable.Create(playableGraph, 2);
playableOutput.SetSourcePlayable(mixerPlayable);
AnimationClipPlayable clipPlayable0 = AnimationClipPlayable.Create(playableGraph, clip0);
AnimationClipPlayable clipPlayable1 = AnimationClipPlayable.Create(playableGraph, clip1);
playableGraph.Connect(clipPlayable0, 0, mixerPlayable, 0);
playableGraph.Connect(clipPlayable1, 0, mixerPlayable, 1);
mixerPlayable.SetInputWeight(0, 1.0f);
mixerPlayable.SetInputWeight(1, 1.0f);
clipPlayable1.Pause();
playableGraph.Play();
}
void OnDestroy()
{
playableGraph.Destroy();
}
}
我们看到虽然暂停了Run动画的播放,但是动作还是融合了停止的Run和变化的Walk,说明停止播放仍然会有输出,只是输出是静态的
示例6:控制播放时间
我们可以自定设置播放的时间
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Animations;
[RequireComponent(typeof(Animator))]
public class PlayWithTimeControlSample : MonoBehaviour
{
public Animator animator;
public AnimationClip clip;
public float time;
PlayableGraph playableGraph;
AnimationClipPlayable clipPlayable;
void Start()
{
if (animator == null)
animator = GetComponent<Animator>();
playableGraph = PlayableGraph.Create("PlayWithTimeControl");
AnimationPlayableOutput output = AnimationPlayableOutput.Create(playableGraph, "Output", animator);
clipPlayable = AnimationClipPlayable.Create(playableGraph, clip);
output.SetSourcePlayable(clipPlayable);
playableGraph.Play();
clipPlayable.Pause();
}
void Update()
{
clipPlayable.SetTime(time);
}
void OnDestroy()
{
playableGraph.Destroy();
}
}
如果这个Clip是循环的,就会循环,如果不是循环的,超过时间后就停止在最后一帧了
示例7:动画播放队列
我们还可以创建自定义的PlayableBehaviour来实现更多的功能,这里我们实现一个依次播放动画队列的功能
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Animations;
public class PlayQueuePlayable : PlayableBehaviour
{
int currentClipIndex = -1;
float timeToNextClip;
Playable mixer;
public void Initialize(AnimationClip[] clipsToPlay, Playable owner, PlayableGraph graph)
{
owner.SetInputCount(1);
int clipCount = clipsToPlay.Length;
mixer = AnimationMixerPlayable.Create(graph, clipCount);
graph.Connect(mixer, 0, owner, 0);
owner.SetInputWeight(0, 1);
for (int clipIndex = 0; clipIndex < clipCount; clipIndex++)
{
var clipPlayable = AnimationClipPlayable.Create(graph, clipsToPlay[clipIndex]);
graph.Connect(clipPlayable, 0, mixer, clipIndex);
mixer.SetInputWeight(clipIndex, 1.0f);
}
}
public override void PrepareFrame(Playable playable, FrameData info)
{
int clipCount = mixer.GetInputCount();
if (clipCount == 0)
return;
timeToNextClip -= info.deltaTime;
if (timeToNextClip <= 0.0f)
{
currentClipIndex++;
if (currentClipIndex >= clipCount)
{
currentClipIndex = 0;
}
var currentClip = (AnimationClipPlayable)mixer.GetInput(currentClipIndex);
currentClip.SetTime(0);
timeToNextClip = currentClip.GetAnimationClip().length;
}
for (int clipIndex = 0; clipIndex < clipCount; clipIndex++)
{
if (clipIndex == currentClipIndex)
mixer.SetInputWeight(clipIndex, 1.0f);
else
mixer.SetInputWeight(clipIndex, 0.0f);
}
}
}
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Animations;
[RequireComponent(typeof(Animator))]
public class PlayQueueSample : MonoBehaviour
{
public Animator animator;
public AnimationClip[] clipsToPlay;
PlayableGraph playableGraph;
void Start()
{
playableGraph = PlayableGraph.Create("PlayQueue");
var playQueuePlayable = ScriptPlayable<PlayQueuePlayable>.Create(playableGraph);
var playQueueBehaviour = playQueuePlayable.GetBehaviour();
playQueueBehaviour.Initialize(clipsToPlay, playQueuePlayable, playableGraph);
var playableOutput = AnimationPlayableOutput.Create(playableGraph, "Output", animator);
playableOutput.SetSourcePlayable(playQueuePlayable);
playableOutput.SetSourceOutputPort(0);
playableGraph.Play();
}
void OnDestroy()
{
playableGraph.Destroy();
}
}
本文
https://blog.csdn.net/ithot/article/details/123966332
测试工程
https://github.com/MonkeyTomato/PlayablesExample
参考
https://docs.unity3d.com/2018.4/Documentation/Manual/Playables-Examples.html
|