自定义TimeLine

自定义TimeLine

什么是TimeLine

在 Unity 中,TimeLine(时间轴)是一种用于创建和管理动画序列的工具。它是 Unity 的一个可视化编辑器窗口,用于创建复杂的、时间驱动的动画、剧情和交互式体验。
Timeline 提供了一系列功能和资源,例如轨道(Track)、片段(Clip)、混合器(Mixer),数据(Data)等,用于组织和控制动画序列。你可以在 Timeline 上创建不同类型的轨道,如动画轨道、音频轨道、事件轨道等,然后将相应的片段添加到轨道上,并在时间轴上安排它们的播放顺序和属性变化。简单的可以理解为timeline就是这四个基本组成的。
了解了上述关于TimeLine的基本介绍之后就到了本篇的重点了,如下。我们只要实现这四个部分就是能自定以TImeLine了。

  • Data : 数据

  • Clip : 片段(放在轨道上的一段动画数据或片段)

  • Mixer:混合(将两个片段按照一定的规则进行融合)

  • Track :轨道(clip和Mixer的载体负责管理和组织)

Data(数据)

继承PlayableBehaviour

在这个类中一般我们只放数据,需要注意的是,这个类中存放的仅仅只是一个模板,真正的数据会在Clip中创建。

csharp 复制代码
using UnityEngine.Playables;

public class DataBehaviour : PlayableBehaviour
{
    public Transform exampleValue;
}

Clip(片段)

继承PlayableAsset 并实现ITimelineClipAsset。

注意:我们上面说了data中的是模板而Clip中才是我么珍重要用到的数据。下面的代码有点不好理解。现在把我们的Timeline比作一场演出,Data是存在Clip中的一些变量,我们把Clip当作一个剧本,但是我们要的是一场演出,光有剧本显然是不行的,我们需要把我们的剧本装换位我们想要的演出这个转换就是CreatePlayable。

csharp 复制代码
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;

public class TextDataClip : PlayableAsset,ITimelineClipAsset
{
    private DataBehaviour template;
   
    // 是否需要混合 Clip.None 不需要混合,blending 需要融合
    public ClipCaps clipCaps => ClipCaps.Blending;
    //需要把你想要展示的数据暴露出来,不然无法进行引用。
    public ExposedReference<Transform> exampleValue;
    // 在这个脚本中 需要理解为什么我们已经有了clip还需要 playable
    // 因为clip相当于戏的剧本而我们给观众是戏不是剧本,这个时候据需要Create 创建一个playable 作为戏来来演出。
    // graph 一个可播放图用于管理播放的行为。owner 表示拥有这个可播放对象的游戏对象。
    public override Playable CreatePlayable(PlayableGraph graph, GameObject owner)
    {
        // 我们需要一个playable 所以用工厂模式创建一个,graph代表我们是给谁创建,template 是我们的data实例表示把这个template创建为playable,但是我们知道这个Template是一个模板里面是没有数据的所以有了下一步
        var playable = ScriptPlayable<DataBehaviour>.Create(graph, template);
        // 我们需要从这个playable上面把clone的data取出来
        DataBehaviour clone = playable.GetBehaviour();
        // 因为mono behaviour 可以引用 mono behaviour 也可以引用 assets 但是反过来  assets 不能随意引用monobehaviour 但是可以通过反过来引用那个引用了assets的monobehaviour来引用其他的monobehaviour。
        // 之后在进行赋值
		clone.exampleValue = exampleValue.Resolve(graph.GetResolover());
        return playable;
    }
}

Track(轨道)

用于组织动画和音频剪辑的容器

继承 TrackAsset 并加上特性。

csharp 复制代码
[TrackColor(0/255f,255/255f,255/255f)] // 轨道的颜色
[TrackBindingType(typeof(GameObject))] // 要绑定的物品的类型是什么,需要给什么物体播放Timeline,可以是一个物体,也可以是一个脚本,或者是一个Aanimator等等
[TrackClipType(typeof(TextDataClip))] // 可以放到这个轨道上的clip是什么类型
csharp 复制代码
using UnityEngine.Timeline;

