1评论

UGUI Text组件扩展

文章来自https://blog.csdn.net/yu1368072332/article/details/84855449 2019-02-21 220浏览

想免费获取内部独家PPT资料库?观看行业大牛直播?点击加入腾讯游戏学院游戏开发行业精英群711501594

在项目开发中,和ui界面打交道是必不可少的,但是最近发现ugui提供的text组件,在很多情况下不能满足美术的需求,这就对text组件进行扩展编辑,使其尽可能满足项目的需求,这里主要实现字间距、字体颜色、字体阴影、字体描边、字体根据需求自动选择字体和颜色字号等功能。

一、关于字间距的实现:
 public void PopulateMesh(VertexHelper toFill)
    {
        if (UseTextSpacing)
        {
            if (toFill.currentVertCount == 0)
            {
                return;
            }
            List<UIVertex> vertexs = new List<UIVertex>();
            toFill.GetUIVertexStream(vertexs);
            int indexCount = toFill.currentIndexCount;
            UIVertex vt;
            for (int i = 6; i < indexCount; i++)
            {
                //第一个字不用改变位置
                vt = vertexs[i];
                vt.position += new Vector3(m_TextSpacing * (i / 6), 0, 0);
                vertexs[i] = vt;
                //以下注意点与索引的对应关系
                if (i % 6 <= 2)
                {
                    toFill.SetUIVertex(vt, (i / 6) * 4 + i % 6);
                }
                if (i % 6 == 4)
                {
                    toFill.SetUIVertex(vt, (i / 6) * 4 + i % 6 - 1);
                }
            }
        }
    }

二、关于字体颜色的调整:
 public void PopulateMesh(VertexHelper toFill, RectTransform rectTransform, Color color)
    {
        if (UseVertexColor)
        {
            Vector2 min = rectTransform.pivot;
            min.Scale(-rectTransform.rect.size);
            Vector2 max = rectTransform.rect.size + min;
            int len = toFill.currentVertCount;
            for (int i = 0; i < len; i++)
            {
                UIVertex v = new UIVertex();
                toFill.PopulateUIVertex(ref v, i);
                v.color = RemapColor(min, max, color, v.position);
                toFill.SetUIVertex(v, i);
            }
        }
    }
    private Color RemapColor(Vector2 min, Vector2 max, Color color, Vector2 pos)
    {
        float x01 = max.x == min.x ? 0f : Mathf.Clamp01((pos.x - min.x) / (max.x - min.x));
        float y01 = max.y == min.y ? 0f : Mathf.Clamp01((pos.y - min.y) / (max.y - min.y));
        x01 -= VertexColorOffset.x * (VertexColorOffset.x > 0f ? x01 : (1f - x01));
        y01 -= VertexColorOffset.y * (VertexColorOffset.y > 0f ? y01 : (1f - y01));
        Color newColor = Color.Lerp(
            Color.Lerp(VertexBottomLeft, VertexBottomRight, x01),
            Color.Lerp(VertexTopLeft, VertexTopRight, x01),
            y01
        );
        switch (VertexColorFilter)
        {
            default:     
            case ColorFilterType.Additive:
                return color + newColor;        
            case ColorFilterType.OverLap:
                float a = Mathf.Max(newColor.a, color.a);
                newColor = Color.Lerp(color, newColor, newColor.a);
                newColor.a = a;
                return newColor;
        }
    }

实现效果:

三、实现字体阴影:
 public Vector2 effectDistance
    {
        get { return m_EffectDistance; }
        set
        {
            if (value.x > kMaxEffectDistance)
                value.x = kMaxEffectDistance;
            if (value.x < -kMaxEffectDistance)
                value.x = -kMaxEffectDistance;
            if (value.y > kMaxEffectDistance)
                value.y = kMaxEffectDistance;
            if (value.y < -kMaxEffectDistance)
                value.y = -kMaxEffectDistance;
            if (m_EffectDistance == value)
                return;
            m_EffectDistance = value;
        }
    }
    protected void ApplyShadow(List<UIVertex> verts, Vector2 min, Vector2 max, Color32 color, float x, float y)
    {
        UIVertex vt;
        int start = 0, end = verts.Count;
        var neededCapacity = verts.Count + end - start;
        if (verts.Capacity < neededCapacity)
            verts.Capacity = neededCapacity;
        for (int i = start; i < end; ++i)
        {
            vt = verts[i];
            verts.Add(vt);
            Vector3 v = vt.position;
            v.x += x;
            v.y += y;
            vt.position = v;
            vt.color = RemapColor(min, max, color, v);
            verts[i] = vt;
        }
    }
    private Color RemapColor(Vector2 min, Vector2 max, Color color, Vector2 pos)
    {
        float x01 = max.x == min.x ? 0f : Mathf.Clamp01((pos.x - min.x) / (max.x - min.x));
        float y01 = max.y == min.y ? 0f : Mathf.Clamp01((pos.y - min.y) / (max.y - min.y));
        x01 -= m_VertexColorOffset.x * (m_VertexColorOffset.x > 0f ? x01 : (1f - x01));
        y01 -= m_VertexColorOffset.y * (m_VertexColorOffset.y > 0f ? y01 : (1f - y01));
        Color newColor = Color.Lerp(
            Color.Lerp(VertexBottomLeft, VertexBottomRight, x01),
            Color.Lerp(VertexTopLeft, VertexTopRight, x01),
            y01
        );
        //使用全新颜色 不继承原有的
        return newColor;
        //return color * newColor;
    }
    public void PopulateMesh(VertexHelper vh, RectTransform rectTransform, Color color)
    {
        if (UseShadow)
        {
            Vector2 min = rectTransform.pivot;
            min.Scale(-rectTransform.rect.size);
            Vector2 max = rectTransform.rect.size + min;
            List<UIVertex> output = new List<UIVertex>();
            vh.GetUIVertexStream(output);
            ApplyShadow(output, min, max, color, effectDistance.x, effectDistance.y);
            vh.Clear();
            vh.AddUIVertexTriangleStream(output);
        }
    }

四、字体描边的实现
public Vector2 EffectDistance
    {
        get { return m_EffectDistance; }
        set
        {
            if (value.x > kMaxEffectDistance)
                value.x = kMaxEffectDistance;
            if (value.x < -kMaxEffectDistance)
                value.x = -kMaxEffectDistance;
            if (value.y > kMaxEffectDistance)
                value.y = kMaxEffectDistance;
            if (value.y < -kMaxEffectDistance)
                value.y = -kMaxEffectDistance;
            if (m_EffectDistance == value)
                return;
            m_EffectDistance = value;
        }
    }
    protected void ApplyShadowZeroAlloc(List<UIVertex> verts, Color32 color, int start, int end, float x, float y)
    {
        UIVertex vt;
        var neededCapacity = verts.Count + end - start;
        if (verts.Capacity < neededCapacity)
            verts.Capacity = neededCapacity;
        for (int i = start; i < end; ++i)
        {
            vt = verts[i];
            verts.Add(vt);
            Vector3 v = vt.position;
            v.x += x;
            v.y += y;
            vt.position = v;
            var newColor = color;
            newColor.a = (byte)((newColor.a * verts[i].color.a) / 255);
            vt.color = newColor;
            verts[i] = vt;
        }
    }
    public void PopulateMesh(VertexHelper vh)
    {
        if (UseOutline)
        {
            List<UIVertex> verts = new List<UIVertex>();
            vh.GetUIVertexStream(verts);
            var neededCpacity = verts.Count * 5;
            if (verts.Capacity < neededCpacity)
                verts.Capacity = neededCpacity;
            var start = 0;
            var end = verts.Count;
            ApplyShadowZeroAlloc(verts, EffectColor, start, verts.Count, EffectDistance.x, EffectDistance.y);
            start = end;
            end = verts.Count;
            ApplyShadowZeroAlloc(verts, EffectColor, start, verts.Count, EffectDistance.x, -EffectDistance.y);
            start = end;
            end = verts.Count;
            ApplyShadowZeroAlloc(verts, EffectColor, start, verts.Count, -EffectDistance.x, EffectDistance.y);
            start = end;
            end = verts.Count;
            ApplyShadowZeroAlloc(verts, EffectColor, start, verts.Count, -EffectDistance.x, -EffectDistance.y);
            vh.Clear();
            vh.AddUIVertexTriangleStream(verts);
        }
    }

五、本地默认颜色和字体的修改,主要实现直接调整为指定文字格式和颜色的功能,例如游戏中有tip、标题、二级弹框等字体,可以直接设置为指定的格式
  public void UpdateText(Text target)
    {
        txt_Target = target;
        if (m_UseLocalization == false)
            return;
        m_TextStyle = (TextStyle)(int)m_TextStyleCN;
        //通过类型选择字体和颜色
        var color_ = Color.black;
        TextStyleFont fontStyle = new TextStyleFont()
        {
            font = Resources.Load<Font>(""),
            fontSize = 20
        };
        switch (m_TextStyle)
        {
            case TextStyle.SystemTitle:
                color_ = Color.blue;
                txt_Target.font = Resources.Load<Font>("Font/FZZDHJW");
                txt_Target.fontSize = 35;
                break;
            case TextStyle.SecondTipTitle:
                color_ = Color.yellow;
                txt_Target.font = Resources.Load<Font>("Font/FZZDHJW");
                txt_Target.fontSize = 25;
                break;
            case TextStyle.SmallTipTitle:
                color_ = Color.yellow;
                txt_Target.font = Resources.Load<Font>("Font/MSYHTTF");
                txt_Target.fontSize = 25;
                break;
        }
        txt_Target.color = color_;
    }

