赞
踩
==转载标明出处==
MaskableGraphic是Unity中多种UI组件的父类,比如Image、Text等。Untiy官网中关于MaskableGraphic的介绍只有一句:
A Graphic that is capable of being masked out.
一个可以遮盖的图形
1.关键属性maskable,当它等于false代表不可遮掩,等于true代表可以被其他组件遮盖。
2.关键方法OnPopulateMesh,在继承了MaskableGraphic的子类中重写该方法,向OnPopulateMesh方法中传入对应的VertexHelper类型(5.0以前的版本4.X是传入Mesh类型)的数据,即可构建出自己想要的组件。
3.VertexHelper是一个包含了网格数据中的顶点数据和三角面对应顶点的序号,不了解网格数据的同鞋可以去查看一下Mesh类型后者查看我的其他网格类型博文。
1.1先定义一下XY轴的一些常量,写在一个单独的类中并序列化,这样可以在Inspector面板上显示常量并方便调节常量。
//序列化该类型 [Serializable] public class FunctionalGraphBase { /// <summary> /// 是否显示X轴 /// </summary> public bool ShowXAxis = true; /// <summary> /// 是否显示Y轴 /// </summary> public bool ShowYAxis = true; /// <summary> /// 是否显示刻度 /// </summary> public bool ShowScale = false; /// <summary> /// 是否显示XY轴单位 /// </summary> public bool ShowXYAxisUnit = true; /// <summary> /// X轴单位 /// </summary> public string XAxisUnit = "X"; /// <summary> /// Y轴单位 /// </summary> public string YAxisUnit = "Y"; /// <summary> /// XY轴刻度 /// </summary> [Range(0.1f,100f)]public float XYAxisScale = 50f; /// <summary> /// XY轴宽度 /// </summary> [Range(0.1f , 100f)]public float XYAxisWidth = 5.0f; /// <summary> /// XY轴颜色 /// </summary> public Color XYAxisColor = Color.gray; /// <summary> /// 是否显示XY轴的箭头 /// </summary> public bool ShowXYAxisArrow = true; /// <summary> /// 箭头尺寸 /// </summary> public float ArrowSzie = 3.0f; }
2.1 定义一个函数公式类型,Func委托是可以输出零到多个参数,并必须有一个返回值的委托类型,第一个float代表输入x值,返回值代表y值
比如:
Mathf.Sin : y = Mathf.Sin(x);
Mathf.Cos : y = Mathf.Cos(x);
直线函数 : y = 2*x + 3;
2.2 类型中定义改函数图的另外两个属性,一个是线条颜色,一个是线条宽度
public class FunctionFormula { /// <summary> /// 函数表达式 /// </summary> public Func<float,float> Formula; /// <summary> /// 函数图对应线条颜色 /// </summary> public Color FormulaColor; public float FormulaWidth; public FunctionFormula(){} public FunctionFormula( Func<float , float> formula ,Color formulaColor ,float width ) { Formula = formula; FormulaColor = formulaColor; FormulaWidth = width; } }
箭头绘制原理图:
public class FunctionalGraph : MaskableGraphic { public FunctionalGraphBase GraphBase = new FunctionalGraphBase(); public List<FunctionFormula> Formulas = new List<FunctionFormula>(); private RectTransform _myRect; /// <summary> /// 初始化函数信息,添加了五个函数公式 /// </summary> private void Init() { _myRect = this.rectTransform; Formulas.Add(new FunctionFormula(Mathf.Sin , Color.red , 3.0f)); Formulas.Add(new FunctionFormula(Mathf.Cos , Color.green , 2.0f)); Formulas.Add(new FunctionFormula(Mathf.Sign , Color.blue , 2.0f)); Formulas.Add(new FunctionFormula(Mathf.Sqrt , Color.magenta , 2.0f)); Formulas.Add(new FunctionFormula(xValue => xValue * 1.3f + 1 , Color.yellow , 2.0f)); } /// <summary> /// 重写这个类以绘制UI,首先初始化数据和清空已有的顶点数据 /// </summary> /// <param name="vh"></param> protected override void OnPopulateMesh(VertexHelper vh) { Init(); vh.Clear(); #region 基础框架的绘制 //绘制X轴,获取X轴左右两个顶点,绘制一个矩形 if (GraphBase.ShowXAxis) { float lenght = _myRect.sizeDelta.x; Vector2 leftPoint = new Vector2(-lenght / 2.0f , 0); Vector2 rightPoint = new Vector2(lenght / 2.0f , 0); vh.AddUIVertexQuad(GetQuad(leftPoint , rightPoint , GraphBase.XYAxisColor , GraphBase.XYAxisWidth)); // 绘制X轴的箭头 // 箭头的绘制和矩形一样,只要传入四个顶点即可,见三角形的绘制详解图利用ABCD四个点绘制 if (GraphBase.ShowXYAxisArrow) { float arrowUnit = GraphBase.ArrowSzie / 2.0f; Vector2 firstPoint = rightPoint + new Vector2(0 , arrowUnit); Vector2 secondPoint = rightPoint; Vector2 thirdPoint = rightPoint + new Vector2(0 , -arrowUnit); Vector2 fourPoint = rightPoint + new Vector2(Mathf.Sqrt(3)* arrowUnit , 0); vh.AddUIVertexQuad(GetQuad(firstPoint,secondPoint,thirdPoint,fourPoint,GraphBase.XYAxisColor)); } } //绘制Y轴,获取Y轴上下两个顶点,绘制一个矩形 if (GraphBase.ShowYAxis) { float height = _myRect.sizeDelta.y; Vector2 downPoint = new Vector2(0 , -height / 2.0f); Vector2 upPoint = new Vector2(0 , height / 2.0f); vh.AddUIVertexQuad(GetQuad(downPoint , upPoint , GraphBase.XYAxisColor , GraphBase.XYAxisWidth)); // 绘制Y轴的箭头 if ( GraphBase.ShowXYAxisArrow ) { float arrowUnit = GraphBase.ArrowSzie / 2.0f; Vector2 firstPoint = upPoint + new Vector2(arrowUnit , 0); Vector2 secondPoint = upPoint; Vector2 thirdPoint = upPoint + new Vector2(-arrowUnit , 0); Vector2 fourPoint = upPoint + new Vector2(0 , Mathf.Sqrt(3) * arrowUnit); vh.AddUIVertexQuad(GetQuad(firstPoint , secondPoint , thirdPoint , fourPoint , GraphBase.XYAxisColor)); } } #endregion #region 函数图的绘制 //遍历函数公式,然后每隔一次像素绘制一个矩形 foreach ( var functionFormula in Formulas ) { Vector2 startPos = GetFormulaPoint(functionFormula.Formula , -_myRect.sizeDelta.x / 2.0f ); //从X轴的负方向轴开始向正方向轴绘制 for ( float x = -_myRect.sizeDelta.x / 2.0f + 1 ; x < _myRect.sizeDelta.x / 2.0f ; x++ ) { Vector2 endPos = GetFormulaPoint(functionFormula.Formula , x ); vh.AddUIVertexQuad(GetQuad(startPos , endPos , functionFormula.FormulaColor , functionFormula.FormulaWidth)); //这里把当前绘制的结束点设置为下一次绘制的起始点 startPos = endPos; } } #endregion } //通过两个端点绘制矩形 private UIVertex[] GetQuad( Vector2 startPos , Vector2 endPos , Color color0 , float lineWidth = 2.0f ) { float dis = Vector2.Distance(startPos , endPos); float y = lineWidth * 0.5f * ( endPos.x - startPos.x ) / dis; float x = lineWidth * 0.5f * ( endPos.y - startPos.y ) / dis; if ( y <= 0 ) y = -y; else x = -x; UIVertex[] vertex = new UIVertex[4]; vertex[0].position = new Vector3(startPos.x + x , startPos.y + y); vertex[1].position = new Vector3(endPos.x + x , endPos.y + y); vertex[2].position = new Vector3(endPos.x - x , endPos.y - y); vertex[3].position = new Vector3(startPos.x - x , startPos.y - y); for ( int i = 0 ; i < vertex.Length ; i++ ) vertex[i].color = color0; return vertex; } //通过四个顶点绘制矩形 private UIVertex[] GetQuad( Vector2 first , Vector2 second , Vector2 third , Vector2 four , Color color0 ) { UIVertex[] vertexs = new UIVertex[4]; vertexs[0] = GetUIVertex(first , color0); vertexs[1] = GetUIVertex(second , color0); vertexs[2] = GetUIVertex(third , color0); vertexs[3] = GetUIVertex(four , color0); return vertexs; } //构造UIVertex private UIVertex GetUIVertex( Vector2 point , Color color0 ) { UIVertex vertex = new UIVertex { position = point , color = color0 , uv0 = new Vector2(0 , 0) }; return vertex; } //利用Func委托,计算出每一个绘制点 private Vector2 GetFormulaPoint( Func<float , float> formula ,float xValue ) { return new Vector2(xValue , formula(xValue / GraphBase.XYAxisScale) *50 ); } }
其他折线图,曲线图等。
以上展示的组件都只需要在UI空物体上添加一个脚本即可实现,纯代码实现不需要其他资源,而且每一个组件在不调用GUI.Text进行文字绘制的情况下,只占用一个Batch,极大的减少了CPU交付GPU绘制的次数,提升效率。以上的其他UI组件,会在后续的博文中更新,并附上全部源码。
==转载标明出处==
CSDN博客:http://blog.csdn.net/qq_29579137 查看更多别的博文
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。