在Unity3D中實現高效的戰鬥飄字

版權所有,轉載須註明出處!
喜歡火影、喜歡Java、喜歡unity3D、喜歡遊戲開發的都可以加入木葉村Q羣:379076227



這周有網友提到用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[i] = 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[i] = 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[i] = 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[i]]), convert2World(mesh.vertices[tris[i + 1]]));
            Gizmos.DrawLine(convert2World(mesh.vertices[tris[i]]), 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://pan.baidu.com/s/1pKpalh5 密碼: snpq


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章