UGUI六芒星
游戏中为了展现角色属性,突出职业特点,经常用到“六芒星”,玩家可以根据六芒星的形状,更好的分析当前角色的属性和特点,如图:
最近正在研究UGUI,为了理解UGUI组织顶点渲染的机制,就用UGUI实现了一套“六芒星”。
在Canvas节点下,所有显示的UI控件都有一个CanvasRenderer组件,这个组件就是用来组织UI控件顶点的。CanvasRenderer有设置Mesh的接口,通过角色的属性,构建出六芒星mesh,并传递给CanvasRenderer,使其符合UGUI渲染机制(深度,Order等)统一渲染。
Unity提供渲染网格接口类就是Mesh,通过Mesh我们可以设置顶点属性(位置,uv,颜色等),以及Mesh的顶点索引数组,就可以构建一个完整的Mesh对象了。为了使其在Canvas中正常显示,我们实例化一个Shader作为Material对象,赋值到CanvasRenderer组件对象中,即可完成渲染。
我们以六芒星为例,六芒星将平面360度平均划分为6份,每份60度,即可确定每个属性的方向,再根据属性的值(相当于向量的模),就可以得到对应的“属性向量”,将6个属性向量的终点连在一起,就可以渲染出整体的六芒星。
为了便于扩展六芒星为“五芒星”,“七芒星”等,我们允许设置以下几个属性:
startDirection:第一个属性的方向,通过这个方向值以及每个属性之间的角度,可以得到其他属性的方向。
attributes:属性数组,数组的长度表示了“N芒星”。
fullStrength:满属性值,通过属性值/满属性值,可以得到这个属性的比例,用于构建六芒星UI控件。
1 2 3 4 5 6 | // 起始方向 public Vector3 startDirection = new Vector3(0, 1, 0); // 星属性 public int [] attributes = null ; // 最大值 public float fullStrength = 100f; |
通过将360度平均划分为N份,以及向量旋转公式,可以得到每个属性的方向向量,算法如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 | // 获取每个属性点的方向向量 int starsCount = this .attributes.Length; List directionList = new List(starsCount); float deltaAngle = this .circle / starsCount; for ( int i = 0; i < attributes.Length; ++i) { float angle = i * deltaAngle; float rad = Mathf.Deg2Rad * angle; float sinA = Mathf.Sin(rad); float cosA = Mathf.Cos(rad); directionList.Add( new Vector3(startDirection.x * cosA + startDirection.y * sinA, -startDirection.x * sinA + startDirection.y * cosA, 0)); } |
接下来计算六芒星中各顶点的位置,要构建六芒星,除了每个属性的顶点外,还需要一个中心点。属性点根据每个属性的方向(单位向量)*属性值可得,算法如下:
1 2 3 4 5 6 7 8 9 10 11 | Mesh mesh = new Mesh(); // 设置顶点位置属性 int verticesCount = starsCount + 1; List vertices = new List(verticesCount); vertices.Add(Vector3.zero); for ( int i = 1; i < verticesCount; ++i) { int index = i - 1; vertices.Add(directionList[index] * this .attributes[index] / this .fullStrength * rectTransform.sizeDelta.x); } mesh.SetVertices(vertices); |
为了表现更丰富一点,我们为每个属性设置一个颜色,属性的颜色值根据属性强度变深,算法如下:
1 2 3 4 5 6 7 8 9 10 11 | // 设置颜色属性 List colors = new List(); colors.Add( new Color32(255, 255, 255, 255)); for ( int i = 0; i < starsCount; ++i) { float strength = attributes[i] / rectTransform.sizeDelta.x; byte r = ( byte )(strength * 200); Color32 c = new Color32(r, 0, 0, 255); colors.Add(c); } mesh.SetColors(colors); |
Mesh对象的顶点属性设置完成后,还要为顶点设置索引数组,六芒星网格是由6个三角形构建而成,这6个三角形有一个共点(中心点),通过中心点及任意两个相邻的属性顶点组成6个三角形,算法如下:
1 2 3 4 5 6 7 8 9 10 11 | // 设置索引属性 int [] indices = new int [3 * starsCount]; for ( int i = 0; i < starsCount; ++i) { int index = 3 * i; indices[index] = 0; indices[index + 1] = i + 1; indices[index + 2] = (i + 2) > starsCount ? (i + 2 - starsCount) : (i + 2); } mesh.SetIndices(indices, MeshTopology.Triangles, 0); canvasRenderer.SetMesh(mesh); |
最后设置材质
1 2 | Material material = new Material(Shader.Find( "UI/Default" )); canvasRenderer.SetMaterial(material, null ); |
效果如下图