这周有网友提到用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