基于Unity编辑器开发技能编辑器 (五)

本文档介绍了在Unity编辑器中开发技能编辑器的时间指针绘制和预览播放功能。时间指针的绘制允许在编辑器下模拟Runtime执行事件,便于技能配置和调整。预览播放函数则根据时间参数和播放速度推进,并触发相应事件。文章还提及了编辑器的更新机制,以及偏移量在编辑器界面设计中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

大家请加入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就会被自动裁剪,看起来就像是无限滑动。

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

风萧水寒人往前

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值