Unity中的UGUI对外还是很开放的,查看了MaskableGraphic类,发现UI的绘制都是继承自此类,然后在OnPopulateMesh方法中进行UI的绘制,要做自己的UI需要继承此类,然后重写OnPopulateMesh方法(这个方法有两个重载);这里就重写OnPopulateMesh(VertexHelper vh),运用VertexHelper 对象的AddUIVertexQuad方法绘制UI;
主要看下面的方法:
private UIVertex[] GetQuad(Vector2 startPos, Vector2 endPos, Color color0, float lineWidth = 2)
{
var dis = Vector2.Distance(startPos, endPos);
float x = lineWidth * 0.5f * (endPos.y - startPos.y) / dis;
float y = lineWidth * 0.5f * (endPos.x - startPos.x) / dis;
if (x <= 0) x = -x;
else y = -y;
UIVertex[] vertexs = new UIVertex[4];
vertexs[0].position = new Vector2(startPos.x + x, startPos.y + y);
vertexs[1].position = new Vector2(endPos.x + x, endPos.y + y);
vertexs[2].position = new Vector2(endPos.x - x, endPos.y - y);
vertexs[3].position = new Vector2(startPos.x - x, startPos.y - y);
for (int i = 0; i < vertexs.Length; i++)
{
vertexs[i].color = color0;
}
return vertexs;
}
private UIVertex[] GetQuad(Vector2 first, Vector2 second, Vector2 third, Vector2 four, Color color0)
{
UIVertex[] vertexs = new UIVertex[]
{
new UIVertex { position=first,color=color0,uv0=Vector2.zero},
new UIVertex { position=second,color=color0,uv0=Vector2.zero},
new UIVertex { position=third,color=color0,uv0=Vector2.zero},
new UIVertex { position=four,color=color0,uv0=Vector2.zero}
};
return vertexs;
}
直接上完整代码看案例:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
using System;
using System.Collections.Generic;
public enum LineType
{
None,
FullLine,
LinaryLine
}
[Serializable]
public class FunctionBase
{
[Range(40, 100)]
public float axisScale = 50;
[Range(3, 20)]
public float arrowScale = 4;
public LineType lineType = LineType.FullLine;
public bool isShowScale = false;
public float scaleLength = 3;
[Range(1,100)]
public float scaleValue = 50;
public float lineLength = 3;
[Range(3, 8)]
public float spaceLength = 3;
[Range(1.5f, 10)]
public float lineWidth = 1.5f;
}
public class FunctionalFormula
{
public Func<float, float> formula;
public Color color;
public float LineWidth;
public FunctionalFormula(Func<float, float> Formula,Color colorL,float width)
{
this.formula = Formula;
color = colorL;
LineWidth = width;
}
public Vector2 GetResult(float x,float scale)
{
return new Vector2(x,formula(x/scale)*scale);
}
}
public class FunctionGraphic : MaskableGraphic
{
[Header("Line About Setting")]
public FunctionBase funcBase = new FunctionBase();
public IList<FunctionalFormula> FunctionList = new List<FunctionalFormula>();
public void AddFunction(IList<FunctionalFormula> formuList)
{
foreach (FunctionalFormula formula in formuList)
AddFunction(formula);
}
public void AddFunction(Func<float ,float> function,Color color1,float width)
{
FunctionalFormula formula = new global::FunctionalFormula(function, color1, width);
AddFunction(formula);
}
public void AddFunction(FunctionalFormula formula)
{
FunctionList.Add(formula);
}
protected override void OnPopulateMesh(VertexHelper vh)
{
vh.Clear();
var size = GetPixelAdjustedRect().size;
var topLeft = new Vector2(-size.x / 2, size.y / 2);
var topRight = new Vector2(size.x / 2, size.y / 2);
var bottomLeft = new Vector2(-size.x / 2, -size.y / 2);
var bottomRight = new Vector2(size.x / 2, -size.y / 2);
#region Draw X axis
var startPos = new Vector2(-size.x / 2, 0);
var endPos = new Vector2(size.x / 2, 0);
vh.AddUIVertexQuad(GetQuad(startPos, endPos, Color.red, funcBase.lineWidth));
var firstPoint = new Vector2(size.x / 2, 0);
var secondPoint = firstPoint + new Vector2(0, funcBase.arrowScale);
var thirdPoint = firstPoint + new Vector2(Mathf.Sqrt(3) * funcBase.arrowScale, 0);
var fourPoint = firstPoint + new Vector2(0, -funcBase.arrowScale);
vh.AddUIVertexQuad(GetQuad(firstPoint, secondPoint, thirdPoint, fourPoint, Color.red));
#endregion
#region Draw Y Axis
var bottomPos = new Vector2(0, -size.y / 2);
var topPos = new Vector2(0, size.y / 2);
vh.AddUIVertexQuad(GetQuad(bottomPos, topPos, Color.red, funcBase.lineWidth));
var firstPos = topPos;
var secondPos = new Vector3(-funcBase.arrowScale, size.y / 2);
var thirdPos = new Vector3(0, size.y / 2 + Mathf.Sqrt(3) * funcBase.arrowScale);
var fourPos = new Vector3(funcBase.arrowScale, size.y / 2);
vh.AddUIVertexQuad(GetQuad(firstPos, secondPos, thirdPos, fourPos, Color.red));
#endregion
#region ShowScale
if (funcBase.isShowScale)
{
for (var i = 1; i * funcBase.axisScale < size.x / 2; i++)
{
var StartPos = new Vector2(funcBase.axisScale * i, 0);
vh.AddUIVertexQuad(GetQuad(StartPos, new Vector2(StartPos.x, funcBase.scaleLength), Color.red, 1.5f));
}
for (var i = 1; -funcBase.axisScale * i > -size.x / 2; i++)
{
var StartPos = new Vector2(-funcBase.axisScale * i, 0);
vh.AddUIVertexQuad(GetQuad(StartPos, new Vector2(StartPos.x, funcBase.scaleLength), Color.red, 1.5f));
}
for (var i = 1; i * funcBase.axisScale < size.y / 2; i++)
{
var StartPos = new Vector2(0, i * funcBase.axisScale);
vh.AddUIVertexQuad(GetQuad(StartPos, new Vector2(funcBase.scaleLength, StartPos.y), Color.red, 1.5f));
}
for (var i = 1; -i * funcBase.axisScale > -size.y / 2; i++)
{
var StartPos = new Vector2(0, -i * funcBase.axisScale);
vh.AddUIVertexQuad(GetQuad(StartPos, new Vector2(funcBase.scaleLength, StartPos.y), Color.red, 1.5f));
}
}
#endregion
#region Draw FrameLine
switch (funcBase.lineType)
{
case LineType.FullLine:
for (var i = 1; i * funcBase.axisScale < size.x / 2; i++)
{
var StartPos = new Vector2(funcBase.axisScale * i, -size.y / 2);
var UpEndPos = new Vector2(StartPos.x, size.y / 2);
vh.AddUIVertexQuad(GetQuad(StartPos, UpEndPos, Color.white, funcBase.lineWidth));
}
for (var i = 1; -funcBase.axisScale * i > -size.x / 2; i++)
{
var StartPos = new Vector2(-funcBase.axisScale * i, -size.y / 2);
var UpEndPos = new Vector2(StartPos.x, size.y / 2);
vh.AddUIVertexQuad(GetQuad(StartPos, UpEndPos, Color.white, funcBase.lineWidth));
}
for (var i = 1; i * funcBase.axisScale < size.y / 2; i++)
{
var StartPos = new Vector2(-size.x / 2, i * funcBase.axisScale);
var rightEndPos = new Vector2(size.x / 2, StartPos.y);
vh.AddUIVertexQuad(GetQuad(StartPos, rightEndPos, Color.white, funcBase.lineWidth));
}
for (var i = 1; -i * funcBase.axisScale > -size.y / 2; i++)
{
var StartPos = new Vector2(-size.x / 2, -i * funcBase.axisScale);
var rightEndPos = new Vector2(size.x / 2, StartPos.y);
vh.AddUIVertexQuad(GetQuad(StartPos, rightEndPos, Color.white, funcBase.lineWidth));
}
break;
case LineType.LinaryLine:
{
for (var i = 1; i * funcBase.axisScale < size.x / 2; i++)
{
var firstPointX = new Vector2(i * funcBase.axisScale, -size.y / 2);
var secondPointx = new Vector2(firstPointX.x, size.y / 2);
GetImageLinaryLine(ref vh, firstPointX, secondPointx, Color.gray, funcBase.lineLength, funcBase.spaceLength, funcBase.lineWidth);
}
for (var i = 1; -funcBase.axisScale * i > -size.x / 2; i++)
{
var firstPointX = new Vector2(-i * funcBase.axisScale, -size.y / 2);
var secondPointx = new Vector2(firstPointX.x, size.y / 2);
GetImageLinaryLine(ref vh, firstPointX, secondPointx, Color.gray, funcBase.lineLength, funcBase.spaceLength, funcBase.lineWidth);
}
for (var i = 1; i * funcBase.axisScale < size.y / 2; i++)
{
var firstPointX = new Vector2(-size.x / 2, i * funcBase.axisScale);
var secondPointx = new Vector2(size.x / 2, firstPointX.y);
GetImageLinaryLine(ref vh, firstPointX, secondPointx, Color.gray, funcBase.lineLength, funcBase.spaceLength, funcBase.lineWidth);
}
for (var i = 1; -i * funcBase.axisScale > -size.y / 2; i++)
{
var firstPointX = new Vector2(-size.x / 2, -i * funcBase.axisScale);
var secondPointx = new Vector2(size.x / 2, firstPointX.y);
GetImageLinaryLine(ref vh, firstPointX, secondPointx, Color.gray, funcBase.lineLength, funcBase.spaceLength, funcBase.lineWidth);
}
}
break;
}
#endregion
if (FunctionList.Count <= 0) return;
var unitPixel = 100 / funcBase.axisScale;
foreach(var formula in FunctionList)
{
var startPoint= formula.GetResult(-size.x/2, funcBase.axisScale);
for(var i=-size.x/2+1;i<size.x/2;i+= unitPixel)
{
var endPoint=formula.GetResult(i, funcBase.axisScale);
vh.AddUIVertexQuad(GetQuad(startPoint,endPoint,formula.color,formula.LineWidth));
startPoint = endPoint;
}
}
}
private UIVertex[] GetQuad(Vector2 startPos, Vector2 endPos, Color color0, float lineWidth = 2)
{
var dis = Vector2.Distance(startPos, endPos);
float x = lineWidth * 0.5f * (endPos.y - startPos.y) / dis;
float y = lineWidth * 0.5f * (endPos.x - startPos.x) / dis;
if (x <= 0) x = -x;
else y = -y;
UIVertex[] vertexs = new UIVertex[4];
vertexs[0].position = new Vector2(startPos.x + x, startPos.y + y);
vertexs[1].position = new Vector2(endPos.x + x, endPos.y + y);
vertexs[2].position = new Vector2(endPos.x - x, endPos.y - y);
vertexs[3].position = new Vector2(startPos.x - x, startPos.y - y);
for (int i = 0; i < vertexs.Length; i++)
{
vertexs[i].color = color0;
}
return vertexs;
}
private UIVertex[] GetQuad(Vector2 first, Vector2 second, Vector2 third, Vector2 four, Color color0)
{
UIVertex[] vertexs = new UIVertex[]
{
new UIVertex { position=first,color=color0,uv0=Vector2.zero},
new UIVertex { position=second,color=color0,uv0=Vector2.zero},
new UIVertex { position=third,color=color0,uv0=Vector2.zero},
new UIVertex { position=four,color=color0,uv0=Vector2.zero}
};
return vertexs;
}
private void GetImageLinaryLine(ref VertexHelper vh,Vector2 startPos,Vector2 endPos,Color color0,float LineLength,float SpaceLength,float lineWidth=1.5f)
{
if(startPos.x.Equals(endPos.x))
{
var secondPoint =startPos+ new Vector2(0,LineLength);
while(secondPoint.y<endPos.y)
{
vh.AddUIVertexQuad(GetQuad(startPos, secondPoint, color0, lineWidth));
startPos = secondPoint + new Vector2(0, SpaceLength);
secondPoint = startPos + new Vector2(0, LineLength);
if(secondPoint.y>endPos.y)
{
secondPoint = new Vector2(startPos.x,endPos.y);
vh.AddUIVertexQuad(GetQuad(startPos, secondPoint, color0, lineWidth));
}
}
}
if(startPos.y.Equals(endPos.y))
{
var secondPoint = startPos + new Vector2(LineLength,0);
while(secondPoint.x<endPos.x)
{
vh.AddUIVertexQuad(GetQuad(startPos,secondPoint,color0, lineWidth));
startPos = secondPoint + new Vector2(SpaceLength,0);
secondPoint = startPos + new Vector2(LineLength,0);
if(secondPoint.x>endPos.x)
{
secondPoint = new Vector2(startPos.x,endPos.y);
vh.AddUIVertexQuad(GetQuad(startPos,secondPoint,color0, lineWidth));
}
}
}
}
}
效果图: