Unity Mash实现战斗飘血

什么是Mesh

Mesh是指的模型的网格,3D模型是由多边形拼接而成,而多边形实际上又是由多个三角形拼接而成的。即一个3D模型的表面其实是由多个彼此相连的三角面构成。三维空间中,构成这些三角形的点和边的集合就是Mesh

为什么要用Mesh实现战斗飘血

我们都做游戏的时候,都是知道一个很熟悉的词汇“预设体”,它在游戏开发过程中有这举足轻重的地位,时刻时刻都能见到他的身影。我们可以通过预设体的特征克隆出大量的具有相同性质的游戏物体,我上一个项目的的飘血实现就是用不断的克隆预设体实现的。由于战斗的节奏很快,所以会创建很多的飘血对象。比如场景有一百条飘血展示,这个时候客户端就需要存在一百条飘血的对象。这个对内存的消耗是很大,并且没有必要的。
问:“有什么改进的方法吗”?
答:“有的”。

工作原理

我们可以通过Mesh来实现,

  1. 创建Mesh对象
  2. 初始化Mash的顶点数据,UV数据
  3. 根据输入的内容设置顶点数据,UV数据
  4. 在Mesh渲染出来

详细过程

附上代码,只有稍微对Mesh有点了解的你,这些代码都不是问题:

1.SpriteHeper

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SpriteHelper
{
    private Rect uvRect;
    private Font font;
    bool isDynamic;
    public Font getFont { get { return font; } }

    Dictionary<char, CharacterInfo> m_dicCharacter;
    Dictionary<char, CharacterInfo> characterTable
    {
        get
        {
            if (m_dicCharacter == null)
                m_dicCharacter = new Dictionary<char, CharacterInfo>();
            return m_dicCharacter;
        }
    }

    public SpriteHelper(Font fontInfo, bool isDynamic)
    {
        font = fontInfo;
        if (font.dynamic != isDynamic)
        {
            Debugger.LogError("字体类型不符合,请修改!");
        }
        this.isDynamic = isDynamic;
    }

    public Rect GetSpriteRect(char index)
    {
        return GetFontUv(index);
    }

    public Rect GetFontUv(char index)
    {
        CharacterInfo cha;
        if (GetCharacterInfo(index, out cha))
        {
            uvRect = new Rect(cha.uvBottomLeft, cha.uvTopRight - cha.uvBottomLeft);
            if (uvRect.width < 0)
            {
                uvRect.x += uvRect.width;
                uvRect.width *= -1;
            }

            if (uvRect.height < 0)
            {
                uvRect.y += uvRect.height;
                uvRect.height *= -1;
            }
            return uvRect;
        }
        return Rect.zero;
    }

    internal bool GetCharacterInfo(char c, out CharacterInfo info)
    {
        if (isDynamic)
        {
            return font.GetCharacterInfo(c, out info);
        }
        else
        {
            if (!characterTable.TryGetValue(c, out info))
            {
                if (font.GetCharacterInfo(c, out info))
                    characterTable.Add(c, info);
                else
                    Debugger.LogError("静态字体没有文字[{0}],请修复", c);
            }
            return true;
        }
    }
}
  1. UIMeshTextGenerator
using System.Collections;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using UnityEngine;

public class UIMeshText
{
    public Color?[] colorArray;
    public string originString; //起始
    public string outPutString; // 输出
    public Vector2 offset;

    public float[] minX;
    public float[] minY;
    public float[] maxX;
    public float[] maxY;
    public float[] advance;

    public Vector3 pos;
    public float scale;
    public Color color;
    public Vector3 scaleVec = Vector3.zero;

    public UIMeshText(string originStr)
    {
        originString = originStr;
        colorArray = new Color?[originStr.Length];
    }

}


public class UIMeshTextGenerator
{
    StringBuilder m_textBuilder;
    static readonly Regex m_colorRegex = new Regex(@"<color=(#[a-zA-Z0-9]{6,8})>(.*?)</color>", RegexOptions.Singleline);

    public UIMeshTextGenerator()
    {
        m_textBuilder = new StringBuilder();
    }

