IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> Unity自定义播放控制(二)——Playables示例 -> 正文阅读

[游戏开发]Unity自定义播放控制(二)——Playables示例

概述

本篇介绍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 = PlayableGraph.Create("PlayAnimationSample");
        playableGraph.SetTimeUpdateMode(DirectorUpdateMode.GameTime);
        // 创建Playable
        AnimationClipPlayable playable = AnimationClipPlayable.Create(playableGraph, clip);
        // 创建PlayableOutput
        AnimationPlayableOutput playableOutput = AnimationPlayableOutput.Create(playableGraph, "Animation", animator);
        // 链接PlayableOutput和Playable
        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>();
        // playableGraph = PlayableGraph.Create("PlayAnimationUtilitesSample");
        // 这个方法会产生一个新的playableGraph,所以我们无需提前创建,创建后会导致存在两个Graph,可以通过Visualizer看出来
        AnimationPlayableUtilities.PlayClip(animator, clip, out playableGraph);
    }
    void OnDestroy()
    {
        playableGraph.Destroy();
    }
}

在这里插入图片描述
在这里插入图片描述

示例2:混合动画

我们可以使用AnimationMixerPlayable来混合两个动画片段


using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Animations;
/// <summary>
/// 动画混合
/// </summary>
[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连接
        graph.Connect(clipPlayable0, 0, mixerPlayable, 0);
        graph.Connect(clipPlayable1, 0, mixerPlayable, 1);
        // 用Playable连接都可以
        // mixerPlayable.ConnectInput(0, clipPlayable0, 0);
        // mixerPlayable.ConnectInput(1, clipPlayable1, 0);
        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;
/// <summary>
/// 混合动画片段和Controller
/// </summary>
[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.SetPlayState(PlayState.Paused);
        clipPlayable1.Pause();  // SetPlayState方法已经被弃用了,可以直接使用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)
    {
        //用动画混合AnimationMixerPlayable作为输入,所以只有1个输入
        owner.SetInputCount(1);
        int clipCount = clipsToPlay.Length;
        mixer = AnimationMixerPlayable.Create(graph, clipCount);
        graph.Connect(mixer, 0, owner, 0);
        owner.SetInputWeight(0, 1);
        // 将所有的动画Clip创建对应的Playable
        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++)
        {
            // 让当前正在播的动画的权重为1,其余全部为0,以此达到只播一个的效果
            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

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2022-04-06 16:21:40  更:2022-04-06 16:22:35 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 -2025/1/16 20:03:46-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码