六、将上述功能添加到text组件中:

这里会定义上述的五个处理器,然后继承OnPopulateMesh,实现上面的功能:
   protected override void OnPopulateMesh(VertexHelper toFill)
    {
        base.OnPopulateMesh(toFill);
        m_FontSpacingHandler.PopulateMesh(toFill);
        m_VertexColorHandler.PopulateMesh(toFill, rectTransform, color);
        m_TextShadowHandler.PopulateMesh(toFill, rectTransform, color);
        m_TextOutlineHandler.PopulateMesh(toFill);        
    }

重新绘制text组件下的信息:
 [MenuItem("GameObject/UI/UGUI Plus/Text Plus")]
    public static void CreateTextPlus()
    {
        GameObject root = new GameObject("Text", typeof(RectTransform), typeof(TextPlus));
        ResetInCanvasFor((RectTransform)root.transform);
        root.GetComponent<TextPlus>().text = "Text Plus";
        var text = root.GetComponent<TextPlus>();
        text.text = "Text Plus";
        text.color = Color.black;
        text.alignment = TextAnchor.MiddleCenter;
        root.transform.localPosition = Vector3.zero;
    }
    public static void TextSpacingGUI(SerializedProperty m_UseTextSpacing, SerializedProperty m_TextSpacing, ref bool m_TextSpacingPanelOpen)
    {
        LayoutF(() =>
        {            
            EditorGUILayout.PropertyField(m_UseTextSpacing);
            if (m_UseTextSpacing.boolValue)
            {
                Space();
                LayoutH(() => {
                    EditorGUI.PropertyField(GUIRect(0, 18), m_TextSpacing, new GUIContent());
                });
            }
        }, "Text Spacing", ref m_TextSpacingPanelOpen, true);
    }
    public static void VertexColorGUI(SerializedProperty m_UseVertexColor, SerializedProperty m_VertexTopLeft, SerializedProperty m_VertexTopRight, SerializedProperty m_VertexBottomLeft, SerializedProperty m_VertexBottomRight, SerializedProperty m_VertexColorFilter, SerializedProperty m_VertexColorOffset, ref bool m_VertexColorPanelOpen)
    {
        LayoutF(() => {
            EditorGUILayout.PropertyField(m_UseVertexColor);
            if (m_UseVertexColor.boolValue)
            {
                Space();
                LayoutH(() => {
                    EditorGUI.PropertyField(GUIRect(0, 18), m_VertexTopLeft, new GUIContent());
                    Space();
                    EditorGUI.PropertyField(GUIRect(0, 18), m_VertexTopRight, new GUIContent());
                });
                Space();
                LayoutH(() => {
                    EditorGUI.PropertyField(GUIRect(0, 18), m_VertexBottomLeft, new GUIContent());
                    Space();
                    EditorGUI.PropertyField(GUIRect(0, 18), m_VertexBottomRight, new GUIContent());
                });
                Space();
                m_VertexColorFilter.enumValueIndex = (int)(VertexColorHandler.ColorFilterType)EditorGUILayout.EnumPopup(
                    new GUIContent("Filter"), (VertexColorHandler.ColorFilterType)m_VertexColorFilter.enumValueIndex
                );
                Vector2 newOffset = EditorGUILayout.Vector2Field("Offset", m_VertexColorOffset.vector2Value);
                newOffset.x = Mathf.Clamp(newOffset.x, -1f, 1f);
                newOffset.y = Mathf.Clamp(newOffset.y, -1f, 1f);
                m_VertexColorOffset.vector2Value = newOffset;
                Space();
            }
        }, "Vertex Color", ref m_VertexColorPanelOpen, true);
    }
    public static void TextShadowGUI(SerializedProperty m_UseShadow, SerializedProperty m_ShadowColorTopLeft, SerializedProperty m_ShadowColorTopRight,
           SerializedProperty m_ShadowColorBottomLeft, SerializedProperty m_ShadowColorBottomRight, SerializedProperty m_ShadowEffectDistance, ref bool m_TextShadowPanelOpen)
    {
        LayoutF(() =>
        {
            EditorGUILayout.PropertyField(m_UseShadow);
            if (m_UseShadow.boolValue)
            {
                Space();
                LayoutH(() => {
                    EditorGUI.PropertyField(GUIRect(0, 18), m_ShadowColorTopLeft, new GUIContent());
                    Space();
                    EditorGUI.PropertyField(GUIRect(0, 18), m_ShadowColorTopRight, new GUIContent());
                });
                Space();
                LayoutH(() => {
                    EditorGUI.PropertyField(GUIRect(0, 18), m_ShadowColorBottomLeft, new GUIContent());
                    Space();
                    EditorGUI.PropertyField(GUIRect(0, 18), m_ShadowColorBottomRight, new GUIContent());
                });
                Space();
                EditorGUILayout.PropertyField(m_ShadowEffectDistance);
            }
        }, "Shadow", ref m_TextShadowPanelOpen, true);
    }
    public static void SimpleUseGUI(string title, ref bool m_PanelOpen, float space, SerializedProperty useThis, params SerializedProperty[] sps)
    {
        LayoutF(() => {
            EditorGUILayout.PropertyField(useThis);
            if (useThis.boolValue)
            {
                foreach (var s in sps)
                {
                    if (s != null)
                    {
                        EditorGUILayout.PropertyField(s);
                    }
                }
            }
        }, title, ref m_PanelOpen, true);
    }
    private static void ResetInCanvasFor(RectTransform root)
    {
        root.SetParent(Selection.activeTransform);
        if (!InCanvas(root))
        {
            Transform canvasTF = GetCreateCanvas();
            root.SetParent(canvasTF);
        }
        if (!Transform.FindObjectOfType<UnityEngine.EventSystems.EventSystem>())
        {
            GameObject eg = new GameObject("EventSystem");
            eg.AddComponent<UnityEngine.EventSystems.EventSystem>();
            eg.AddComponent<UnityEngine.EventSystems.StandaloneInputModule>();
        }
        root.localScale = Vector3.one;
        root.localPosition = new Vector3(root.localPosition.x, root.localPosition.y, 0f);
        Selection.activeGameObject = root.gameObject;
    }
    private static bool InCanvas(Transform tf)
    {
        while (tf.parent)
        {
            tf = tf.parent;
            if (tf.GetComponent<Canvas>())
            {
                return true;
            }
        }
        return false;
    }
    private static Transform GetCreateCanvas()
    {
        Canvas c = Object.FindObjectOfType<Canvas>();
        if (c)
        {
            return c.transform;
        }
        else
        {
            GameObject g = new GameObject("Canvas");
            c = g.AddComponent<Canvas>();
            c.renderMode = RenderMode.ScreenSpaceOverlay;
            g.AddComponent<CanvasScaler>();
            g.AddComponent<GraphicRaycaster>();
            return g.transform;
        }
    }
    private static void LayoutF(System.Action action, string label, ref bool open, bool box = false)
    {
        bool _open = open;
        LayoutV(() => {
            _open = GUILayout.Toggle(
                _open,
                label,
                GUI.skin.GetStyle("foldout"),
                GUILayout.ExpandWidth(true),
                GUILayout.Height(18)
            );
            if (_open)
            {
                action();
            }
        }, box);
        open = _open;
    }
    private static Rect GUIRect(float width, float height)
    {
        return GUILayoutUtility.GetRect(width, height, GUILayout.ExpandWidth(width <= 0), GUILayout.ExpandHeight(height <= 0));
    }
    private static void Space(float space = 4f)
    {
        GUILayout.Space(space);
    }
    private static void LayoutH(System.Action action, bool box = false)
    {
        if (box)
        {
            GUIStyle style = new GUIStyle(GUI.skin.box);
            GUILayout.BeginHorizontal(style);
        }
        else
        {
            GUILayout.BeginHorizontal();
        }
        action();
        GUILayout.EndHorizontal();
    }
    private static void LayoutV(System.Action action, bool box = false)
    {
        if (box)
        {
            GUIStyle style = new GUIStyle(GUI.skin.box)
            {
                padding = new RectOffset(6, 6, 2, 2)
            };
            GUILayout.BeginVertical(style);
        }
        else
        {
            GUILayout.BeginVertical();
        }
        action();
        GUILayout.EndVertical();
    }


工程链接: 链接:https://pan.baidu.com/s/1xsA4-DlYh0jFCgrdj3UqKw  提取码:xj3y