• Unity UGUI图文混排源码(二)


    Unity UGUI图文混排源码(一):http://blog.csdn.net/qq992817263/article/details/51112304

    Unity UGUI图文混排源码(二):http://blog.csdn.net/qq992817263/article/details/51112311

    为了方便整理,申请了一个专栏,链接:Unity UGUI图文混排专栏


    图文混排解决方案二:

    通过继承Text组件来获取文字的UIVertex并得到他的位置,通过Text富文本的<quad />来为图片占位,这样来实现图文混排,这里参考了一篇博客:http://blog.csdn.net/akof1314/article/details/49028279

    1.这里我们会使用到一个SpriteAsset,具体的创建方法:http://blog.csdn.net/qq992817263/article/details/50958025

    2.自定义一个渲染组件,用来渲染图片,后面我会将他放在Text文本下,这里会用一个参数,就是上面的SpriteAsset文件,具体代码如下

    using UnityEngine;
    using UnityEngine.UI;
    using System.Collections;
    
    public class SpriteGraphic : MaskableGraphic {
        public SpriteAsset m_spriteAsset;
    
        public override Texture mainTexture
        {
            get
            {
                if (m_spriteAsset == null)
                    return s_WhiteTexture;
    
                if (m_spriteAsset.texSource == null)
                    return s_WhiteTexture;
                else
                    return m_spriteAsset.texSource;
            }
        }
    
    #if UNITY_EDITOR
        //在编辑器下 
        protected override void OnValidate()
        {
            base.OnValidate();
            //Debug.Log("Texture ID is " + this.texture.GetInstanceID());
        }
    #endif
    
        protected override void OnRectTransformDimensionsChange()
        {
            // base.OnRectTransformDimensionsChange();
        }
    
        /// <summary>
        /// 绘制后 需要更新材质
        /// </summary>
        public new void UpdateMaterial()
        {
            base.UpdateMaterial();
        }
    }
    

    3.自定义一个脚本用来继承Text,这里就是一个较为核心的代码,里面写了较为详细的注释

    using UnityEngine;
    using UnityEngine.UI;
    using System.Collections.Generic;
    using System.Text.RegularExpressions;
    
    public class InlieText : Text {
    
        /// <summary>
        /// 用正则取标签属性 名称-大小-宽度比例
        /// </summary>
        private static readonly Regex m_spriteTagRegex =
              new Regex(@"<quad name=(.+?) size=(d*.?d+%?) width=(d*.?d+%?) />", RegexOptions.Singleline);
        /// <summary>
        /// 需要渲染的图片信息列表
        /// </summary>
        private List<InlineSpriteInfor> listSprite;
        /// <summary>
        /// 图片资源
        /// </summary>
        private SpriteAsset m_spriteAsset;
        /// <summary>
        /// 标签的信息列表
        /// </summary>
        private List<SpriteTagInfor> listTagInfor;
        /// <summary>
        /// 图片渲染组件
        /// </summary>
        private SpriteGraphic m_spriteGraphic;
        /// <summary>
        /// CanvasRenderer
        /// </summary>
        private CanvasRenderer m_spriteCanvasRenderer;
    
        /// <summary>
        /// 初始化 
        /// </summary>
        protected override void OnEnable()
        {
            base.OnEnable();
            if (m_spriteGraphic == null)
                m_spriteGraphic = GetComponentInChildren<SpriteGraphic>();
            if (m_spriteCanvasRenderer == null)
                m_spriteCanvasRenderer = m_spriteGraphic.GetComponentInChildren<CanvasRenderer>();
            m_spriteAsset = m_spriteGraphic.m_spriteAsset;
        }
    
        /// <summary>
        /// 在设置顶点时调用
        /// </summary>
        public override void SetVerticesDirty()
        {
            base.SetVerticesDirty();
            //解析标签属性
            listTagInfor = new List<SpriteTagInfor>();
            foreach (Match match in m_spriteTagRegex.Matches(text))
            {
                SpriteTagInfor tempSpriteTag = new SpriteTagInfor();
                tempSpriteTag.name = match.Groups[1].Value;
                tempSpriteTag.index = match.Index;
                tempSpriteTag.size = new Vector2(float.Parse(match.Groups[2].Value)*float.Parse(match.Groups[3].Value), float.Parse(match.Groups[2].Value));
                listTagInfor.Add(tempSpriteTag);
            }
        }
    
        /// <summary>
        /// 绘制模型
        /// </summary>
        /// <param name="toFill"></param>
        protected override void OnPopulateMesh(VertexHelper toFill)
        {
            base.OnPopulateMesh(toFill);
            //获取所有的UIVertex,绘制一个字符对应6个UIVertex,绘制顺序为012 203
            List<UIVertex> listUIVertex = new List<UIVertex>();
            toFill.GetUIVertexStream(listUIVertex);
            
            //通过标签信息来设置需要绘制的图片的信息
            listSprite = new List<InlineSpriteInfor>();
            for (int i = 0; i < listTagInfor.Count; i++)
            {
                //UGUIText不支持<quad/>标签,表现为乱码,我这里将他的uv全设置为0,清除乱码
                for (int m = listTagInfor[i].index*6; m < listTagInfor[i].index*6 + 6; m++)
                {
                    UIVertex tempVertex = listUIVertex[m];
                    tempVertex.uv0 = Vector2.zero;
                    listUIVertex[m] = tempVertex;
                }
    
                InlineSpriteInfor tempSprite = new InlineSpriteInfor();
                //如果图片在第一个位置,则计算他的位置为文本的初始点位置
                //否,则返回上一个字符的第三个UIVertex的position,这是根据他的顶点的绘制顺序所获得的
                if (listTagInfor[i].index == 0)
                {
                    Vector2 anchorPivot = GetTextAnchorPivot(alignment);
                    Vector2 rectSize = rectTransform.sizeDelta;
                    
                    tempSprite.textpos = -rectSize / 2.0f + new Vector2(rectSize.x * anchorPivot.x,rectSize.y*anchorPivot.y- listTagInfor[i].size.y);
    
                }
                else
                    tempSprite.textpos = listUIVertex[listTagInfor[i].index * 6 - 4].position;
                
                //设置图片的位置
                tempSprite.vertices = new Vector3[4];
                tempSprite.vertices[0] = new Vector3(0, 0, 0) + tempSprite.textpos;
                tempSprite.vertices[1] = new Vector3(listTagInfor[i].size.x, listTagInfor[i].size.y, 0) + tempSprite.textpos;
                tempSprite.vertices[2] = new Vector3(listTagInfor[i].size.x, 0, 0) + tempSprite.textpos;
                tempSprite.vertices[3] = new Vector3(0, listTagInfor[i].size.y, 0) + tempSprite.textpos;
    
                //计算其uv
                Rect spriteRect = m_spriteAsset.listSpriteInfor[0].rect;
                for (int j = 0; j < m_spriteAsset.listSpriteInfor.Count; j++)
                {
                    //通过标签的名称去索引spriteAsset里所对应的sprite的名称
                    if (listTagInfor[i].name == m_spriteAsset.listSpriteInfor[j].name)
                        spriteRect = m_spriteAsset.listSpriteInfor[j].rect;
                }
                Vector2 texSize = new Vector2(m_spriteAsset.texSource.width, m_spriteAsset.texSource.height);
    
                tempSprite.uv = new Vector2[4];
                tempSprite.uv[0] = new Vector2(spriteRect.x / texSize.x, spriteRect.y / texSize.y);
                tempSprite.uv[1] = new Vector2((spriteRect.x + spriteRect.width) / texSize.x, (spriteRect.y + spriteRect.height) / texSize.y);
                tempSprite.uv[2] = new Vector2((spriteRect.x + spriteRect.width) / texSize.x, spriteRect.y / texSize.y);
                tempSprite.uv[3] = new Vector2(spriteRect.x / texSize.x, (spriteRect.y + spriteRect.height) / texSize.y);
                
                //声明三角顶点所需要的数组
                tempSprite.triangles = new int[6];
                listSprite.Add(tempSprite);
            }
            //清除<quad />标签的乱码 重新绘制
            toFill.Clear();
            toFill.AddUIVertexTriangleStream(listUIVertex);
            DrawSprite();
        }
    
       /// <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;
    
            m_spriteCanvasRenderer.SetMesh(m_spriteMesh);
            m_spriteGraphic.UpdateMaterial();
        }
    
    }
    
    [System.Serializable]
    public class SpriteTagInfor
    {
        /// <summary>
        /// sprite名称
        /// </summary>
        public string name;
        /// <summary>
        /// 对应的字符索引
        /// </summary>
        public int index;
        /// <summary>
        /// 大小
        /// </summary>
        public Vector2 size;
    }
    
    
    [System.Serializable]
    public class InlineSpriteInfor
    {
        // 文字的最后的位置
        public Vector3 textpos;
        // 4 顶点 
        public Vector3[] vertices;
        //4 uv
        public Vector2[] uv;
        //6 三角顶点顺序
        public int[] triangles;
    }
    

    4.开始测试效果,创建一个InlieText组件,并在其组件下,添加一个SpriteGraphic组件,输入文字加标签测试

    InlieTex组件:


    SpriteGraphic组件:


    文字测试:


    5.做了一个聊天测试:


    6.同时在测试的时候就发现了些许bug,这里并不想写出来,有兴趣的可以一起修改讨论。

    工程使用的unity版本为unity的版本为:5.3.1f1


    最后给出工程链接:https://code.csdn.net/qq992817263/uguitextpro/tree/master

  • 相关阅读:
    Seaslog高性能日志系统学习
    同步、异步与阻塞、非阻塞、协程
    SQL常用增删改查语句
    js里的document对象大全(DOM操作)
    php的cURL资源的初步使用
    hive学习笔记(初级)
    使用NSIS制作可执行程序的安装包
    C#设置一个控件可以鼠标拖动
    C#画图超出屏幕的部分无法显示的解决方法
    C#获取当前不同网卡对应的iP
  • 原文地址:https://www.cnblogs.com/liang123/p/6325886.html
Copyright © 2020-2023  润新知