系列文章目录
自定义TimeLine
前言
自定义TimeLine实际上就是自定义轨道, 在这里我们实现一个简单的例子,我使用的Unity版本是2021.3.20f1c1
创建的一个URP项目。其实Build-in也是一样的 但是有的代码可能需要改一下。
正文
在这里先介绍一下实现思路,因为要实现的是我们每次收看音乐频道的时候下方歌词的效果,首先我们需要创建两个Text一个在下面,作为底色,然后在控制上层的字进行移动以达到效果
UI部分
我使用TMP创建的Text,其中的结构如下图
其中有一个地方需要着重说一下就是 Mask 这是一个 空物体挂在了Rect Mask 2D 组件 用于遮挡文字实现效果,如果不使用遮罩而是直接控制Text会出现文字卡顿的现象为了避免这种现象所以使用的是遮罩。
还有就是需要把中心点设为(0,0)
还有就是创建一个空物体加上Playable Director 组件控制timeline。
代码部分
Data(数据)
csharp
using UnityEngine.UI;
using UnityEngine.Playables;
public class TextBehaviour : PlayableBehaviour
{
public string line; //我们要显示的文字
public float speed; // 文字移动的速度
}
Clip(片段)
csharp
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;
public class TextClip : PlayableAsset,ITimelineClipAsset
{
private TextBehaviour template;
//这俩个参数是参数,不需要进行拖拽操作所以没有使用再上一篇讲的暴露变量
public float speed;
public string Line;
public override Playable CreatePlayable(PlayableGraph graph, GameObject owner)
{
var playable = ScriptPlayable<TextBehaviour>.Create(graph, template);
TextBehaviour clone = playable.GetBehaviour();
clone.speed = speed;
clone.line = Line;
return playable;
}
public ClipCaps clipCaps => ClipCaps.All;
}
Track(轨道)
csharp
using UnityEngine;
using UnityEngine.Playables;
using UnityEngine.Timeline;
[TrackBindingType(typeof(TextController))]
[TrackColor(255/255f,255/255f,200/255f)]
[TrackClipType(typeof(TextClip))]
public class TextTrack : TrackAsset
{
public override Playable CreateTrackMixer(PlayableGraph graph, GameObject go, int inputCount)
{
return ScriptPlayable<TextMixer>.Create(graph, inputCount);
}
}
Mixer(混合)
csharp
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Playables;
public class TextMixer : PlayableBehaviour
{
private string defaultLine = default;
private float defaultProgress = default;
public override void ProcessFrame(Playable playable, FrameData info, object playerData)
{
var textController = playerData as TextController;
int inputCount = playable.GetInputCount();
string currentLine = defaultLine;
float currentProgress = defaultProgress;
bool isEmpty = true;
for (int i = 0; i < inputCount; i++)
{
var clipPlayable = (ScriptPlayable<TextBehaviour>)playable.GetInput(i);// 获取当前的
TextBehaviour behaviour = clipPlayable.GetBehaviour();
float inputWight = playable.GetInputWeight(i);
Debug.Log(inputWight);
if (inputWight > 0)
{
isEmpty = false;
float progress = (float)(clipPlayable.GetTime() / clipPlayable.GetDuration());
if(textController) textController.OnUpdate(behaviour.line,behaviour.speed,progress);
}
//textController.OnUpdate(defaultLine,0,defaultProgress);
}
if (isEmpty)
{
textController.OnUpdate(defaultLine,0,defaultProgress);
}
}
}
被控制物体
csharp
using System.Collections;
using System.Collections.Generic;
using TMPro;
using UnityEngine;
public class TextController : MonoBehaviour
{
public TextMeshProUGUI baseText;
public TextMeshProUGUI colorText;
[SerializeField]private RectTransform maskTransform;
public void OnUpdate(string line,float speed,float progress)
{
baseText.text = line;
colorText.text = line;
float x = colorText.preferredWidth * progress * speed;
maskTransform.sizeDelta = new Vector2(x, maskTransform.sizeDelta.y);
}
}
总结
基本上说完了,因为这个只是做一个简单示例所以也没有过多的细讲。因为只要理解了原理这其实很简单的。