    public UIMeshText GeneratText(string originStr)
    {
        UIMeshText meshText = new UIMeshText(originStr);
        meshText.outPutString = originStr;
        meshText.minX = new float[meshText.outPutString.Length];
        meshText.minY = new float[meshText.outPutString.Length];
        meshText.maxX = new float[meshText.outPutString.Length];
        meshText.maxY = new float[meshText.outPutString.Length];
        meshText.advance = new float[meshText.outPutString.Length];
        return meshText;
    }

    private void FillOutPutClass(string originStr, UIMeshText meshText)
    {
        m_textBuilder.Length = 0;
        int textIndex = 0;

        foreach (Match match in m_colorRegex.Matches(originStr))
        {
            m_textBuilder.Append(originStr.Substring(textIndex, match.Index - textIndex));
            int trueIndex = m_textBuilder.Length;
            m_textBuilder.Append(match.Groups[2].Value);
            for (int i = 0; i < match.Groups[2].Value.Length; i++)
                meshText.colorArray[trueIndex + i] = GetColot(match.Groups[1].Value);
            textIndex = match.Index + match.Length;
        }

        m_textBuilder.Append(originStr.Substring(textIndex, originStr.Length - textIndex));
        meshText.outPutString = m_textBuilder.ToString();
    }


    private Color GetColot(string colorStr)
    {
        Color colour;
        ColorUtility.TryParseHtmlString(colorStr, out colour);
        return colour;
    }

}

3 . UIMesh

using System.Collections;
using System.Collections.Generic;
using System;
using UnityEngine;
using UnityEngine.UI;
using System.Text;

public class VertPool
{
    private int maxVertNum;
    private int[] blocks;           //顶点
    private char[] charList;

    public VertPool(int maxVert)
    {
        maxVertNum = maxVert;
        blocks = new int[maxVert % 4 == 0 ? maxVert >> 2 : maxVert >> 2 + 1];   // 取4的倍数
        charList = new char[maxVert % 4 == 0 ? maxVert >> 2 : maxVert >> 2 + 1];
    }


    // 获取一个顶点
    public int GetVert()
    {
        for (int i = 0; i < blocks.Length; i++)
        {
            if (blocks[i] >= 0)
            {
                blocks[i] = -1;
                return i;
            }
        }
        Debug.Log("No Available Vertex");
        return -1;
    }

    public int GetVert(char value)
    {
        for (int i = 0; i < blocks.Length; i++)
        {
            if (blocks[i] >= 0)
            {
                blocks[i] = -1;
                charList[i] = value;
                return i;
            }
        }
        Debug.Log("No Available Vertex");
        return -1;
    }

    // 顶点数是否足够
    public bool TestVert(int nCount)
    {
        int nCurCount = 0;
        for (int i = 0; i < blocks.Length; i++)
        {
            if (blocks[i] >= 0)
            {
                nCurCount++;
                if (nCurCount > nCount)
                {
                    return true;
                }
            }
        }
        return false;
    }

    public int[] GetBlocks { get { return blocks; } }
    public char[] GetCharList { get { return charList; } }

    //释放
    public void ReleaseVert(int id)
    {
        if (id < blocks.Length && blocks[id] < 0)
        {
            blocks[id] = 0;
        }
    }

}

public class UIMesh
{
    private GameObject gameObj;
    private MeshFilter meshFilter;
    private MeshRenderer meshRenderer;
    private Vector3[] vertices;               //顶点
    private Vector2[] uvs;                    //uv 顶点
    private Color[] colors;
    private int[] triangles;                //三角形 

    private Mesh mesh;
    private VertPool vp;                    //顶点对象池

    private SpriteHelper spriteHelper;
    private bool m_isDrawUving = false;     // 正在绘制Uv
    private Vector2 m_rectVec = Vector2.zero;
    private Vector3 m_vertOffsetVec = Vector3.zero;
    private Dictionary<List<int>, UIMeshText> m_requireList;
    private UIMeshTextGenerator textGenerator;
    public RectTransform rectTransform;
    private bool bShow = false;
    private bool needRefresh = false;
    private bool dynamic = false;       //是否动态
    private bool uvNeedRebuild = false;
    private float critScale = 0.7f;

