您现在的位置是:首页 >技术交流 >Unity Timeline使用网站首页技术交流

Unity Timeline使用

[奋斗不止] 2024-06-03 11:54:19
简介Unity Timeline使用

Unity Timeline使用

1.创建Timeline:打开面板Window->Sequencing->Timeline

(1.1)选择一个要添加 Timeline 的物体,我创建一个物体就叫 Timeline(可以随意命名),选择Timeline,然后在面板上显示 Create 按钮,如下

在这里插入图片描述
点 Create 按钮,保存一个 *.playable 的文件,然后自动给Timeline物体添加一个 PlayableDirector 脚本
脚本参数 Playable :TestTimeline 就是创建的 TestTimeline.playable 文件
Play On Awake:勾选则自动播放
在这里插入图片描述
选择GameObject Timeline可以看到 Timeline 面板

2.创建Activation Track (显示/隐藏物体轨道

(2.1)在左侧空白处,鼠标右键,选择 ActivationTrack

在这里插入图片描述

(2.2) 创建一个 Cube,为了方便管理,放在 Timeline 下方

在这里插入图片描述
然后拖拽到 Activation 轨道的目标物体上
右侧Active区域是Cube物体显示的时间区域(Timeline执行到这个时间段,物体是显示的,在这个时间段之外时,物体都是隐藏的)
可以左右拖动,可以把鼠标放在左右两侧拉长时间区域

(2.3)点击左侧对勾区域,Post-playback state

在这里插入图片描述
Active状态:Timeline完成播放时,将绑定的游戏对象的状态设置为激活(显示)状态
Inactive状态:Timeline完成播放时,将绑定的游戏对象的状态设置为停用(隐藏)状态
Revert状态:Timeline开始播放之前,将绑定的游戏对象的状态设置为停用(隐藏)状态
Leave As Is状态:Timeline完成播放时,绑定的对象状态是显示的就设置为显示状态,Timeline完成播放时,绑定的对象状态是隐藏的,就设置为隐藏状态
名词解释:
**Timeline完成播放时:**Timeline播放时间到,所有轨道结束时,才是Timeline完成播放时

(2.4)选择轨道上的 Active,在 Inspector 面板上可以看到参数

Start:开始时间(秒) f:帧(60帧/秒)
End:结束时间(秒)
Duration:持续时间(秒)
在这里插入图片描述

(2.4.1)选择挂Playable Director 脚本的GameObject,在 Timeline窗口左上角,点击三角预览播放

(2.4.2)直接运行Unity也可以预览播放

在这里插入图片描述

(3)创建 Animation Track (动画轨道)

(3.1)空白位置鼠标右键,选择 Animation Track

在这里插入图片描述
创建一个 Cube 拖拽到 None 位置
在这里插入图片描述
提示 Create Animator on Cube:添加Animator 组件到Cube上,点击Create 即可,自动在 Cube 上挂一个Animator 组件

(3.2)添加动画帧

在轨道空白位置鼠标右键
在这里插入图片描述
Create Annotation from clipboard contents:创建一个动画帧,在动画轨道上出现标签如下
在这里插入图片描述
AddFrom Animation Clip:弹出窗口选择一个现有的动画帧
也可以直接将一个动画帧拖拽到轨道上,如角色预制体拖拽到左侧作为绑定对象,然后将角色的动画拖拽到轨道上即可实现播放

(3.3) 创建 Create Annotation from clipboard contents

(3.3.1)点击左侧红色圆圈,开始录制,在轨道上显示红色并且有 Recoding… 字体提示

然后选择绑定的对象 Cube,在Inspector面板上,可以选择Cube上添加的可用组件添加动画帧
如Transform,可以分别在 Position、Rotation、Scale 位置鼠标右键 弹框选择 AddKey
在这里插入图片描述
点击 AddKey将在左侧轨道下方出现选择的属性,点击下方图中红色位置,可以显示隐藏编辑属性

展开如下
在这里插入图片描述

(3.3.2)在轨道区域双击打开动画编辑窗口

在这里插入图片描述
切换到 Curves 编辑动画
在这里插入图片描述

(3.3.3)左上角Recorded为保存的动画名,动画存放在当前编辑的TestTimeline.playable 下方,如下图,保存多个动画会自动命名为 Recorded(1)、Recorded(2)、Recorded(3)…

在这里插入图片描述

(3.3.4)点击动画轨道上的动画帧,在Inspector面板查看参数,如下

在这里插入图片描述
在这里插入图片描述
Track Offsets:将相同的位置和旋转偏移应用到动画轨道上所有的动画片段

  • Position: 添加控制Position 动画帧
  • Rotation: 添加控制 Rotation 动画帧

Apply Foot IK:启用动画反向动力学功能
Apply Avatar Mask:启动/禁用动画骨骼遮罩,启动遮罩时,所选的遮罩会应用到当前动画轨道上所有的动画片段
Default Offset Match Fields:动画轨道上所有的动画片段在进行匹配片段偏移时,选择默认的匹配选项

(3.4)AddFrom Animation Clip 添加一个现有动画帧

在这里插入图片描述

(3.4.1)将角色拖拽到左侧绑定

在这里插入图片描述
模型需要添加Animator脚本
Animator属性Controller为空即可
在这里插入图片描述

(3.4.2)在右侧轨道右键 AddFrom Animation Clip 或者拖拽一个动画帧到轨道上

运行或者预览即可查看动画播放

(3.4.3)在轨道上选择动画帧,在Inspector面板查看参数

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

可以修改片段的名称

(3.4.3.1)Clip Timing 属性包含一下内容

Start:动画片段开始时间
End:动画片段结束时间
Duration:动画片段持续时间
Ease In Duration:淡入动画片段所需时间
Ease Out Duration:淡出动画片段所需时间

(3.4.3.2)

Pre-Extrapolate:设置该动画帧开始播放前的状态,该属性会影响动画片段的淡入
None:在播放clip前Capsule会保持真实位置而不是动画位置
Hold:在播放clip前Capsule会保持第一帧动画位置
Loop:在播放clip前不停循环clip,保证在clip开始前动画内容正好播到结尾,不过开头不一定(主要看留出时间)
Ping Pong:会播放来回clip(会自动补动画),保证在clip开始时机前动画内容正好回到开头
Continue:只能在unity运行时查看,保持的是Loop或Hold选项的状态
Post-Extrapolate:设置动画片段的后外推,该属性影响动画片段的淡出

(3.4.3.3)Blend Curves:包含以下属性

In:自动/手动调整动画片段的淡入曲线
Out:自动/手动调整动画片段的淡出曲线

(3.4.3.4) Animation Playable Asset:包含以下属性

Clip Transform Offsets:将位置和旋转偏移应用于所选动画片段的根运动
Offset Match Fields:进行匹配片段偏移时,在片段级别上设置的匹配选项

(3.4.4)动画融合,拖拽两个动画相互穿插控制融合时间

在这里插入图片描述

(4) 创建 Audio Track (音效轨道)播放音效

在这里插入图片描述

(4.1)轨道添加音效

在这里插入图片描述
轨道空白处右键 Add From Audio Clip 或者直接将音效拖拽到轨道上

(4.2)音效参数

在这里插入图片描述
点击轨道上音效片段,Inspector 面板查看参数

(4.2.1)Audio Playable Asset:包含以下属性

Clip:选择音频片段使用的音频文件。
Loop:设置音频片段是否循环播放。
Volume:设置音频片段的音量。

(5)Signal Track:信号轨道,发射信号,相当于发送一个事件

(5.1)在TimeWindow面板左侧空白区域,右键选择 Signal Track

在这里插入图片描述
在这里插入图片描述
创建后显示如上,

(5.2)创建一个接收信号的 GameObject,我命名为 SingleReceiveObj,然后拖拽到左侧 None(Signal Receiver) 位置,提示添加 Create Signal Receiver 脚本,选择 Create 即可在 GameObject 上自动挂 Signal Receiver 脚本,如下

在这里插入图片描述

(5.3) 在信号轨道空白处右键添加一个发射器

在这里插入图片描述
Add Signal Emitter:创建一个信号发射器,发射器显示如下
在这里插入图片描述
点击信号发射器看Inspector 面板,Emit Signale 位置可以选择已经创建的发射器
在这里插入图片描述
Time:发射信号的时间
Retroactive:
EmitOnce:勾选后只会发射一次信号
Emit Signal:选择一个发射信号Asset,可以复用之前创建的,也可以选择 Create Signal 创建一个
Add Signal Emitter From Signal Asset: 会打开选择窗口,可以选择已经创建的发射器

(5.4)配置接收函数

// 创建一个接收信号的脚本,类名随意
public class SignalReceiveTest : MonoBehaviour
{
    public void OnTimelineSignal()
    {
        Debug.LogError("收到信号了");
    }
}

SignalReceiveTest 脚本挂到 SingleReceiveObj 物体上
Signal Receiver 下方点击 AddReaction
在这里插入图片描述
在这里插入图片描述
点击 +
选择 Runtime,在 NoFunction 处下拉选择 SignalReceiveTest 脚本上的 OnTimelineSignal 函数
在这里插入图片描述
运行预览,时间轴执行到信号发射器位置时,将会调用到 OnTimelineSignal 函数

(5.5).自定义信号

(5.5.1)新建信号发射类,继承 SignalEmitter

using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;

// 自定义的信号
public class CustomSignal : SignalEmitter
{
    // 自定义参数
    public string eventName;
    public int param;
}

创建一个 Signal Track 轨道,然后在右侧右键,如下可以看到新建的信号发射器
在这里插入图片描述
创建一个接收信号的GameObject我命名为 CustomSignalReceiverObj,添加 SngnalReceiver 脚本,并拖拽到信号轨道

(5.5.2)选择新创建的 Custom Signal,在Inspector 面板可以看到 CustomSignal 类的两个参数 eventName和 param,可以手动输入参数值

在这里插入图片描述

(5.5.3) 创建信号接收类

/// <summary>
/// 自定义信号接收器
/// </summary>
public class CustomSignalReceiver : MonoBehaviour, INotificationReceiver
{
    public void OnNotify(Playable origin, INotification notification, object context)
    {
        var signal = notification as CustomSignal;
        if (signal != null
            && signal.asset != null)
        {
            Debug.LogError(signal.number + "   " + signal.param);
        }
    }
}

将脚本CustomSignalReceiver挂到 CustomSignalReceiverObj
选择添加的自定义信号发射器Custom Signal 如下
在这里插入图片描述
查看Inspector面板下方显示
在这里插入图片描述
运行后将自动触发 CustomSignalReceiver 类的 OnNotify 函数

(6)创建 Control Track

在这里插入图片描述

(6.1)控制物体显示

方法一:将场景内的物体拖拽到右侧轨道上绑定,下方 Sphere
方法二:将预制体拖拽到右侧轨道上绑定,下方 Cube1
在这里插入图片描述
运行,时间轴执行到轨道开始时间时,将绑定物体显示出来,轨道时间结束后隐藏
Control Track 绑定的如果是场景内的物体,则直接控制其显示/隐藏
Control Track 绑定的如果是预制体,可以自动加载预制体并控制其显示隐藏

(6.2)点击轨道上的片段,在Inspector 面板查看参数

在这里插入图片描述
在这里插入图片描述
SourceGameObject:绑定的物体是场景内的GameObject 如上 Sphere

  • Prefab:预制体拖拽到轨道上,Prefab属性关联对绑定对象的引用,如上 Cube1

Post PlayBack 同 (2.3) Post-playback state

(6.3)Control Track嵌套控制其他的Timeline

再创建一个Timeline2
Playable Director 脚本Play On Awake 不勾选(不自动播放)
在这里插入图片描述
在 Timeline上创建一个Control Track,将Timeline2 拖拽到右侧轨道上,嵌套到Timeline
在这里插入图片描述

(6.4)在 Timeline选择被嵌套的 Timeline2,查看Inspector面板

Control Activation:
勾选时,Timeline 执行时会调用 Timeline2,主要让Timeline2做一些前置处理
不勾选时,Timeline执行时需要等到Timeline2时间开始位置才触发Timeline2
在这里插入图片描述
看例子,下面是 Timeline2控制一个Cube的显示
在这里插入图片描述

(6.4.1)如果在Timeline轨道上将Timeline2 的 Control Activation 勾选,则Timeline一开始执行,Timeline2控制Cube 立即隐藏,直到执行到 Timeline2需要显示Cube的时候,才将 Cube显示出来

(6.4.2)如果在Timeline轨道上将Timeline2 的 Control Activation 不勾选,则Timeline一开始执行,Timeline2 不会控制Cube隐藏(Cube一开始是显示的),知道执行到Timeline2开始时间位置,Timeline2才控制Cube先隐藏,然后时间到 Active 位置时将Cube显示

(7)添加 TrackGroup(轨道组)

将多个轨道规划为一个组,方便管理,先创建一个 TrackGroup,然后在TrackGroup
在这里插入图片描述

(8)操作辅助

(8.1) Lock轨道加锁,选中一个轨道,在轨道空白位置,右键选择Lock

在这里插入图片描述
加锁标志如下
在这里插入图片描述
解锁:选择加锁的轨道,右键 Unlock
在这里插入图片描述
加锁的作用:当编辑完成一个轨道后,避免无意修改,加锁,该轨道将不能被编辑,也不能被删除,起到一个保护的作用,当需要编辑时解锁即可

(8.2)Mute 轨道静默,选中一个轨道,在轨道空白位置,右键选择Mute

在这里插入图片描述
静默标志如下
在这里插入图片描述
解除静默:选择静默的轨道,右键 Unmute
在这里插入图片描述
静默的作用:轨道静默后预览/播放时该轨道将不会播放,不生效了,当有多个轨道在编辑时,你想专注查看某一个或者一些轨道效果,可以将其他的轨道设置静默。

(8.3)轨道优先级

轨道排序优先级为,下面轨道优先级>上面轨道优先级
如果多个轨道控制的是同一个物体,则最下面的一个轨道生效
如何调整优先级:在左侧拖拽一个轨道,上下挪动,一条白线显示的位置就是可以放置的位置,在白线位置松开鼠标即可,如下
在这里插入图片描述

(8.4)三种模式:Mix model、Ripple model、Replace model

在这里插入图片描述
上图红色框中三个按钮分别对应Mix model、Ripple model、Replace model
Mix model:拖动右侧轨道上的剪辑相互独立,当两个剪辑相交时为,两个剪辑混合
Ripple model:拖动右侧轨道上的剪辑,会一同推动它左右两侧的剪辑
Replace model:拖动右侧轨道上的剪辑,当剪辑覆盖其他剪辑时,将其他剪辑替换掉

(9)添加自定义轨道

(9.1)我添加一个设置 Image 颜色的 自定义轨道,执行到轨道帧开始位置时改变Image颜色,轨道帧结束时将Image颜色设置为(0, 0, 0,0)

先看效果,下图中 TimeTest->Image Track 是自定义的轨道
绑定的对象类型为 UGUI->Image在这里插入图片描述

在这里插入图片描述
在轨道右侧,鼠标右键添加轨道帧,Add Image Asset 也是自定义添加的

(9.2)选中 ImageAsset 在 Inspector 面板查看参数

在这里插入图片描述
Image Asset 部分
Image Color:添加的自定义颜色属性,执行时将Image 的颜色设置为这个颜色
Param:添加的自定义 Int 类型属性

需要添加三个脚本

(9.3) 添加轨道帧资源,上方右键Add Image Asset 就是下面代码创建的

using System;
using UnityEngine;
using UnityEngine.Playables;

namespace TimeTest
{
    /// <summary>
    /// 创建轨道资源
    /// </summary>
    [Serializable]
    public class ImageAsset : PlayableAsset
    {
        // 设置的颜色
        public Color imageColor;
        // 参数
        public int param;

        public override Playable CreatePlayable(PlayableGraph graph, GameObject owner)
        {
            // 创建一个新的 Playable(Script类型)
            // ScriptPlayable<ImageMixerBehavior>.Create 实际接收两个参数
            // 第一个参数是 Graph
            // 第二个参数是 我们创建的这个Playable接收几个参数,默认不填写那么就是0个输入
            var playable = ScriptPlayable<ImageMixerBehavior>.Create(graph);

            // 通过 GetBehaviour 获取上面创建的 ImageMixerBehavior 类型实例
            var imageMixerBehavior = playable.GetBehaviour();
            // 将轨道资源参数赋值给 imageMixerBehavior
            imageMixerBehavior.imageColor = imageColor;
            imageMixerBehavior.param = param;

            // 返回 Playable 类型实例,Unity会帮我们自动连接
            return playable;
        }
    }
}

(9.4)添加轨道,TimeTest->Image Track 就是下面代码创建的

using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;
using UnityEngine.UI;

namespace TimeTest
{
    /// <summary>
    /// 自定义 Timeline 轨道 ImageTrack (名字随意定)
    /// 在 Timeline 添加轨道位置右键,新加 TimeTest->ImageTrack
    /// </summary>
    [TrackColor(0.13f, 0.18f, 0.9f)]     // 轨道颜色
    [TrackBindingType(typeof(Image))]    // 绑定对象类型为 UnityEngine.UI.Image
    [TrackClipType(typeof(ImageAsset))]  // 轨道帧类型为 ImageAsset (也需要自定义)
    public class ImageTrack : TrackAsset
    {
        public override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount)
        {
            return ScriptPlayable<ImageMixerBehavior>.Create(graph, inputCount);
        }
    }
}

