# custom_timeline
**Repository Path**: liuyaoif/custom_timeline
## Basic Information
- **Project Name**: custom_timeline
- **Description**: 扩展unity的timeline,实现自定义轨道(track)和clip。
- **Primary Language**: Unknown
- **License**: WTFPL
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 1
- **Forks**: 3
- **Created**: 2021-12-31
- **Last Updated**: 2024-09-12
## Categories & Tags
**Categories**: Uncategorized
**Tags**: Unity
## README
# Timeline扩展方案
> Timeline默认的Track和Clip如下。
> 
> 如果想让Timeline驱动游戏逻辑,需要自定义TrackAsset,PlayableBehaviour和PlayableAsset 来实现。目前有3种方式使用自定义功能。
> ||
> |:----:|
> |Playable track|
> |ClipBehaviour|
> |TrackBehaviour|
>
## 1. Playable track方式
1. 添加一条Playable track。
。
1. 创建一个PlayableAsset脚本: create->Playables->Playable Assets C# Script。
2. 拖到Playable track上。
> 这个方法受限制严重,不推荐使用。
## 2. ClipBehaviour
1. 创建一个TrackAsset的C#脚本。
```CSharp
[TrackClipType(typeof(TextTLAsset))]
[TrackBindingType(typeof(Text))]
public class TextTLTrack : TrackAsset
{
///
/// TrackAsset在创建时必然会遍历所有的Clip,有机会给所有的clip传值
///
///
///
///
///
protected override Playable CreatePlayable(PlayableGraph graph, GameObject gameObject, TimelineClip clip)
{
PlayableDirector direct = graph.GetResolver() as PlayableDirector;
//在Clip创建时传参
TextTLAsset asset = clip.asset as TextTLAsset;
asset.Label = direct.GetComponent().label;
return base.CreatePlayable(graph, gameObject, clip);
}
}
```
> TrackAsset实现CreatePlayable方法,这条Track上每一个Clip(拖拽一个Asset就有一个Clip)都会调用一次这个方法。利用这个方法给Asset传参数。这里传递了label这个控件。
2. 创建一个PlayableAsset的C#脚本。
```CSharp
[System.Serializable]
public class TextTLAsset : PlayableAsset
{
public Text Label { set; get; }
public string Content;
///
/// 在创建时向Behaviour传引用
///
///
///
///
public override Playable CreatePlayable(PlayableGraph graph, GameObject go)
{
//创建ClipBehaviour
var playable = ScriptPlayable.Create(graph);
var behaviour = playable.GetBehaviour();
behaviour.Label = Label;
behaviour.Content = Content;
return playable;
}
}
```
> PlayableAsset实现CreatePlayable方法,并Create一个PlayableBehaviour,这个Behaviour的生命周期是绑定这个Asset的。也就是说有多个Clip就有多少Behaviour实例,所以称之为ClipBehaviour。Asset向自己的Behaviour传参Label控件和Content参数。
3. 创建一个PlayableBehaviour的C#脚本。
```CSharp
[Serializable]
// A behaviour that is attached to a playable
public class TextTLBehaviour : PlayableBehaviour
{
public Text Label;
public string Content;
public override void OnBehaviourPlay(Playable playable, FrameData info)
{
if (Label != null)
{
Label.text = Content;
}
}
public override void OnBehaviourPause(Playable playable, FrameData info)
{
if (Label != null)
{
Label.text = string.Empty;
}
}
}
```
> Behaviour实现OnBehaviourPlay和OnBeahviourPause两个方法,当时间线走到对应的Asset时就会调用到。
> 
> 这个方案适合于做连续台词等不需要混合的需求。
## 3. TrackBehaviour
> TrackBehaviour方式和ClipBehaviour大部分相似,也是需要自定义的TrackAsset,PlayableBehaviour和PlayableAsset。区别在于PlayableBehaviour由TrackAsset创建而不是Asset。
1. 创建TrackAsset
```CSharp
[TrackClipType(typeof(ColorTLAsset))]
[TrackBindingType(typeof(Text))]
public class ColorTLTrack : TrackAsset
{
public ScriptPlayable TrackBehaviourPlayable;
private ColorTLBehaviour behaviour;
//创建Track混合器而不是Clip
public override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount)
{
//取外部引用
PlayableDirector direct = graph.GetResolver() as PlayableDirector;
Text label = direct.GetComponent().label;
//创建TrackBehaviour并设置inputCount,inputCount就是Clip的个数
TrackBehaviourPlayable = ScriptPlayable.Create(graph);
TrackBehaviourPlayable.SetInputCount(inputCount);
behaviour = TrackBehaviourPlayable.GetBehaviour();
//传递参数
behaviour.label = label;
behaviour.track = this;
return TrackBehaviourPlayable;
}
}
```
> 注意,TrackBehaviour是TrackAsset创建,生命周期绑定到了TrackAsset上,当Track启动、结束后触发Behaviour的OnBehaviourPlay和OnBeahviourPause,这个Behaviour和Clip是没有关系的。
2. 创建PlayableAsset
```CSharp
[System.Serializable]
public class ColorTLAsset : PlayableAsset
{
public Color CurColor;
public override Playable CreatePlayable(PlayableGraph graph, GameObject go)
{
return Playable.Create(graph);
}
}
```
> TrackBehaviour方案的Asset比较简单,只是暴露参数用于设置就好了。
3. 创建PlayableBehaviour
```CSharp
public class ColorTLBehaviour : PlayableBehaviour
{
public Text label;
public ColorTLTrack track;
//OnBehaviourPlay和OnBehaviourPause方法和Clip没关系了,所以只能在ProcessFrame(Update)中获取
public override void ProcessFrame(Playable playable, FrameData info, object playerData)
{
//取ClipCount
int clipCount = playable.GetInputCount();
int index = 0;
for (int i = 0; i < clipCount; i++)
{
float weight = playable.GetInputWeight(i);
//Weight > 0f的Clip是进入了的Clip,可能有多个
if (weight > 0f)
{
index = i;
break;
}
}
//根据Clip的Index取Clip和Asset
ColorTLAsset curAsset = null;
foreach (var itr in track.GetClips())
{
if (index == 0)
{
curAsset = itr.asset as ColorTLAsset;
}
index--;
}
//赋值
if (label != null)
{
label.color = curAsset.CurColor;
}
}
}
```
> 该方法适合自动控制有融合的多个Clip之间的混合。[Timeline混合Demo](https://blogs.unity3d.com/2018/09/05/extending-timeline-a-practical-guide/)