    public UIMesh(GameObject parent, string name, Font font, bool isdynamic = false, int vertCount = 2040)
    {
        CreateMeshObject(name, parent);
        CreateMeshComponent(font.material);
        InitCapacity(vertCount);

        spriteHelper = new SpriteHelper(font, isdynamic);
        m_requireList = new Dictionary<List<int>, UIMeshText>();
        textGenerator = new UIMeshTextGenerator();
        dynamic = isdynamic;
        this.gameObj.SetActive(false);

        if (isdynamic)
        {
            Font.textureRebuilt += OnFontTextureRebuild;
        }
        else
        {
            meshRenderer.material.shader = UnityEngine.UI.Text.defaultGraphicMaterial.shader;
        }
    }

    public void SetRenderQueue(int nQueue)
    {
        meshRenderer.material.renderQueue = nQueue;
    }

    public void Show(bool bShow)
    {
        if (this.bShow == bShow)
        {
            return;
        }
        this.bShow = bShow;
        this.gameObj.SetActive(bShow);
    }

    public Vector3 GetVectorInMesh(Vector3 worldPos)
    {
        return gameObj.transform.InverseTransformPoint(worldPos);
    }


    //创建对象
    private void CreateMeshObject(string name, GameObject parent)
    {
        gameObj = new GameObject();
        gameObj.name = name;
        gameObj.transform.SetParent(parent.transform);
    }

    //添加脚本
    private void CreateMeshComponent(Material meshMaterial)
    {
        rectTransform = gameObj.AddComponent<RectTransform>();
        meshFilter = gameObj.AddComponent<MeshFilter>();
        meshRenderer = gameObj.AddComponent<MeshRenderer>();
        meshRenderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.Off;
        meshRenderer.lightProbeUsage = UnityEngine.Rendering.LightProbeUsage.Off;
        meshRenderer.reflectionProbeUsage = UnityEngine.Rendering.ReflectionProbeUsage.Off;
        meshRenderer.receiveShadows = false;
        meshRenderer.material = meshMaterial;
        mesh = new Mesh();
        mesh.name = gameObj.name;
        meshFilter.mesh = mesh;
    }

    //初始化顶点数据
    private void InitCapacity(int vertCount)
    {
        vertices = new Vector3[vertCount];
        uvs = new Vector2[vertCount];
        triangles = new int[(vertCount - 2) * 3];      
        colors = new Color[vertCount];
        vp = new VertPool(vertCount);
    }

    public void OnFontTextureRebuild(Font changedFont)
    {
        if (changedFont != spriteHelper.getFont)
            return;
        RebuildMesh();
    }

    private void ReDrawVerts(int vertIndex, float vertPosx, float vertPosy, Color vertColor, float vertAngle = 0)
    {
        if (vertAngle != 0)
            RotationZ(vertAngle, ref vertPosx, ref vertPosy);
        vertices[vertIndex].x = vertPosx;
        vertices[vertIndex].y = vertPosy;
        colors[vertIndex] = vertColor;
    }

    private void ReDrawUVs(int vertIndex, float uvVectorx, float uvVectory)
    {
        uvs[vertIndex].x = uvVectorx;
        uvs[vertIndex].y = uvVectory;
    }

    /// <summary>
    /// 通过旋转矩阵对顶点进行旋转,等同于修改unity中的rotation
    /// </summary>
    /// <param name="angle"></param>
    /// <param name="vertX"></param>
    /// <param name="vertY"></param>
    private void RotationZ(float angle, ref float vertX, ref float vertY)
    {
        float x, y;
        float CosAngle = Mathf.Cos(angle * Mathf.Deg2Rad);
        float SinAngle = Mathf.Sin(angle * Mathf.Deg2Rad);
        x = vertX * CosAngle - SinAngle * vertY;
        y = vertX * SinAngle + CosAngle * vertY;
        vertX = x;
        vertY = y;
    }

