zoukankan      html  css  js  c++  java
  • 扩展UGuiText支持文字背景

    其实这个需求用TextMeshPro一分钟就能搞定,可TMP对中文动态字体的支持并不完美。针对即时输出的随机化文本,只能扩展Text来实现了。

    基本思路

    获得输出文本的每个字的位置和宽高数据。这个通过字体渲染时的顶点数据可以拿到。
    算法整合每行的最大高度
    整合所有行的bounds信息
    根据bounds大小来绘制Image

    Code

    using System.Collections;
    using System.Collections.Generic;
    using System.Linq;
    using UnityEngine;
    using UnityEngine.UI;
    
    public class TextBg : BaseMeshEffect
    {
        public class CharQuad
        {
            public UIVertex TopLeft { get; set; }
            public UIVertex TopRight { get; set; }
            public UIVertex BottomRight { get; set; }
            public UIVertex BottomLeft { get; set; }
    
            public float Left { get; set; }
            public float Right { get; set; }
            public float Top { get; set; }
            public float Bottom { get; set; }
    
            public void Calculate()
            {
                Left = TopLeft.position.x;
                Right = TopRight.position.x;
                Top = TopLeft.position.y;
                Bottom = BottomLeft.position.y;
            }
        }
    
        public override void ModifyMesh(VertexHelper vh)
        {
            if (!IsActive())
            {
                return;
            }
            int count = vh.currentVertCount;
            if (count <= 0)
            {
                return;
            }
            List<UIVertex> vertices = new List<UIVertex>();
            for (int i = 0; i < count; i++)
            {
                UIVertex vertex = new UIVertex();
                vh.PopulateUIVertex(ref vertex, i);
                vertex.color = Color.red;
                vertices.Add(vertex);
                //vh.SetUIVertex(vertex, i);
            }
            int charlen = count / 4;
    #if UNITY_EDITOR
            Debug.LogWarningFormat("text vertices count = {0} charlen = {1}", count, charlen);
    #endif
            CharQuad[] charquads = new CharQuad[charlen];
            //根据顶点拓扑顺序
            for (int i = 0; i < charlen; i++)
            {
                CharQuad cquad = new CharQuad();
                cquad.TopLeft = vertices[i * 4];
                cquad.TopRight = vertices[i * 4 + 1];
                cquad.BottomRight = vertices[i * 4 + 2];
                cquad.BottomLeft = vertices[i * 4 + 3];
                cquad.Calculate();
                charquads[i] = cquad;
            }
            //计算text行字符
            //如果字符换行了
            //1.n+1字符的top<=n字符的bottom
            List<CharQuad[]> cquadslist = new List<CharQuad[]>();
            if (charlen == 1)
            {
                cquadslist = new List<CharQuad[]>();
                cquadslist.Add(charquads);
            }
            else
            {
                List<CharQuad> cqlist = new List<CharQuad>();
                cqlist.Add(charquads[0]);
                for (int i = 1; i < charquads.Length; i++)
                {
                    CharQuad n0char = charquads[i - 1];
                    CharQuad n1char = charquads[i];
                    if (n1char.Top <= n0char.Bottom)
                    {
                        cquadslist.Add(cqlist.ToArray());
                        cqlist.Clear();
                    }
                    cqlist.Add(charquads[i]);
                }
                if (cqlist.Count > 0)
                {
                    cquadslist.Add(cqlist.ToArray());
                }
            }
            //计算bounds
            //计算text每一行的bound
            /*Vector4[] */bounds = new Vector4[cquadslist.Count];
            for (int i = 0; i < cquadslist.Count; i++)
            {
                CharQuad[] cquads = cquadslist[i];
                float left = float.MaxValue;
                float right = float.MinValue;
                float top = float.MinValue;
                float bottom = float.MaxValue;
                for (int k = 0; k < cquads.Length; k++)
                {
                    CharQuad cq = cquads[k];
                    if (left > cq.Left)
                    {
                        left = cq.Left;
                    }
                    if (right < cq.Right)
                    {
                        right = cq.Right;
                    }
                    if (top < cq.Top)
                    {
                        top = cq.Top;
                    }
                    if (bottom > cq.Bottom)
                    {
                        bottom = cq.Bottom;
                    }
                }
    #if UNITY_EDITOR
                Debug.LogWarningFormat("text mesh line = {0} charlen = {1} left = {2} right = {3} top = {4} bottom = {5}", i, cquads.Length, left, right, top, bottom);
    #endif
                bounds[i] = new Vector4(left, right, top, bottom);
            }
            //bounds参数以text组件中心点为原点,所以参数存在负值,需要处理成正值
            //以text组件左下角为原点,即可完成正值化
            {
                float left = float.MaxValue;
                float right = float.MinValue;
                float top = float.MinValue;
                float bottom = float.MaxValue;
                for (int i = 0; i < bounds.Length; i++)
                {
                    Vector4 bound = bounds[i];
                    if (left > bound.x)
                    {
                        left = bound.x;
                    }
                    if (right < bound.y)
                    {
                        right = bound.y;
                    }
                    if (top < bound.z)
                    {
                        top = bound.z;
                    }
                    if (bottom > bound.w)
                    {
                        bottom = bound.w;
                    }
                }
                float width = right - left + 1;
                float height = top - bottom + 1;
    #if UNITY_EDITOR
                Debug.LogWarningFormat("text texture left = {0} right = {1} top = {2} bottom = {3} width = {4} height = {5}", left, right, top, bottom, width, height);
    #endif
                StartCoroutine(delayDrawImage());
            }
        }
    
        Vector4[] bounds;
        private List<Image> _lines = new List<Image>();
        void CreateBg()
        {
            for (int i = 0; i < transform.childCount; i++)
            {
                GameObject.DestroyImmediate(transform.GetChild(i).gameObject);
                Debug.LogWarning("DESOTRY: " + i);
            }
    
            Vector4[] list = bounds;
            _lines.Clear();
    
            Debug.LogWarning("CreateUnderLines==========================list.length:" + list.Length);
            for (int i = 0; i < list.Length; i++)
            {
                //初始化
                GameObject obj = new GameObject();
                obj.transform.SetParent(transform, false);
                obj.name = "underline" + i;
                _lines.Add(obj.AddComponent<Image>());
                _lines[i].rectTransform.pivot = new Vector2(0, 1);
                _lines[i].rectTransform.anchorMin = new Vector2(0, 1);
                _lines[i].rectTransform.anchorMax = new Vector2(0, 1);
    
                //颜色和大小
                float fWidth = Mathf.Abs((list[i].y - list[i].x));
                float fHeight = Mathf.Abs((list[i].w - list[i].z));
                var tex = new Texture2D((int)fWidth, (int)fHeight, TextureFormat.ARGB32, false);
                Color[] colors = tex.GetPixels();
                for (int j = 0; j < colors.Length; j++)
                    colors[j] = new Color(1, 0, 0, 0.2f);
                tex.SetPixels(colors);
                tex.Apply();
                _lines[i].sprite = Sprite.Create(tex, new Rect(0, 0, tex.width, tex.height), Vector2.zero);
                _lines[i].SetNativeSize();
                _lines[i].rectTransform.sizeDelta = new Vector2(fWidth, fHeight);
                _lines[i].rectTransform.anchorMin = new Vector2(0.5f, 0.5f);
                _lines[i].rectTransform.anchorMax = new Vector2(0.5f, 0.5f);
    
                //坐标
                float x =  list[i].x;
                _lines[i].rectTransform.anchoredPosition = new Vector2(x, list[i].z);
            }
        }
    
        IEnumerator delayDrawImage()
        {
            yield return null;
            CreateBg();
        }
    }
    

    备注

    Image的删除会报错,有空再优化了

  • 相关阅读:
    基于Redis的短链接设计思路
    再谈对协变和逆变的理解(Updated)
    Java基础—ClassLoader的理解
    遇到个小问题,Java泛型真的是鸡肋吗?
    一次失败升级后的反思
    JVM是如何分配和回收内存?有实例!
    一个Java对象到底占用多大内存?
    《深入理解Java虚拟机》读书笔记:垃圾收集器与内存分配策略
    快速掌握RabbitMQ(二)——四种Exchange介绍及代码演示
    快速掌握RabbitMQ(一)——RabbitMQ的基本概念、安装和C#驱动
  • 原文地址:https://www.cnblogs.com/CodeKnight/p/15689276.html
Copyright © 2011-2022 走看看