当前位置: 首页 > 工具软件 > log2timeline > 使用案例 >

TimeLine的使用和自定义TimeLine控制

司空鸿熙
2023-12-01

1.unity2017版本中最新出炉Timeline
第一次看到timeline觉得这个东西和以前自己的做视频时使用的剪辑软件video studio/premiere/After Effect等非常的相似,同样的视频轨道,随意滑动,非常便于操作 如下图所示。

现在开始简要介绍一下timeline的基本操作:

     1.直接在面板上新建一个空物体,create empty,随便取个名字叫做timeline manger;

     2.直接点击windows ,点击timeline  editor;就会弹出如上图所所示的timeline 操作界面,然后删掉出现的第一个轨道。            因为没什么用。

3.点击timeline下面的add,就可以添加几个轨道: 其中

activeation track可以让物体在什么时间在什么地点出现或者消失;

animation track可以添加动画片段,或者自己点击红色圆圈自己录制动画;

audio track 可以添加音效片段;

playable track 可以写上控制代码,这里我在后面将重点讲解;

control track 自己还没有用过。。。。。;

2.timeline具体使用方法事例
目前网上已经有人将timeline的相关函数都进行了封装,我们可以很方便的进行使用。具体的封装方法见链接。点击打开链接

我自己稍微改了一下,具体代码见下。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;

public class TimelineUnit {

public string name;
public PlayableDirector director;
public PlayableAsset asset;
public Dictionary<string, PlayableBinding> bindings;
public Dictionary<string, Dictionary<string, PlayableAsset>> clips;
public Dictionary<string, PlayableAsset> playables;

public void Init(string path, PlayableDirector director)
{
    this.name = path;               // director标签
    this.director = director;       // 获取当前组件
    playables = new Dictionary<string, PlayableAsset>();
    InitPlayables(path);            // 获得所有的动画
}

public void Switch(string assetName)
{

    if (!playables.TryGetValue(assetName, out this.asset))
    {
        Debug.LogError("No Asset exist!");
        return;
    }
    director.playableAsset = asset; // 导演Manager
    
    bindings = new Dictionary<string, PlayableBinding>(); // PlayableAsset下的所有binding
    clips = new Dictionary<string, Dictionary<string, PlayableAsset>>(); // binding里的所有clip
    foreach (var o in asset.outputs) // 每一个binding,其实就是trackasset和需要动画的模型之间的链接关系
    {
        var trackname = o.streamName;
        bindings.Add(trackname, o);  // 每一个binding的名字和binding绑定

        var track = o.sourceObject as TrackAsset; // 每个binding下的对象为track
        var clipList = track.GetClips(); // 获得每一个track下的所有动画片段
        foreach (var c in clipList) // 存入clips
        {
            if (!clips.ContainsKey(trackname))
            {
                clips[trackname] = new Dictionary<string, PlayableAsset>();
            }
            var name2clips = clips[trackname];
            if (!name2clips.ContainsKey(c.displayName))
            {
                name2clips.Add(c.displayName, c.asset as PlayableAsset);
            }
        }
    }
}

// 清空数据
public void Remove()
{
    bindings.Clear();
    clips.Clear();
}

// 动画和模型进行绑定
public void SetBinding(string trackName, Object o)
{
    director.SetGenericBinding(bindings[trackName].sourceObject, o);
}

// 获得动画轨道
public T GetTrack<T>(string trackName) where T : TrackAsset
{
    return bindings[trackName].sourceObject as T;
}

// 获得动画片段
public T GetClip<T>(string trackName, string clipName) where T : PlayableAsset
{
    if (clips.ContainsKey(trackName))
    {
        var track = clips[trackName];
        if (track.ContainsKey(clipName))
        {
            return track[clipName] as T;
        }
        else
        {
            Debug.LogError("GetClip Error, Track does not contain clip, trackName: " + trackName + ", clipName: " + clipName);
        }
    }
    else
    {
        Debug.LogError("GetClip Error, Track does not contain clip, trackName: " + trackName + ", clipName: " + clipName);
    }
    return null;
}

// 读入所有动画资源
private void InitPlayables(string path)
{
    PlayableAsset[] o = Resources.LoadAll<PlayableAsset>(path + "/");
    foreach (var asset in o)
    {
        playables.Add(asset.ToString().Replace(" (UnityEngine.Timeline.TimelineAsset)", ""), asset);
        Debug.Log(asset.ToString());
    }
}

// 控制动画的播放,停止等
public void Play()
{
    director.Play();
}

public void pause()
{

    director.Pause();
 
}

public void Stop()
{

    director.Stop();

}
public void Resume()
{

    director.Resume();

}

}