    /// <summary>
    /// 绘制一个正方形,占用4个顶点。根据顶点下标,绘制位置,图集宽高,uv位置绘制。
    /// </summary>
    /// <param name="vertIndex">顶点下标,不是4的倍数会从4的倍数开始绘制</param>
    /// <param name="drawRect">xy为绘制起点(左下角),宽高代表绘制大小与缩放,使用世界坐标</param>
    /// <param name="uvRect">xy是左下角uv坐标值。根据这个值算出四个点的uv</param>
    private void DrawMesh(int vertIndex, Rect drawRect, Rect uvRect, Color drawColor, float vertAngle = 0)
    {
        return;
        if (vertIndex % 4 != 0)
        {
            vertIndex = vertIndex >> 2 << 2;
        }
        int vertStartIndex = vertIndex;
        int triglesIndex = vertIndex * 6 / 4;

        ReDrawVerts(vertIndex, drawRect.x, drawRect.y, drawColor, vertAngle);
        ReDrawUVs(vertIndex, uvRect.x, uvRect.y);

        ReDrawVerts(++vertIndex, drawRect.x, drawRect.y + drawRect.height, drawColor, vertAngle);
        ReDrawUVs(vertIndex, uvRect.x, (uvRect.y + uvRect.height));

        ReDrawVerts(++vertIndex, drawRect.x + drawRect.width, drawRect.y + drawRect.height, drawColor, vertAngle);
        ReDrawUVs(vertIndex, (uvRect.x + uvRect.width), (uvRect.y + uvRect.height));

        ReDrawVerts(++vertIndex, drawRect.x + drawRect.width, drawRect.y, drawColor, vertAngle);
        ReDrawUVs(vertIndex, (uvRect.x + uvRect.width), uvRect.y);

        SetTriangle(triglesIndex, vertStartIndex);
    }

    private void SetTriangle(int triangleIndex, int vertIndex)
    {
        
        triangles[triangleIndex] = vertIndex;
        triangles[triangleIndex + 1] = vertIndex + 1;
        triangles[triangleIndex + 2] = vertIndex + 2;

        triangles[triangleIndex + 3] = vertIndex;
        triangles[triangleIndex + 4] = vertIndex + 2;
        triangles[triangleIndex + 5] = vertIndex + 3;
    }

    void SetColor(int index, Color color)
    {
        colors[index + 0] = color;
        colors[index + 1] = color;
        colors[index + 2] = color;
        colors[index + 3] = color;
    }

    //构建Meag
    public void RebuildMesh()
    {
        if (m_isDrawUving)
        {
            return;
        }
        var blocks = vp.GetBlocks;
        var charList = vp.GetCharList;

        for (int i = 0; i < blocks.Length; i++)
        {
            if (blocks[i] == -1)
            {
                CharacterInfo ch;
                if (!spriteHelper.GetCharacterInfo(charList[i], out ch))
                {
                    uvNeedRebuild = true;
                    return;
                }
                SetUv(i << 2, ch);
            }
        }
        needRefresh = true;
    }

    private void SetUv(int index, CharacterInfo ch)
    {
        //矩形的四个顶点
        var uvTopLeft = ch.uvTopLeft;
        var uvTopRight = ch.uvTopRight;
        var uvBottomRight = ch.uvBottomRight;
        var uvBottomLeft = ch.uvBottomLeft;
        if (uvTopLeft == uvTopRight)
        {
            return;
        }

        uvs[index + 1] = uvTopLeft;
        uvs[index + 2] = uvTopRight;
        uvs[index + 3] = uvBottomRight;
        uvs[index + 0] = uvBottomLeft;
    }

    public void Update()
    {
        if (!this.bShow)
        {
            return;
        }

        if (needRefresh)
        {
            RefreshMesh();
            needRefresh = false;
        }

        if (null == m_requireList || dynamic == false)
        {
            return;
        }

        var e = m_requireList.GetEnumerator();
        while (e.MoveNext())
        {
            spriteHelper.getFont.RequestCharactersInTexture(e.Current.Value.outPutString);
        }

        if (uvNeedRebuild)
        {
            uvNeedRebuild = false;
            RebuildMesh();
        }
    }

