MMD联动Unity学习笔记 Vol.27 Timeline使用动画片段&自定义代码控制

前言
这期笔记来自Shallot夏洛特大佬的视频。主要内容是使用动画片段及自定义代码控制Timeline。视频在下面


使用动画片段
下面我们了解如何在Timeline编辑器的轨道里对角色使用不同的动画文件,并且如何对它们进行变换,并且还会介绍如何将我们录制的动画转换成为动画片段。
假如我们要做一个剪辑或者说是对话场景,我们有许多不同的动画,并且想让角色播放这些动画,让他看起来是与另外的角色在进行互动,在这个事例里我们就会使用Timeline播放不同的动画来达成这个目标。另外我们还会对相机录制动画来制作镜头剪辑。

在这场景里有两个角色模型都是使用了人型Rig。
在这里,我们想要做一个双方轮流互动的对话系统,所以我先设置好他们的位置,让他们面对面站着。

在每个角色的身后也都放置有一个相机,看向对方。同时也创建有一个Timeline,每一个角色放置在一个轨道上。

赋在这里的角色身上挂有Animator组件,组件里有对应的形象,这样Timeline可以直接对它们的动画形象应用动画片段。

这里也有许多轨道应用于不同的相机,如果我运行起来可以看到并没有什么事情发生,所以让我们给角色添加动画,给他们带来生命吧。

在角色动画轨道上,右键点击选择,从动画片段添加。

然后可以直接选取需要的动画片段。

或者可以直接从工程窗口直接拖入动画片段。可以直接拖动片段到我们想让它开始播放的位置。

我们还可以拖拽它的左端或者右端来缩短或者扩展它的播放时间。

如果想添加一个相同的片段,可以选中它,按下CTRL+D复制一个,或者鼠标右键选择复制。

直接把复制出来的片段拖给另一个角色。运行一下,两个角色看起来比之前有活力了。我们想要动画一直循环下去,可以设置属性来办到。

这些设置可以修改片段在播放前或者播放后的一些行为。让我们把它们的属性从“保持”改为"继续"。

预览一下,可以看到它,Timeline完成这些片段以后,它们还是在继续播放的,或者你可以扩展片段的长度到剪辑的最末端,有相同的效果。

我们再给角色添加另一个动画片段。

在初始化的时候,新片段会自动紧贴到上一个片段,可以连续播放。

如果我们把新的动画片段往前拖,那么这两个动画将会自动融合。往前拖得越长,融合的时间也会越长。

可以多次尝试找出你觉得最适合的融合时间点,我们可以拖动每一个片段的开始或者介绍端来对融合片段进行微调。
还需要知道的一点,是我们可以再次编辑融合曲线来调整融合动画。

默认被设置为自动曲线。如果想自定义可以修改成手动模式。

然后选择一个曲线预设。

或者自定义一个曲线。

这就是基本的动画片段操作,你可以继续给Timeline添加内容并编辑。

假设我们还需要一台相机,给他录制不同的位置,制作镜头,使用同一台相机,完成镜头剪辑,在这里我给相机录制了动画,我想把这两个轨道转换成片段,这样更灵活。

可以鼠标右键点击我们的录制数据轨道,然后选择转换成片段轨道。

然后其实可以只是用一个轨道来编辑了。

所以我删掉另外的轨道,非常方便,完美。


自定义代码控制Timeline
下面我们了解如何使用自定义脚本控制Playable Director,我们将会写一个叫做Timeline Controller的脚本,并引用一个Playable Director组件。另外我们还会介绍如何使用脚本来控制以及修改多个Playable Director组件。
假设在游戏里,玩家控制角色,按下这个按钮就会播放Timeline。场景里有一个带有按钮的讲台,它带有碰撞盒。

在讲台的前方设置了一个触发器,在讲台身上挂着这个脚本,脚本检测角色进入触发器以后,执行一个事件,在检测玩家是否会按下空格键。

我们还会在游戏里自定义代码,来播放一个Timeline。
在写代码之前取消勾选属性,它在运行时就不会自动播放了。

现在创建我们的脚本,选择C#脚本重命名为TimelineController。

要能访问Playable Director类需要using unityEngine.Playable。(unity2018已经取消内置的Mono IDE)

先定义一个公有变量,这样我们就可以把想控制的Timeline赋给它。再定义一个公有函数,返回值为void(没有返回值),函数体里就直接播放我们赋值的这个Timeline。

回到Unity,把这个脚本赋给对象,然后将需要播放的Timeline拖入脚本。

我们还要告诉Timeline Controller脚本何时播放,记住在你的工程里可以调用这个函数。然而在本示例里我想让玩家按下按钮的时候才调用play函数,所以我要从交互脚本里调用它。


现在只要按下空格键就可以播放Timeline剪辑了。场景里有一辆蓝色坦克,它身上也有一个Timeline。

如果我们把它的Timeline拖给我们的脚本,按下空格就可以播放。

现在我们想让这些剪辑同时播放,我们当然可以再创建一个按钮,但是我们现在只想使用一个按钮,按一次就可以播放所有剪辑,所以我们需要再修改一下代码。
回到Mono ,确保我们添加的这行代码(using System.Collections.Generic;),这样才可以使用list(列表)。将原先的单个组件改成一个列表,然后play函数也要修改,使用foreach循环来播放列表。

回到引擎,我们可以看到这里变成了列表,可以自定义数量。

我将需要播放的剪辑全部拖进来,按下空格键,它们都被播放了。

现在假设我们想用脚本控制一个对象上的多个Timeline,比如说坦克上有两个Timeline,一个是移动动画,另一个是炮头旋转。当玩家按下不同的按钮,坦克会播放不同的Timeline。 这个脚本的定义了两个事件,按下空格和回车可以执行不同的操作。

我们又会编辑控制器脚本,让它知道应该播放哪一个Timeline。请确保添加了这两行代码,这样才可以访问Timeline,以及使用列表。

首先定义一个公有的Timeline列表,然后我们需要从Timeline列表里获取它们的Playable Director组件,再写一个新的函数,参数使用整型作为索引值。索引是用来表示我们将播放Timeline列表中的哪一个。然后再定义一个局部变量,储存我们从列表里抽取的对象。最后这个脚本实际上只是播放一个Timeline而已。在这里我们就播放列表中的第一个元素,为了避免错误,我们需要确保我们抽取的索引值是小于列表值的。如果索引值大于列表的值,那我们就把索引设为列表里的最后一个元素。

回来引擎,把Timeline拖入脚本。

然后增加一个事件,把Timeline控制器脚本被拖入事件对象的接口。

设置播放函数的索引值为零。

同理,再设置另一个播放索引为1。

运行,先按下回车,第一个Timeline就会被播放了,接着按下空格。第二个就会播放。
你看到自定义代码仅仅几行,就可以轻松控制Timeline。

最后感谢Shallot夏洛特大佬的分享。示例代码请到大佬视频介绍中下载