(9.5)添加轨道执行逻辑

using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.UI;

namespace TimeTest
{
    /// <summary>
    /// 继承自 PlayableBehaviour,定义 Playable 的行为
    /// </summary>
    public class ImageMixerBehavior : PlayableBehaviour
    {
        private Image img;

        public Color imageColor;
        public int param;

        /// <summary>
        /// 重写 OnBehaviourPlay 函数,第一次执行到轨道帧开始的时间
        /// </summary>
        /// <param name="playable"></param>
        /// <param name="info"></param>
        public override void OnBehaviourPlay(Playable playable, FrameData info)
        {
            base.OnBehaviourPlay(playable, info);
        }

        /// <summary>
        /// 重写 ProcessFrame 函数,Timeline 开始执行,直到所有轨道结束,每帧都会调用这个方法
        /// </summary>
        /// <param name="playable"></param>
        /// <param name="info"></param>
        /// <param name="playerData">绑定对象 类型为:ImageTrack 类设置的 TrackBindingType 类型 Image</param>
        public override void ProcessFrame(Playable playable, FrameData info, object playerData)
        {
            Color blendColor = Color.clear;

            // 转换为绑定对象 Image
            img = playerData as Image;
            int inputCount = playable.GetInputCount();
            if (null != img && inputCount > 0)
            {
                for (int i = 0; i < inputCount; i++)
                {
                    float weight = playable.GetInputWeight(i);
                    ImageMixerBehavior imageMixerBehavior = ((ScriptPlayable<ImageMixerBehavior>)playable.GetInput(i)).GetBehaviour();

                    // 获取颜色值
                    blendColor += imageMixerBehavior.imageColor * weight;
                }

                // 给绑定的 Image 对象设置颜色
                img.color = blendColor;
            }
        }

        /// <summary>
        /// 执行到当前轨道帧 End Time
        /// </summary>
        /// <param name="playable"></param>
        /// <param name="info"></param>
        public override void OnBehaviourPause(Playable playable, FrameData info)
        {
            base.OnBehaviourPause(playable, info);
            if (null != img)
            {
                img.color = Color.clear;
            }
        }
    }
}

执行即可预览效果

(10)代码控制播放、暂停、停止

public class PlayableDirectorController : MonoBehaviour
{
    private PlayableDirector playableDirector;
    void Start()
    {
        playableDirector = GetComponent<PlayableDirector>();
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetKeyDown(KeyCode.A))
        {
            // 暂停播放,时间轴停在当前位置
            playableDirector.Pause();
        }

        if (Input.GetKeyDown(KeyCode.D))
        {
            // 播放/继续播放,从时间轴当前位置播放
            playableDirector.Play();
        }

        if (Input.GetKeyDown(KeyCode.W))
        {
            // 停止播放,时间轴回到0
            playableDirector.Stop();
        }
    }
}
风语者!平时喜欢研究各种技术,目前在从事后端开发工作,热爱生活、热爱工作。