    private void RefreshMesh()
    {
        mesh.vertices = vertices;
        mesh.uv = uvs;
        mesh.triangles = triangles;
        mesh.colors = colors;
    }

    private Vector3 SetVertOffsetVector(Vector3 pos, float x, float y)
    {
        pos.x += x;
        pos.y += y;
        return pos;
    }

    private void SetVert(int index, Vector3 pos, float maxX, float maxY, Vector3 scale)
    {
        int x = maxX > 0 ? 1 : -1;
        int y = maxY > 0 ? 1 : -1;
        if (y < 0)
        {
            pos.y += scale.y;
        }

        vertices[index + 1] = SetVertOffsetVector(pos, 0, scale.y * y);

        vertices[index + 2] = SetVertOffsetVector(pos, scale.x * x, scale.y * y);

        vertices[index + 3] = SetVertOffsetVector(pos, scale.x * x, 0);

        vertices[index + 0] = pos;
    }

    public void RefreshDynamicPos(List<int> vertIndexList, Vector3 pos, Vector3 scale)
    {
        if (null == vertIndexList) return;
        UIMeshText meshText = m_requireList[vertIndexList];
        if (pos == meshText.pos)
            return;
        meshText.pos = pos;
        meshText.scaleVec = scale;
        pos.x -= scale.x * 0.5f;
        m_isDrawUving = true;
        var listCount = vertIndexList.Count;
        for (int i = 0; i < listCount; i++)
        {
            int verticeStartIndex = vertIndexList[i] << 2;
            SetVert(verticeStartIndex, pos, meshText.maxX[i], meshText.maxY[i], scale);
            pos.x += meshText.advance[i] * scale.z;
        }
        needRefresh = true;
        m_isDrawUving = false;
    }

    public void RefreshDynamicPos(List<int> vertIndexList, string showString, Vector3 pos, float scale, Color color, float scaleGlobal = 0.1f)
    {
        if (null == vertIndexList) return;
        UIMeshText meshText = m_requireList[vertIndexList];
        if (showString == meshText.originString && pos == meshText.pos && color == meshText.color)
            return;
        meshText.pos = pos;
        meshText.color = color;
        showString = meshText.outPutString;
        if (showString != null)
        {
            pos.x -= meshText.offset.x * 0.5f;
        }
        m_isDrawUving = true;
        var listCount = vertIndexList.Count;
        for (int i = 0; i < listCount; i++)
        {
            int verticeStartIndex = vertIndexList[i] << 2;
            //Color c = meshText.colorArray[i] == null ? color : (Color)meshText.colorArray[i];
            SetVert(verticeStartIndex, pos, meshText.minX[i], meshText.minY[i], meshText.maxX[i], meshText.maxY[i], scale);
            SetColor(verticeStartIndex, color);
            pos.x += meshText.advance[i] * scale;
        }
        needRefresh = true;
        m_isDrawUving = false;
    }

    public void RefreshDynamicPos(List<int> vertIndexList, Color color)
    {
        if (null == vertIndexList) return;
        UIMeshText meshText = m_requireList[vertIndexList];
        if (color == meshText.color)
            return;
        meshText.color = color;
        m_isDrawUving = true;
        var listCount = vertIndexList.Count;
        for (int i = 0; i < listCount; i++)
        {
            int verticeStartIndex = vertIndexList[i] << 2;
            SetColor(verticeStartIndex, color);
        }
        needRefresh = true;
        m_isDrawUving = false;
    }