[TrackColor(0/255f,255/255f,255/255f)]
[TrackBindingType(typeof(Transform))]
[TrackClipType(typeof(DataClip))]
public class TextTrack : TrackAsset
{
	public override Playable CreateTrackMixer(PlayableGraph graph,GameObject go,int inputCount)
    {
       // var mixerPlayable = ScriptPlayable<CustomMixer>.Create(graph);//这个是被CustomMixer驱动的Playable,mixerPlayable.GetBehaviour() as CustomMixer;就可以获得CustomMixer了
        //mixerPlayable.SetInputCount(inputCount);
        //return mixerPlayable;
        //返回mixer
        return ScriptPlayable<CustomMixer>.Create(graph,inputCount);
    }
}

Mixer(混合)

Mixer会铺满整条轨道,他并不会知道现在在播放哪一个clip,他会询问在他上面的每一个clip的权重,当播放到某一个clip的时候这个clip的权重就会变成1但是当两个混合的时候 权重的大小就会变成一条斜线

csharp 复制代码
public class CustomMixer:PlayableBehaviour
{
    public override void OnPlayableCreate(Playable playable)
    {
        ...
    }
    public override void OnPlayableDestroy(Playable playable)
    {
        ...
    }

    public override void PrepareFrame(Playable playable, FrameData info)
    {
        ...
    }
    // 相当于update 会一直更新的
    public override void ProcessFrame(Playable playable, FrameData info, object playerData)
    {
        //得到绑定的东西(就是你需要修改的东西)
        Transform transform =  playerData as Transform;
        
        for(int i = 0 ; i < playable.GetInputCount(); i++)//获取轨道上所有的片段
        {
            float weight  = playable.GetInputWeight(i);//获取片段在当前帧的片段的权重
            var clipPlayable = (ScriptPlayable<CustomPlayableBehaviour>)playable.GetInput(i);// 获取当前的 
            CustomPlayableBehaviour behaviour = clipPlayable.GetBehaviour();//获取CustomPlayableBehaviour
            ...//接下来你可以根据Clip的权重写相应的逻辑(如果你没有在ClipCaps里设置blend的话,应该只有一个片段的权重是1,其他为0)
        }
    }

    //上面4个虚方法是最常用的,OnBehaviourPause不建议使用,不太好掌控(会因为各种原因暂停)。直接根据time值得变化判断是否暂停也挺好得
}

这里自定义TimeiLine就完成了,后面会做一个例子的。

相关推荐
4 小时前
Unity开发中常用的洗牌算法
java·算法·unity·游戏引擎·游戏开发
马特说7 小时前
Unity VR手术模拟系统架构分析与数据流设计
unity·系统架构·vr
心前阳光1 天前
Unity WebGL文本输入
unity·游戏引擎·webgl
天涯过客TYGK1 天前
unity A星寻路
unity·游戏引擎
KhalilRuan1 天前
Unity Demo——3D平台跳跃游戏笔记
笔记·游戏·unity·游戏引擎
ttod_qzstudio2 天前
Unity中使用EzySlice实现模型切割与UV控制完全指南
unity
南無忘码至尊2 天前
Unity 实现与 Ollama API 交互的实时流式响应处理
unity·游戏引擎·交互
平行云2 天前
如何实现UE程序大并发多集群的像素流部署
unity·ue5·图形渲染
向宇it3 天前
【unity小技巧】在 Unity 中将 2D 精灵添加到 3D 游戏中,并实现阴影投射效果,实现类《八分旅人》《饥荒》等等的2.5D游戏效果
游戏·3d·unity·编辑器·游戏引擎·材质
向宇it3 天前
Unity Universal Render Pipeline/Lit光照材质介绍
游戏·unity·c#·游戏引擎·材质