Unity3D-EditorWindow应用学习01

mac2024-03-22  27

目标

绘制传感器读入的一组数据,在线(实时)绘制成折线图,效果类似下面这样 (当然这个图是Excel的了) 参考了很多教程&博客,参考最后的时候一并列出 一遍学习一边写博客,不知道最后产出会是神马样子

学习内容:EditorWindow

EditorWindow类,继承 ScriptableObject,用于创建一个编辑器窗口,通常用 MenuItem 打开编辑器窗口 1.创建脚本

using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEditor; //添加的引用 public class MyData : EditorWindow { //不再是继承mono,而是继承EditorWindow //也不需要挂在在物体上,脚本放到Editor文件夹就ok //初始化窗口 MyData() { this.titleContent = new GUIContent("window2"); } //设置窗口出现打开的位置 [MenuItem("Test/Test窗口")] static void CreateTestWindows() { EditorWindow.GetWindow(typeof(MyData)); } }

两个重要的调用的方法是OnEnable()方法和OnGUI()方法,前者在窗口启动时调用,也就是初始化参数,后者是绘制的相关组件,我需要实时绘制,应该还需要Update()?

private void OnEnable() { } private void OnGUI() { }

具体的内容之后再添加吧

功能分析

参考前面的数据图,完成任务需要的内容有 1.绘制xy轴 2.绘制数据点(折线)图 3.显示当前选定的(时间)上的点,显示数据 4.显示MAX,MIN,AVG,频率等一些信息 5.实时更新

XY轴

实质是两条箭头: 参考博客,比较简单

private void OnGUI() { //坐标轴绘制 DrawArrow(new Vector2(_axisRect.xMin, _axisRect.yMax), new Vector2(_axisRect.xMin, _axisRect.yMin), Color.black); DrawArrow(new Vector2(_axisRect.xMin, _axisRect.yMax), new Vector2(_axisRect.xMax, _axisRect.yMax), Color.black); } /// <summary> /// 绘制坐标轴//绘制带箭头的线 /// </summary> /// <param name="from"></param> /// <param name="to"></param> /// <param name="color"></param> private void DrawArrow(Vector2 from, Vector2 to, Color color) { Handles.BeginGUI(); Handles.color = color; Handles.DrawAAPolyLine(3, from, to); Vector2 v0 = from - to; v0 *= 10 / v0.magnitude; Vector2 v1 = new Vector2(v0.x * 0.866f - v0.y * 0.5f, v0.x * 0.5f + v0.y * 0.866f); Vector2 v2 = new Vector2(v0.x * 0.866f + v0.y * 0.5f, v0.x * -0.5f + v0.y * 0.866f); Handles.DrawAAPolyLine(3, to + v1, to, to + v2); Handles.EndGUI(); }
数据折线图

从绘制静态的折线图开始吧。可能会容易一点 假设我们图上有100个点 画折线==>绘制线段 我的数据都是统一频率(时间间隔)的,所以x轴较好处理 第一个点x坐标就是Rect的左边框,以此类推 y轴的话,知道数据的量程,然后就可以处理了 逻辑如下:

private void DrawData() { float maxValue = 100; //float avgValue = 0; //设定最大最小值 //获得对应的点的xy轴坐标信息 for (int i = 0; i < 100; ++i) { _points[i].x = (float)i / maxValue * _graphContentRect.width + _graphContentRect.xMin; _points[i].y = _graphContentRect.yMax - _samples[i]/ maxValue * _graphContentRect.height; } }

然后是折线段的绘制 这里面用的了GL类,这是OpenGL在Unity的封装 绘制的函数如下

private void DrawData() { //前面同上 // GL.PushMatrix(); //不知道啥用 //然后开始绘制这一部分 _graphMaterial.SetPass(0); //_graphMaterial.SetColor(Color.red); GL.Begin(GL.LINE_STRIP);//绘制直线 GL.Color(Color.red);//设定颜色 for (int i = 0; i < maxValue; ++i) { if (_graphRect.Contains(_points[i])) { GL.Vertex(_points[i]); } } GL.End(); // GL.PopMatrix(); }

注意GL.Begin()的参数可以选择绘制三角形/直线 绘制直线用的参数是GL.LINE_STRIP而不是GL.LINES,区别如下面的两张图 也不用多解释了,后者是两两练成一组线段,前者是连续连接。同理绘制三角形的两个参数

实时更新问题

每一时刻有新的数据输入进来,图像应该更新(反应在图上相当于左移了) 这里开始找不到现有的文章作参考了

/// <summary> /// 数据测试,模拟生成随机数 /// </summary> /// <returns></returns> private List<int> RandomData() { List<int> list = new List<int>(); for (int i = 0; i < 100; i++) { int value = UnityEngine.Random.Range(0, 100); list.Add(value); } return list; } private void Update() { //试一下实时处理数据 //重新生成数据 _samples = RandomData(); } }

前文用这么一个函数来生成随机数据,然后我想防治一个Update函数来更新数据,发现一个神奇的现象,一般情况下界面是不动的,但是当我用鼠标拖动EditorWindow编辑器窗口,图像就突然更新了 估计是因为当鼠标点击的时候,OnGUI()函数被重新调用了… 在继承自Mono类的.cs文件里,OnGUI()函数每帧调用两次。但在editorwindow里面,如果鼠标不点击,它就会处在非激活状态 参考博客,找到了解决方案,在代码中加入 void OnInspectorUpdate() { //开启窗口的重绘,不然窗口信息不会刷新 Repaint(); } 问题得到解决 效果动图如下

长得丑和一些其他需求的问题

坐标轴需要个单位了 要记录max和min的值啦 乱七八糟的有空搞吧 这篇blog,把主要的功能都实现了就ok了

参考文献

https://blog.51cto.com/13638120/2103991 这是一个很出色的demo,参考了很多代码过来 https://blog.csdn.net/douniwan007009/article/details/79620150 EditorWindow 类的介绍,比较详细 https://www.jianshu.com/p/97520d98a1f2 同上 https://blog.csdn.net/Htlas/article/details/79748512 GL库的使用教程 https://blog.csdn.net/weixin_33816300/article/details/91463054 OnGUI()函数非激活不执行的解决方案

最新回复(0)