下面是自己的代码:

(注意:TextPlayableBehaviour 不用挂在物体上,里面包含了不同情况下自动执行的逻辑)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.UI;

// A behaviour that is attached to a playable
public class TextPlayableBehaviour : PlayableBehaviour
{
public Text _text;
public string s;
private PlayableDirector director;
// Called when the owning graph starts playing
public override void OnGraphStart(Playable playable)
{
director = GameObject.Find(“TimelineManager”).GetComponent();//找到timelinemanger,取得控制权

}
 Called each frame while the state is set to Play
public override void PrepareFrame(Playable playable, FrameData info)
{
    _text.text = s;
}

public override void OnBehaviourPlay(Playable playable, FrameData info)
{
   
    _text.enabled = true;//为了让text可视化
    //  Debug.Log("为true了");
}

 Called when the state of the playable is set to Paused
public override void OnBehaviourPause(Playable playable, FrameData info)
{
  _text.enabled = false;
    if (director.time > 0.4f)//因为未知原因导致,一开始就检测到了onbehavior pause,所以设定一定的时间范围,延缓0.4s再检测,此时onbehavior pause是在正常的地方停下
    {
        director.Pause();
    }
}

 Called when the owning graph stops playing
//public override void OnGraphStop(Playable playable) {
//    //director.Pause();
//   Debug.Log("OnGraphStop起作用了");
//}

 Called when the state of the playable is set to Play
//public override void OnBehaviourPlay(Playable playable, FrameData info) {

//    _text.enabled = true;
//}

 Called when the state of the playable is set to Paused
//public override void OnBehaviourPause(Playable playable, FrameData info) {

//   // director.Pause();
//    Debug.Log("OnBehaviourPause起作用了");

//}

}
(注意:TextPlayableAsset写好后,直接在playableTrack中的直接add 就行了,这里主要是生成了一个具体的TextPlayableAsset,其中new了一个TextPlayableBehaviour 的对象)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.UI;
using TMPro;

[System.Serializable]
public class TextPlayableAsset : PlayableAsset
{
public ExposedReference text;
public string s;

// Factory method that generates a playable based on this asset
public override Playable CreatePlayable(PlayableGraph graph, GameObject go) {

    TextPlayableBehaviour t = new TextPlayableBehaviour();
    t._text = text.Resolve(graph.GetResolver());
    t.s = s;
   
    // Debug.Log("textplayableasset"+s);
  //  t._text.enabled = false;
    
    return ScriptPlayable<TextPlayableBehaviour>.Create(graph, t);
}

}
接下来就创建一个空物体,名字叫做timelinemanger,自己写一个timelinemanger的函数,里面new一个timelineunit的对象,就可以使用timeline中的各种方法了。(由于项目中的方法太复杂,也就不便于贴出来了)但是出于对读者的尊重,我还是写一个(awake的函数)吧。剩下的就是如何触发play 或者是stop了,这就交由读者了。

private void Awake () {
director = GetComponent();
text = GameObject.Find(“text_result”);
//如果没有PlayableDirector,则添加
if (null == director)
{
director = gameObject.AddComponent();
}
//初始化工作
helper = new TimelineUnit();
helper.Init(“operaiton_Animation”, director);
text.GetComponent ().text = null;
helper.Switch(timeline_name);
helper.SetBinding(“Animation Track”, GameObject.Find(“garbage car”));

}

其中在使用过成中的一些注意如下:

(1)setbinding函数必须得有一个动画轨道,也就是你必须得在使用switch()函数之后才能够调用setbinding函数将自己的动画与对象进行绑定。

(2)你可以参照下面的代码,直接复制粘贴一个PlayableAsset和PlayableBehaviour,这样你就可以动态的显示文字了,但是好像不能当时就改变(这里大家如果做到了,麻烦跟我说一下)。而且如果是多个PlayableAsset对应这同一个textUI,那么在playabletrack中的PlayableAsset最好起不一样的名字,因为会产生错误(比如找不到对应的PlayableAsset)。

(3)我不知道PlayableAsset中的ExposedReference是什么意思,为什么没有它就不能传值了,此处我并没有做过具体实验,(大牛如果知道,告诉小弟我一声)。

 类似资料: