在Unity3D中实现高效的战斗飘字

Posted kakashi8841

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在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


以上是关于在Unity3D中实现高效的战斗飘字的主要内容,如果未能解决你的问题,请参考以下文章

在Unity3D中实现高效的战斗飘字

浅谈在Unity3D中实现Finite State Machine System有限状态机框架系统

如何在unity3d中实现动态环境光的效果

如何在Unity3d中实现战争迷雾效果

如何在 Python 中实现高效的过滤逻辑?

技术博客在Unity3d中实现烟花效果