    public void RefreshDynamicPos(List<int> vertIndexList, string showString, Vector3 pos, Vector3 scale, Color color, float scaleGlobal = 0.1f)
    {
        if (null == vertIndexList) return;
        UIMeshText meshText = m_requireList[vertIndexList];
        showString = meshText.outPutString;
        if (showString == meshText.originString && pos == meshText.pos && color == meshText.color && meshText.scaleVec == scale) return;
        meshText.pos = pos;
        meshText.color = color;
        meshText.scaleVec = scale;
        pos.x -= scale.x * 0.5f;
        m_isDrawUving = true;
        var listCount = vertIndexList.Count;
        for (int i = 0; i < listCount; i++)
        {
            int verticeStartIndex = vertIndexList[i] << 2;

            //Color c = color//meshText.colorArray[i] == null ? color : (Color)meshText.colorArray[i];
            SetVert(verticeStartIndex, pos, meshText.maxX[i], meshText.maxY[i], scale);
            SetColor(verticeStartIndex, color);
            pos.x += meshText.advance[i] * scale.z;
        }
        needRefresh = true;
        m_isDrawUving = false;
    }

    public void LuanMa(List<int> vertIndexList)
    {
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < vertIndexList.Count; i++)
        {
            int vertIndex = vertIndexList[i];
            int index = vertIndex << 2;
            sb.Append(string.Format("{0}=", vertIndex));
            for (int k = 0; k < 4; k++)
            {
                sb.Append(string.Format("({0:0.000000},{1:0.000000}) ", uvs[index + k].x, uvs[index + k].y));
            }
            sb.Append("\n");
        }
        Debugger.Log("strUV==" + sb.ToString());
    }

    public void SetUVNeedRebuild()
    {
        uvNeedRebuild = true;
    }

    public Vector2 GetTextOffset(List<int> vertIndexList, float scale)
    {
        if (null == vertIndexList)
            return Vector2.zero;
        UIMeshText meshText = m_requireList[vertIndexList];
        if (meshText != null)
            return meshText.offset;
        return Vector2.zero;
    }

    public List<int> DrawDynamicTextUVs(string showString, Vector3 pos, float scale, Color color, float scaleGlobal = 0.1f, bool isCrit = false)
    {
        if (!vp.TestVert(showString.Length))
        {
            return null;
        }
        UIMeshText meshText = textGenerator.GeneratText(showString);
        meshText.pos = pos;
        meshText.scale = scale;
        meshText.color = color;
        if (dynamic)
            spriteHelper.getFont.RequestCharactersInTexture(meshText.outPutString);
        List<int> indexArray = new List<int>();
        int vertIndex;
        bool bSuccess = true;
        var offsets = GetTextRect(meshText.outPutString, scale, out bSuccess);
        if (!bSuccess)
        {
            Debugger.LogError("DrawDynamicTextUVs uv error={0}", showString);
            return null;
        }

        meshText.offset = offsets;
        pos.x -= offsets.x * 0.5f;
        for (int i = 0; i < meshText.outPutString.Length; i++)
        {
            vertIndex = vp.GetVert(meshText.outPutString[i]);
            if (vertIndex == -1)
            {
                return null;
            }
            indexArray.Add(vertIndex);

            int verticeStartIndex = vertIndex << 2;
            int triangleStartIndex = vertIndex * 6;

            CharacterInfo ch;
            Color c = meshText.colorArray[i] == null ? color : (Color)meshText.colorArray[i];
            if (!spriteHelper.GetCharacterInfo(meshText.outPutString[i], out ch))
            {
                uvNeedRebuild = true;
                continue;
            }

            if ((meshText.outPutString[i] == '暴' || meshText.outPutString[i] == '击') && isCrit)
            {
                meshText.minX[i] = ch.minX * critScale;
                meshText.maxX[i] = ch.maxX * critScale;
                meshText.minY[i] = ch.minY * critScale;
                meshText.maxY[i] = ch.maxY * critScale;
                meshText.advance[i] = ch.advance * critScale;
            }
            else
            {
                meshText.minX[i] = ch.minX;
                meshText.maxX[i] = ch.maxX;
                meshText.minY[i] = ch.minY;
                meshText.maxY[i] = ch.maxY;
                meshText.advance[i] = ch.advance;
            }

            SetVert(verticeStartIndex, pos, meshText.minX[i], meshText.minY[i], meshText.maxX[i], meshText.maxY[i], scale);
            SetUv(verticeStartIndex, ch);
            SetColor(verticeStartIndex, c);
            SetTriangle(triangleStartIndex, verticeStartIndex);
            pos.x += meshText.advance[i] * scale;
        }
        needRefresh = true;
        if (!m_requireList.ContainsKey(indexArray))
            m_requireList.Add(indexArray, meshText);
        return indexArray;
    }

    private void SetVert(int index, Vector3 pos, float minX, float minY, float maxX, float maxY, float scale)
    {
        minX *= scale;
        maxX *= scale;
        minY *= scale;
        maxY *= scale;

        vertices[index + 1] = SetVertOffsetVector(pos, minX, maxY);

        vertices[index + 2] = SetVertOffsetVector(pos, maxX, maxY);

        vertices[index + 3] = SetVertOffsetVector(pos, maxX, minY);

        vertices[index + 0] = SetVertOffsetVector(pos, minX, minY);
    }

    public Vector2 GetTextRect(string showString, float scale, out bool bSuccess, bool isCrit = false)
    {
        float length = 0;
        float heigth = 0;
        bSuccess = true;
        for (int i = 0; i < showString.Length; i++)
        {
            CharacterInfo ch;
            bSuccess = spriteHelper.GetCharacterInfo(showString[i], out ch);
            if (!bSuccess)
            {
                break;
            }

            if ((showString[i] == '暴' || showString[i] == '击') && isCrit)
            {
                length += ch.advance * scale * critScale;
                float fAbsHeight = Mathf.Abs(ch.glyphHeight);
                heigth = heigth > fAbsHeight ? heigth : fAbsHeight;
            }
            else
            {
                length += ch.advance * scale;
                float fAbsHeight = Mathf.Abs(ch.glyphHeight);
                heigth = heigth > fAbsHeight ? heigth : fAbsHeight;
            }
        }
        m_rectVec.x = length;
        m_rectVec.y = heigth;
        return m_rectVec;

    }
    public void RefreshVertPos(List<int> vertArray, Vector3 pos, float scale, Color color, float vertAngle = 0)
    {
        RefreshDynamicPos(vertArray, null, pos, scale, color);
    }

    public void ReleaseVert(List<int> vertArray)
    {
        if (null == vertArray) return;
        for (int i = 0; i < vertArray.Count; i++)
        {
            vp.ReleaseVert(vertArray[i]);
            DrawMesh(vertArray[i] * 4, Rect.zero, Rect.zero, Color.white);
        }
        //ListPool<int>.Release(vertArray);
        if (m_requireList.ContainsKey(vertArray))
            m_requireList.Remove(vertArray);
        needRefresh = true;
    }

    public List<int> DrawDamage(string showString, Vector3 pos, float scale, Color color, bool isCrit = false)
    {
        //请有bug修复bug,不要在这里用Replace方式处理文字。以下代码屏蔽@hmz
        //showString = showString.Replace(" ", "");
        return DrawDynamicTextUVs(showString, pos, scale, color, 0.1f, isCrit);
    }
}
  1. 简单测试代码
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class MyMeshText : MonoBehaviour
{
    UIMesh mesh;
    public UnityEngine.UI.Text text;
    private List<int> m_meshArry = new List<int>();
    void Start()
    {
        mesh = new UIMesh(gameObject, "mymesh", text.font, true, 1024);
        m_meshArry = mesh.DrawDamage("闪避", new Vector3(978, 529, 0), 0.4f, Color.black, false);
    }

    int i = 0; 
    // Update is called once per frame
    void Update()
    {
        if (null != mesh)
            mesh.Update();

        mesh.Show(true);

        if (Input.GetKeyDown(KeyCode.A))
        {
            i += 100;
            mesh.ReleaseVert(m_meshArry);
            m_meshArry.Clear();
            m_meshArry =  mesh.DrawDamage("44444525", new Vector3(978, 529 + i, 0), 0.4f, Color.black, false);
        }
    }
}

在这里插入图片描述
这样我们只需要对一个Mesh操作就能实现很多伤害飘血。而不需要像之前那样美一条伤害飘血都去创建一个UIText显示。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值