unity优化Unity技术分享Unity基础入门分享

[Unity] UGUI拓展 - 动画控制富文本异色部分的Alp

2017-09-26  本文已影响432人  _Walker__

1、问题背景

  今天接到一个表现上的需求:在有淡出动画的奖励提示上,异色标记稀有道具的名称
  本来是一个挺简单的功能,在提示文字中找出道具名的位置,然后在两端插入UGUI的<color>标签。测试的时候却发现,淡出过程中异色部分的透明度没有发生变化。

Alpha不变的情况

  在项目组询问一番,有大佬已经写脚本处理了这个问题。怀着不断造轮子的心态,对同事的脚本进行了改写(当然改写的脚本没有放入项目),改写的目的有两个:

改进后的效果

2、浅析

  简单分析(cai)下问题的原因。
  首先,UGUI改变color属性,是修改顶点色,而不是修改材质的属性。因此可以出现同一段文字,颜色(包含Alpha)不同的情况。
  然后,文字异色是通过<color>标签进行标记的,它使用的是一个8位十六进制数表示,顺序分别是RGBA。第一张图中虽然我用的是6位的#00ff00,但Unity内部应该会把它补成8位的#00ff00ff。(具体实现没细究,大概是取不到Alpha位就默认不透明吧)
  那么问题就能猜到了,淡出动画仅仅是修改了color属性,文本中的<color>标签没有任何变化,Unity依旧使用标签的信息去填充顶点色。解决方案也是针对<color>标签进行处理的。

3、完整代码

[ExecuteInEditMode]
public class RichTextAlphaUpdater : MonoBehaviour
{
    public Text Txt;

    /// <summary>
    /// 匹配颜色值
    /// </summary>
    public static readonly Regex RichColorReg = new Regex("<color=#([a-f0-9]{8})>", RegexOptions.IgnoreCase);
    public const int ColorMax = 255;
    
    private UnityAction _vertDirtyAction;
    private UnityAction VertDirtyAction
    {
        get
        {
            if (null == _vertDirtyAction)
            {
                _vertDirtyAction = _OnVertDirty;
            }
            return _vertDirtyAction;
        }
    }

    /// <summary>
    /// 文字顶点变化的事件
    /// </summary>
    private void _OnVertDirty()
    {
        string alpha = _GetHexAlpha();
        string txt = Txt.text;
        Match match = RichColorReg.Match(txt);
        Group group = null;
        while (match.Success)
        {
            group = match.Groups[1];
            _ReplaceAlpha(txt, group.Index, alpha);
            match = match.NextMatch();
        }
    }

    /// <summary>
    /// 缓存数据,降低处理频率
    /// </summary>
    private int _prevAlpha = 0;
    private string _hexAlpha = null;

    /// <summary>
    /// 获取当前Alpha的Hex值
    /// </summary>
    private string _GetHexAlpha()
    {
        int alpha = Mathf.Clamp((int) (Txt.color.a * ColorMax), 0, ColorMax);
        if (null != _hexAlpha && alpha == _prevAlpha)
        {
            return _hexAlpha;
        }

        string hexAlpha = Convert.ToString(alpha, 16);
        if (hexAlpha.Length == 1)
        {
            return "0" + hexAlpha;
        }
        return hexAlpha;
    }

    private void _ReplaceAlpha(string txt, int colorIdx, string alpha)
    {
        unsafe
        {
            fixed (char* hexPtr = txt)
            {
                hexPtr[colorIdx + 6] = alpha[0];
                hexPtr[colorIdx + 7] = alpha[1];
            }
        }
    }

    void OnEnable()
    {
        if (null == Txt)
        {
            Txt = GetComponent<Text>();
        }
        if (null != Txt)
        {
            Txt.RegisterDirtyVerticesCallback(VertDirtyAction);
        }
    }

    void OnDisable()
    {
        if(null == Txt) return;
        Txt.UnregisterDirtyVerticesCallback(VertDirtyAction);
    }
}

4、知识点

代码虽然简单,但也有几个小点值得记录备忘。

1)Text重建回调
2)Unity中使用指针

  为了减少字符串操作(减少GC),我尝试使用指针进行字符替换,然后得到了喜人的结果,性能和GC都有所提高~

  这里有个小抉择,本来为了使用的时候方便,想支持6位色值的。写完指针方案后,我放弃了6位色值。因为它无法通过一对一的char替换完成,需要插入内容,那么GC就无法避免了。

3)正则表达式
上一篇下一篇

猜你喜欢

热点阅读