大家请加入qq交流群:756931022 半成品会持续更新在群里、以及可以在群里交流
上一节回顾
上一节我讲解了时间轴的绘制,主要就是如何在一个rect内去复刻出一个时间轴,其实就是将固定宽度转为固定时间,然后就是时间轴了。这一节将来讲解时间指针的绘制,以及预览播放函数的编写。
时间指针的绘制
时间轴可以说是一系列固定的事件的触发顺序的话,时间指针,就是在编辑器下模拟Runtime的情况去执行这一系列的事件,从而完成在编辑器下预览播放一个技能,这样可以进行编辑器的下技能的配置和调整。
首先看代码如下:
//绘制时间指针
private void DrawTimePointer()
{
timeHeaderPointer.x = 0f + timeLineOffsetX + timePointerOffsetX;
timeHeaderPointer.y = 0f;
timeHeaderPointer.width = 20f;
timeHeaderPointer.height = styles.timeBtnsHeight;
//先绘制时间指针头部的Rect
EditorGUI.DrawRect(timeHeaderPointer, Color.red);
timeBodyPointer.x = 0f + timeLineOffsetX + timePointerOffsetX;
timeBodyPointer.y = styles.timeBtnsHeight;
timeBodyPointer.width = 2f;
timeBodyPointer.height = styles.playSpeedHeight + startIndex * (trackHeight + headerSpan) - headerSpan;
//再绘制时间指针的线
EditorGUI.DrawRect(timeBodyPointer, Color.red);
}
可以看到时间指针的宽度是不变的,是不受我缩放的影响的,然后这里面最重要的一个属性就是时间指针的位置,他会受到两个变量影响,一个是timelineoffsetX,一个是timepointeroffsetX。第一个变量在上一节中已经提到了,是滑动时间轴的时候,让时间指针也能跟着滑动,而第二个变量就是时间指针自己在播放或者拖拽(这个拖拽功能目前有后续打算删掉,太鸡肋在此不讲解了)时候,时间指针自己的偏移量。可以想象一下,在预览播放的时候,时间在累积推进,偏移量在累积,时间指针每次绘制就在向前移动,这样看起来就像是播放进度条一样的东西。
预览播放函数
在之前的章节中已经可以看到在轨道头部那部分的Rect内有几个小小的按钮,没错其实那些就是播放按钮,按下play就会把一个play的bool值打开,再次点击play就会关闭掉bool值。预览播放函数如下:
//绘制预览播放
public static void PreviewPlay(float deltaTime)
{
view.Focus();
deltaTime *= playSpeed;
totalTime += deltaTime * 1000;
timePointerOffsetX += (deltaTime * 1000 / timeScale);
//Debug.Log($"当前的累积时间{totalTime}毫秒");
foreach (var item in animationTracks)
{
foreach (var evt in item.animationEvents)
{
switch (evt.IsOnMessage(totalTime))
{
case StateEventStage.UnTrigger:
break;
case StateEventStage.Triggering:
//evt.EditorTriggerEvent(roleMgr, timePointerOffsetX,timeScale);
evt.EditorTriggerEvent(roleMgr, totalTime - evt.triggerTime);
break;
case StateEventStage.Exit:
evt.ExitEvent(roleMgr);
break;
}
}
}
foreach (var item in hitTracks)
{
foreach (var evt in item.hitEvents)
{
switch (evt.IsOnMessage(totalTime))
{
case StateEventStage.UnTrigger:
break;
case StateEventStage.Triggering:
if(currtentHit == null)
{
currtentHit = evt;
}
evt.TriggerEvent(roleMgr);
break;
case StateEventStage.Exit:
currtentHit = null;
evt.ExitEvent(roleMgr);
break;
}
}
}
window.Repaint();
//return;
//totalTime = 0.0f;
}
函数接受一个时间参数,然后不停的累积时间,同时受到播放速度的影响,这里同时更改掉上面所说的timepointeroffsetX,在就是遍历这个技能里面所有的事件,如果当前累积时间大于等于event的触发时间就可以调用。这段函数是很好理解的,在runtime下也是可以这样调用的。而这个函数在什么时候被调用呢?
public static void OpenWindow(RoleManager role)
{
roleMgr = role;
roleMgr.animator = roleMgr.GetComponent<Animator>();
animationClips = roleMgr.animator.runtimeAnimatorController.animationClips;
animationClipsName = new string[animationClips.Length];
animationClipsSelect = new int[animationClips.Length];
for (int i = 0; i < animationClips.Length; i++)
{
animationClipsName[i] = animationClips[i].name;
animationClipsSelect[i] = i;
}
startIndex = 0;
cfgAsset = null;
roleCfg = null;
currtentSelectd = null;
window = GetWindow<SkillEditorWindow>();
window.titleContent = new GUIContent("技能编辑器");
//初始化样式
styles = new SkillEditorGuIStyles(window.position);
InitHeaderTest();
InitTrack();
lastTime = EditorApplication.timeSinceStartup;
currtentTime = lastTime;
EditorApplication.update += PlayUpdate;
}
//编辑器下预览更新
private static void PlayUpdate()
{
//确保在编辑器下
if (!Application.isPlaying)
{
float deltaTime = 0;
currtentTime = EditorApplication.timeSinceStartup;
deltaTime = (float)(currtentTime - lastTime);
lastTime = currtentTime;
if (isPlay)
{
PreviewPlay(deltaTime);
}
}
}
就是在打开窗体的时候,EditorAppLiaction.update是Unity在编辑器的下update函数,和runtime的update,注册入自己的playupdate即可。
总结
这一节和上一节文章,在实现timeline的时候,都利用了一个偏移量的概念,其实这个概念不光在timeline可以用,比如类似shadergraph那种节点编辑器界面,看起来画布和节点是可以无限滑动的,其实就是画布中每个元素受到了个Vector2的偏移量的影响,这样每次拖拽时候更改这个vector2的偏移量,即可把元素绘制到拖拽的地方,如果超出Rect就会被自动裁剪,看起来就像是无限滑动。