zoukankan      html  css  js  c++  java
  • Unity UGUI图文混排(五) -- 一张图集对应多个Text

    继上一篇说的更新了一张图集对应多个Text的功能,为了节省资源嘛

    这里,但是也没有舍弃之前的一个Text一个图集,因为我感觉应该两个都有用,于是我重新写了一个脚本


    1.其实大体跟前面的都没变,解析标签,获取表情的相关数据,这里只是将绘制图片的功能,移植到SpriteGraphic上,本地增加了一个刷新图片绘制信息的函数。

    麻烦的是去找到SpriteGraphic绘制图片,也是因为这个感觉有很大的潜在问题,不过基本能用,具体看脚本

    using UnityEngine;
    using UnityEngine.UI;
    using System.Collections.Generic;
    using System.Text.RegularExpressions;
    
    public class InlieSpriteText : Text {
    
        /// <summary>
        /// 用正则取标签属性 名称-大小-宽度比例
        /// </summary>
        private static readonly Regex m_spriteTagRegex =
              new Regex(@"<quad name=(.+?) size=(d*.?d+%?) width=(d*.?d+%?) />", RegexOptions.Singleline);
    
        /// <summary>
        /// 图片资源
        /// </summary>
        private SpriteAsset m_spriteAsset;
        /// <summary>
        /// 图片渲染组件
        /// </summary>
        private SpriteGraphic m_spriteGraphic;
        /// <summary>
        /// CanvasRenderer
        /// </summary>
        private CanvasRenderer m_spriteCanvasRenderer;
    
        /// <summary>
        /// 图片渲染管理
        /// </summary>
        private SpriteGraphicManager m_SGManager;
    
        #region 动画标签解析
        //最多动态表情数量
        int AnimNum = 8;
      //  List<int> m_AnimIndex;
        List<SpriteTagInfor[]> m_AnimSpiteTag;
        public List<InlineSpriteInfor[]> m_AnimSpriteInfor;
        #endregion
    
        /// <summary>
        /// 初始化 
        /// </summary>
        protected override void OnEnable()
        {
            //在编辑器中,可能在最开始会出现一张图片,就是因为没有激活文本,在运行中是正常的。可根据需求在编辑器中选择激活...
            base.OnEnable();
            //对齐几何
            alignByGeometry = true;
            
            #region 为了将SpriteGraphicManager显示到最上级,这里的SpriteGraphicManager可能会放在最下面,所以需要从全局去找
            if (m_SGManager == null)
                m_SGManager = GameObject.FindObjectOfType<SpriteGraphicManager>();
            #endregion
    
            if (m_SGManager != null)
            {
                m_spriteGraphic = m_SGManager.GetComponent<SpriteGraphic>();
                m_spriteCanvasRenderer = m_SGManager.GetComponent<CanvasRenderer>();
                m_spriteAsset = m_spriteGraphic.m_spriteAsset;
            }
    
            //初始化 调用顶点绘制
            SetVerticesDirty();
        }
    
    
       
    
    
        /// <summary>
        /// 在设置顶点时调用
        /// </summary>
        public override void SetVerticesDirty()
        {
            base.SetVerticesDirty();
            
          //  m_AnimIndex = new List<int>();
            m_AnimSpiteTag = new List<SpriteTagInfor[]>();
    
            foreach (Match match in m_spriteTagRegex.Matches(text))
            {
                if (m_spriteAsset == null)
                    return;
    
                #region 解析动画标签
                List<string> tempListName = new List<string>();
                for (int i = 0; i < m_spriteAsset.listSpriteInfor.Count; i++)
                {
                   // Debug.Log((m_spriteAsset.listSpriteInfor[i].name));
                    if (m_spriteAsset.listSpriteInfor[i].name.Contains(match.Groups[1].Value))
                    {
                        tempListName.Add(m_spriteAsset.listSpriteInfor[i].name);
                    }
                }
                if (tempListName.Count > 0)
                {
                    SpriteTagInfor[] tempArrayTag = new SpriteTagInfor[tempListName.Count];
                    for (int i = 0; i < tempArrayTag.Length; i++)
                    {
                        tempArrayTag[i] = new SpriteTagInfor();
                        tempArrayTag[i].name = tempListName[i];
                        tempArrayTag[i].index = match.Index;
                        tempArrayTag[i].size = new Vector2(float.Parse(match.Groups[2].Value) * float.Parse(match.Groups[3].Value), float.Parse(match.Groups[2].Value));
                        tempArrayTag[i].Length = match.Length;
                    }
                    m_AnimSpiteTag.Add(tempArrayTag);
                }
                #endregion
            }
        }
    
        readonly UIVertex[] m_TempVerts = new UIVertex[4];
        /// <summary>
        /// 绘制模型
        /// </summary>
        /// <param name="toFill"></param>
        protected override void OnPopulateMesh(VertexHelper toFill)
        {
            //  base.OnPopulateMesh(toFill);
    
            if (font == null)
                return;
    
            // We don't care if we the font Texture changes while we are doing our Update.
            // The end result of cachedTextGenerator will be valid for this instance.
            // Otherwise we can get issues like Case 619238.
            m_DisableFontTextureRebuiltCallback = true;
    
            Vector2 extents = rectTransform.rect.size;
    
            var settings = GetGenerationSettings(extents);
            cachedTextGenerator.Populate(text, settings);
    
            Rect inputRect = rectTransform.rect;
    
            // get the text alignment anchor point for the text in local space
            Vector2 textAnchorPivot = GetTextAnchorPivot(alignment);
            Vector2 refPoint = Vector2.zero;
            refPoint.x = (textAnchorPivot.x == 1 ? inputRect.xMax : inputRect.xMin);
            refPoint.y = (textAnchorPivot.y == 0 ? inputRect.yMin : inputRect.yMax);
    
            // Determine fraction of pixel to offset text mesh.
            Vector2 roundingOffset = PixelAdjustPoint(refPoint) - refPoint;
    
            // Apply the offset to the vertices
            IList<UIVertex> verts = cachedTextGenerator.verts;
            float unitsPerPixel = 1 / pixelsPerUnit;
            //Last 4 verts are always a new line...
            int vertCount = verts.Count - 4;
    
            toFill.Clear();
    
            //清楚乱码
            for (int i = 0; i < m_AnimSpiteTag.Count; i++)
            {
                if (m_AnimSpiteTag[i].Length > 0)
                {
                    //UGUIText不支持<quad/>标签,表现为乱码,我这里将他的uv全设置为0,清除乱码
                    for (int m = m_AnimSpiteTag[i][0].index * 4; m < m_AnimSpiteTag[i][0].index * 4 + 4; m++)
                    {
                        UIVertex tempVertex = verts[m];
                        tempVertex.uv0 = Vector2.zero;
                        verts[m] = tempVertex;
                    }
                }
            }
                //计算标签   其实应该计算偏移值后 再计算标签的值    算了 后面再继续改吧
                //  CalcQuadTag(verts);
    
            if (roundingOffset != Vector2.zero)
            {
                for (int i = 0; i < vertCount; ++i)
                {
                    int tempVertsIndex = i & 3;
                    m_TempVerts[tempVertsIndex] = verts[i];
                    m_TempVerts[tempVertsIndex].position *= unitsPerPixel;
                    m_TempVerts[tempVertsIndex].position.x += roundingOffset.x;
                    m_TempVerts[tempVertsIndex].position.y += roundingOffset.y;
                    if (tempVertsIndex == 3)
                        toFill.AddUIVertexQuad(m_TempVerts);
                }
            }
            else
            {
                for (int i = 0; i < vertCount; ++i)
                {
                    int tempVertsIndex = i & 3;
                    m_TempVerts[tempVertsIndex] = verts[i];
                    m_TempVerts[tempVertsIndex].position *= unitsPerPixel;
                    if (tempVertsIndex == 3)
                        toFill.AddUIVertexQuad(m_TempVerts);
                }
            }
    
            //计算标签 计算偏移值后 再计算标签的值
            List<UIVertex> vertsTemp = new List<UIVertex>();
            for (int i = 0; i < vertCount; i++)
            {
                UIVertex tempVer=new UIVertex();
                toFill.PopulateUIVertex(ref tempVer,i);
                vertsTemp.Add(tempVer);
            }
            CalcQuadTag(vertsTemp);
    
            m_DisableFontTextureRebuiltCallback = false;
    
            //更新绘制图片信息
            if(m_SGManager!=null)
                m_SGManager.UpdateSpriteInfor();
            //DrawSprite();
        }
    
    
        private IList<UIVertex> _OldVerts;
    
        #region 计算标签
        /// <summary>
        /// 解析quad标签  主要清除quad乱码 获取表情的位置
        /// </summary>
        /// <param name="verts"></param>
        void CalcQuadTag(IList<UIVertex> verts)
        {
    
            m_AnimSpriteInfor = new List<InlineSpriteInfor[]>();
    
            Vector3 _TempStartPos = Vector3.zero;
            if(m_SGManager!=null)
                _TempStartPos = transform.position - m_SGManager.transform.position;
    
            for (int i = 0; i < m_AnimSpiteTag.Count; i++)
            {
                SpriteTagInfor[] tempTagInfor = m_AnimSpiteTag[i];
                InlineSpriteInfor[] tempSpriteInfor = new InlineSpriteInfor[tempTagInfor.Length];
                for (int j = 0; j < tempTagInfor.Length; j++)
                {
                    tempSpriteInfor[j] = new InlineSpriteInfor();
                    tempSpriteInfor[j].textpos = _TempStartPos + verts[((tempTagInfor[j].index + 1) * 4) - 1].position;
                    //设置图片的位置
                    tempSpriteInfor[j].vertices = new Vector3[4];
                    tempSpriteInfor[j].vertices[0] = new Vector3(0, 0, 0) + tempSpriteInfor[j].textpos;
                    tempSpriteInfor[j].vertices[1] = new Vector3(tempTagInfor[j].size.x, tempTagInfor[j].size.y, 0) + tempSpriteInfor[j].textpos;
                    tempSpriteInfor[j].vertices[2] = new Vector3(tempTagInfor[j].size.x, 0, 0) + tempSpriteInfor[j].textpos;
                    tempSpriteInfor[j].vertices[3] = new Vector3(0, tempTagInfor[j].size.y, 0) + tempSpriteInfor[j].textpos;
    
                    //计算其uv
                    Rect newSpriteRect = m_spriteAsset.listSpriteInfor[0].rect;
                    for (int m = 0; m < m_spriteAsset.listSpriteInfor.Count; m++)
                    {
                        //通过标签的名称去索引spriteAsset里所对应的sprite的名称
                        if (tempTagInfor[j].name == m_spriteAsset.listSpriteInfor[m].name)
                            newSpriteRect = m_spriteAsset.listSpriteInfor[m].rect;
                    }
                    Vector2 newTexSize = new Vector2(m_spriteAsset.texSource.width, m_spriteAsset.texSource.height);
    
                    tempSpriteInfor[j].uv = new Vector2[4];
                    tempSpriteInfor[j].uv[0] = new Vector2(newSpriteRect.x / newTexSize.x, newSpriteRect.y / newTexSize.y);
                    tempSpriteInfor[j].uv[1] = new Vector2((newSpriteRect.x + newSpriteRect.width) / newTexSize.x, (newSpriteRect.y + newSpriteRect.height) / newTexSize.y);
                    tempSpriteInfor[j].uv[2] = new Vector2((newSpriteRect.x + newSpriteRect.width) / newTexSize.x, newSpriteRect.y / newTexSize.y);
                    tempSpriteInfor[j].uv[3] = new Vector2(newSpriteRect.x / newTexSize.x, (newSpriteRect.y + newSpriteRect.height) / newTexSize.y);
    
                    //声明三角顶点所需要的数组
                    tempSpriteInfor[j].triangles = new int[6];
                }
                m_AnimSpriteInfor.Add(tempSpriteInfor);
    
                _OldVerts = verts;
            }
        }
        #endregion
    
        #region 更新图片的信息
        public void UpdateSpriteInfor()
        {
            if (_OldVerts == null)
                return;
    
            CalcQuadTag(_OldVerts);
        }
        #endregion
    
    }
    2.这里新写了一个SpriteGraphicManager脚本用来管理SpriteGraphic的图片绘制,和获取InlieSpriteText传来的相关绘制图片的信息,SpriteGraphicManager就是绑定在SpriteGraphic上的,因为UGUI的渲染顺序是从上到下,SpriteGraphic的放置位置就显得比较尴尬了,应该可以用shader更改渲染层级,没去试,先这样吧,我这里将SpriteGraphic放在最下面的

    using UnityEngine;
    using System.Collections;
    using System.Collections.Generic;
    
    
    /********
    为了图片渲染在最上面
    需要将他放砸canvas的最下层
    应该可以改shader的渲染顺序  没去试  就这样写吧
    *********/
    
    [RequireComponent(typeof(SpriteGraphic))]
    public class SpriteGraphicManager : MonoBehaviour {
    
        /// <summary>
        /// 需要渲染的图片信息列表
        /// </summary>
        private List<InlineSpriteInfor> listSprite;
        #region 动画标签解析
        //最多动态表情数量
        int AnimNum = 8;
        List<InlineSpriteInfor[]> m_AnimSpriteInfor;
        #endregion
    
        #region 更新图片信息
        public void UpdateSpriteInfor()
        {
            listSprite = new List<InlineSpriteInfor>();
            m_AnimSpriteInfor = new List<InlineSpriteInfor[]>();
    
            //  inline
            //  InlieSpriteText[] AllInlieSpriteText = GetComponentsInChildren<InlieSpriteText>();
            //  找到所有InlieSpriteText的物体  ----  这里隐藏问题蛮大的  他搜索的所有的InlieSpriteText
            //  包括InlieSpriteText也是全局搜索的SpriteGraphicManager,意思SpriteGraphicManager最好只有一个 
            //  当然 可以自定义根据功能   自己改了  我这里是这么定义的
            InlieSpriteText[] AllInlieSpriteText = GameObject.FindObjectsOfType<InlieSpriteText>();
    
            for (int i = 0; i < AllInlieSpriteText.Length; i++)
            {
                if (AllInlieSpriteText[i].m_AnimSpriteInfor != null)
                {
                    AllInlieSpriteText[i].UpdateSpriteInfor();
                    for (int j = 0; j < AllInlieSpriteText[i].m_AnimSpriteInfor.Count; j++)
                    {
                        m_AnimSpriteInfor.Add(AllInlieSpriteText[i].m_AnimSpriteInfor[j]);
                        listSprite.Add(AllInlieSpriteText[i].m_AnimSpriteInfor[j][0]);
                    }
                }
            }
            DrawSprite();
        }
        #endregion
    
    
        #region update刷新动画
        float fTime = 0.0f;
        int iIndex = 0;
        void Update()
        {
            if (m_AnimSpriteInfor == null)
                return;
    
            fTime += Time.deltaTime;
            if (fTime >= 0.1f)
            {
                //刷新一次 更新绘制图片的相关信息
                UpdateSpriteInfor();
    
                for (int i = 0; i < m_AnimSpriteInfor.Count; i++)
                {
                    if (iIndex >= m_AnimSpriteInfor[i].Length)
                    {
                        listSprite[i] = m_AnimSpriteInfor[i][0];
                    }
                    else
                    {
                        listSprite[i] = m_AnimSpriteInfor[i][iIndex];
                    }
                }
                DrawSprite();
                iIndex++;
                if (iIndex >= AnimNum)
                {
                    iIndex = 0;
                }
                fTime = 0.0f;
            }
        }
        #endregion
    
        
    
        #region 绘制图片
        /// <summary>
        /// 绘制图片
        /// </summary>
        void DrawSprite()
        {
            Mesh m_spriteMesh = new Mesh();
    
            List<Vector3> tempVertices = new List<Vector3>();
            List<Vector2> tempUv = new List<Vector2>();
            List<int> tempTriangles = new List<int>();
    
            for (int i = 0; i < listSprite.Count; i++)
            {
                for (int j = 0; j < listSprite[i].vertices.Length; j++)
                {
                    tempVertices.Add(listSprite[i].vertices[j]);
                }
                for (int j = 0; j < listSprite[i].uv.Length; j++)
                {
                    tempUv.Add(listSprite[i].uv[j]);
                }
                for (int j = 0; j < listSprite[i].triangles.Length; j++)
                {
                    tempTriangles.Add(listSprite[i].triangles[j]);
                }
            }
            //计算顶点绘制顺序
            for (int i = 0; i < tempTriangles.Count; i++)
            {
                if (i % 6 == 0)
                {
                    int num = i / 6;
                    tempTriangles[i] = 0 + 4 * num;
                    tempTriangles[i + 1] = 1 + 4 * num;
                    tempTriangles[i + 2] = 2 + 4 * num;
    
                    tempTriangles[i + 3] = 1 + 4 * num;
                    tempTriangles[i + 4] = 0 + 4 * num;
                    tempTriangles[i + 5] = 3 + 4 * num;
                }
            }
    
            m_spriteMesh.vertices = tempVertices.ToArray();
            m_spriteMesh.uv = tempUv.ToArray();
            m_spriteMesh.triangles = tempTriangles.ToArray();
    
            if (m_spriteMesh == null)
                return;
            
            GetComponent<CanvasRenderer>().SetMesh(m_spriteMesh);
            GetComponent<SpriteGraphic>().UpdateMaterial();
        }
        #endregion
    
    }
    
    3.差不多一张图集对应多个Text的功能就完了,看一下截图,因为这都是根据之前的更新的,看了之前工程的同学都应该能看明白,我架设你们都看过了


    4.这里还更新了一个小东西,就是做聊天demo的时候感觉之前的标签太长,比如<quad name=meat size=20 width=1 />,确实有点长,本来应该表情也绘制在输入框的,一是自己也没去测试,二是有同学已经测试,但是发现不少问题,我暂时也就将标签缩短了<#meat>


    5.之前的工程的基本功能都是基本完善的,最新的基本都是一些功能和逻辑上的扩展:  工程链接

  • 相关阅读:
    第五届河南省大学生程序设计竞赛 :最强DE战斗力(大数乘法)
    zzuli2455: 最大增区间(一)
    zzuli2455: 最大增区间(一)
    zzuli2424: 越靠近,越幸运(dfs)
    菜根谭#31
    菜根谭#30
    菜根谭#29
    菜根谭#28
    菜根谭#27
    菜根谭#26
  • 原文地址:https://www.cnblogs.com/liang123/p/6325847.html
Copyright © 2011-2022 走看看