这周有网友提到用NGUI做战斗冒血,冒伤害等文字性能太差。确实如此,我之前(NGUI 3.8.2,1000块的Android机器上)在Profile中也发现UIPanel占用CPU奇高。
因此最终自己在战斗飘文字这一块没有使用NGUI,而是自己创建Mesh来处理。优化前后在手机上每秒大概增加了10帧。
先看一下效果。
可以看到DrawCall和NGUI一样都为1。
这个 MeshText 就是我自己写的HUD文本组件了。
代码如下:
using UnityEngine; [ExecuteInEditMode] public class MeshText : MonoBehaviour { [SerializeField] private string _text = ""; public MeshFilter meshFilter; public MeshRenderer meshRenderer; [HideInInspector] public Material material; public UIAtlas uiAtlas; [SerializeField] private Color _color1 = Color.white; public Color color1 { get { return _color1; } set { _color1 = value; } } [SerializeField] private Color _color2 = Color.white; public Color color2 { get { return _color2; } set { _color2 = value; } } public enum HorizontalAlignType { Left, Center, Right } //当text中存在宽度不一致的字体时,计算Center和Right会有误差。不过对于战斗HUD,够用了。 public HorizontalAlignType HAlignType; public string Text { get { return _text; } set { _text = value; GenerateFilter(); } } void Awake() { #if UNITY_EDITOR meshRenderer.sharedMaterial = uiAtlas.spriteMaterial; material = meshRenderer.sharedMaterial; #else meshRenderer.material = uiAtlas.spriteMaterial; material = meshRenderer.material; #endif if (!string.IsNullOrEmpty(_text)) { GenerateFilter(); } } public void GenerateFilter() { Mesh mesh = new Mesh(); int length = Text.Length; Vector3[] vertices = new Vector3[length<<2]; Vector2[] uvs = new Vector2[vertices.Length]; int[] triangles = new int[(length<<1)*3]; Texture tex = uiAtlas.texture; Color[] colors = new Color[vertices.Length]; int tmp = 0; float tmp2 = 0; switch (HAlignType) { case HorizontalAlignType.Center: tmp2 = - (vertices.Length >> 3); break; case HorizontalAlignType.Left: tmp2 = 0; break; case HorizontalAlignType.Right: tmp2 = -(vertices.Length >> 2); break; default: tmp2 = 0; break; } float r = 1; for (int i = 0; i < vertices.Length; i+=4) { tmp = (i + 1) % 2; string s = Text[i / 4].ToString(); UISpriteData mSprite = uiAtlas.GetSprite(s); r = (mSprite.width * 1.0f / mSprite.height); //setting vertices vertices[i ] = new Vector3( tmp2, tmp + 1 ); vertices[i + 1] = new Vector3( tmp2, tmp ); tmp2 += r; vertices[i + 2] = new Vector3( tmp2, tmp + 1 ); vertices[i + 3] = new Vector3( tmp2, tmp ); colors = color1; colors[i+1] = color2; colors[i+2] = color1; colors[i+3] = color2; //setting uvs Rect inner = new Rect(mSprite.x + mSprite.borderLeft, mSprite.y + mSprite.borderTop, mSprite.width - mSprite.borderLeft - mSprite.borderRight, mSprite.height - mSprite.borderBottom - mSprite.borderTop); inner = NGUIMath.ConvertToTexCoords(inner, tex.width, tex.height); uvs = new Vector2(inner.xMin, inner.yMax); uvs[i + 1] = new Vector2(inner.xMin, inner.yMin); uvs[i + 2] = new Vector2(inner.xMax, inner.yMax); uvs[i + 3] = new Vector2(inner.xMax, inner.yMin); } for (int i = 0; i < triangles.Length; i+=6) { tmp = (i / 3) << 1; triangles = triangles[i + 3] = tmp; triangles[i + 1] = triangles[i + 5] = tmp + 3; triangles[i + 2] = tmp + 1; triangles[i + 4] = tmp + 2; } mesh.vertices = vertices; mesh.colors = colors; mesh.triangles = triangles; mesh.uv = uvs; meshFilter.mesh = mesh; } void OnDrawGizmos() { Gizmos.color = Color.gray; DrawMesh(); } void OnDrawGizmosSelected() { Gizmos.color = Color.green; DrawMesh(); } private void DrawMesh() { if (meshFilter == null) { return; } Mesh mesh = meshFilter.sharedMesh; if (mesh == null) { return; } int[] tris = mesh.triangles; for (int i = 0; i < tris.Length; i += 3) { Gizmos.DrawLine(convert2World(mesh.vertices[tris]), convert2World(mesh.vertices[tris[i + 1]])); Gizmos.DrawLine(convert2World(mesh.vertices[tris]), convert2World(mesh.vertices[tris[i + 2]])); Gizmos.DrawLine(convert2World(mesh.vertices[tris[i + 1]]), convert2World(mesh.vertices[tris[i + 2]])); } } private Vector3 convert2World(Vector3 src) { return transform.TransformPoint(src); } }
关于这段代码应该没什么解释的,主要是关于三角形顶点计算、uv计算这些。随便找一篇创建Mesh的文章看完应该就可以看懂了。
虽然里面用到了NGUI的图集,但渲染和更新已经完全和NGUI无关了。
如果想改成不用NGUI的图集也可以。不过那时候比较懒,已经有图集了,就直接拿过来用咯。
不想用NGUI图集的可以自行修改掉。这样可以脱离NGUI运行。
完整工程(基于Unity3D 4.3.3 和 NGUI3.8.2测试)链接:
http://www.taidous.com/bbs/thread-38226-1-1.html