[Unity]聊天使用TextMeshPro

        项目已经在大厂正式上线半个月了,忙碌了大半年的时间啊。时间实在是太赶了,上线的那几天,一堆问题,通宵达旦的修复问题,几乎没这么睡过,想想都心累呀!

*************************************************分割线***********************************************************

        之前有说过,聊天界面是之前留下来的锅,卡顿问题已经解决,图片长度也可以处理。但在大厂的一个月测试的时候发现,聊天有很多问题,很严重:乱码问题,表情偏移等问题。发现这应该是占位符问题导致,而且是偶现,切换后台啥的又突然好了,应该是底层渲染的时候计算有问题导致。不清楚是不是LinkImageText这个脚本被修改太多导致的。

        为了快速解决这些问题,就用之前使用过的TextMeshPro,看了下替换情况,发现从LinkImageText替换为TextMeshPro,需要的时间不是很多,1个下午就替换完毕,之前聊天是一个Text,所以替换很快。但是为了性能考虑,再次优化,使用了另一个插件SuperScrollView。

        SuperScrollView需要根据UI的高度值和宽度值来计算的,但是TextMeshPro有个bug就是不会修改RectTransform的值,只好每次修改文本内容的时候,强制调用ForceMeshUpdate()来获取渲染的高度值和宽度值。顺带修改下SuperScrollView的获取高度值和宽度值的接口,将RectTransform.rect.height和RectTransform.rect.width修改成如下接口:

        private TMP_Text m_tmpText;
        private bool m_bIsFind = false;
        private bool GetBIsTMPText()
        {
            bool bIsTmpText = false;
            if (!m_bIsFind)
            {
                m_tmpText = gameObject.GetComponent<TMP_Text>(); 
                 m_bIsFind = true;
            }
            bIsTmpText = m_tmpText != null;

            return bIsTmpText;
        }

        public float GetHeight()
        {
            float height = 0.0f;
            bool bIsTmpText = GetBIsTMPText();
            if (bIsTmpText)
            {
                height = m_tmpText.renderedHeight;
                if (CachedRectTransform.rect.height != m_tmpText.renderedHeight)
                    CachedRectTransform.sizeDelta = new Vector2(CachedRectTransform.sizeDelta.x, m_tmpText.renderedHeight);
            }       
            else
                height = CachedRectTransform.rect.height;

            return height;
        }

        public float GetWidth()
        {
            float width = 0.0f;
            bool bIsTmpText = GetBIsTMPText();
            if (bIsTmpText)
            {
                width = m_tmpText.renderedWidth;
                if (CachedRectTransform.rect.width != m_tmpText.renderedWidth)
                    CachedRectTransform.sizeDelta = new Vector2(m_tmpText.renderedWidth, CachedRectTransform.sizeDelta.y);
            }
               
            else
                width = CachedRectTransform.rect.width;

            return width;
        }

        结合SuperScrollView和TextMeshPro插件修改聊天功能,解决了LinkImageText的遗留问题,而且在性能上有很大的提升。但是又发现个问题,为啥没有一个插件是直接拿来就能用的呀。

        问题其实不是很严重,但是策划一直很在意,那只好花点时间看源码,真TM长,4000多行代码,相当于现在我给接大厂SDK写的代码长度。

        问题如下:

        只要汉字后面接着一串数字或者阿拉丁字母等,都会导致莫名其妙的换行。修改倒是很简单,在TMPro_UGUI_Private.cs脚本中注释2行代码就OK:

        修改后就解决了,效果如下:

        其实比较坑的是Unity论坛上有人反映过这个问题,到现在都没修复这个Bug,也没有比较好的解决方案,还得自己来踩坑,真心累。

        使用TextMeshPro,还有个问题就是字体丢失的问题,项目使用的是7000个字的字库。玩家的想法不能确定,所以需要处理这些生僻字的问题,TextMeshPro源码中是用用空格来代替生僻字的,而且还会大量输出log日志。这个相对来说就比较简单了:

                    // 注释掉,避免更多的消耗
                    //if (glyph == null)
                    //{
                    //    // Search for the missing glyph in the TMP Settings Default Font Asset.
                    //    if (TMP_Settings.defaultFontAsset != null)
                    //        tempFontAsset = TMP_FontUtilities.SearchForGlyph(TMP_Settings.defaultFontAsset, c, out glyph);
                    //}

                    if (glyph == null)
                    {
                        // Use Space (32) Glyph from the currently assigned font asset.
                        c = chars[i] = 42;//32表示空格 42表示*
                        tempFontAsset = TMP_FontUtilities.SearchForGlyph(m_currentFontAsset, c, out glyph);
                        //if (!TMP_Settings.warningsDisabled) Debug.LogWarning("Character with ASCII value of " + srcGlyph + " was not found in the Font Asset Glyph Table. It was replaced by a space.", this);
                    }

        还有就是策划表里添加的生僻字,这些生僻字是一定要能显示的,为了解决策划秀他们语文功底的问题,专门写了工具来遍历策划表来查找新的生僻字,然后添加到字库中去。策划转的表是lua格式的,不需要操作Excel太多,只需要IO读取lua中的内容就OK。代码很简单,就不做任何解释:

using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using UnityEditor;
using UnityEngine;

public class FindRareCharacterTool
{
    private static List<string> m_existText = new List<string>() { "TextMesh Pro/CustomFont1.txt", "TextMesh Pro/CustomFont2.txt" };
    private static string m_tblRelativePath = "Resources/Lua/Table";
    private static string m_rareCharacterRelativePath = "TextMesh Pro/tempRareWord.txt";
    private static List<string> m_tblList;
    private static List<char> m_existCharList;
    private static List<char> m_rareWordCharList;

    [MenuItem("Tools/查找生僻字(策划表)")]
    public static void FindRareCharacterBtn()
    {
        FindRareCharacter();
    }

    public static void FindRareCharacter()
    {
        if (m_tblList == null)
            m_tblList = new List<string>();
        else
            m_tblList.Clear();

        string tblAbsoluteRelativePath = Application.dataPath + "/" + m_tblRelativePath;
        FindTbls(tblAbsoluteRelativePath);

        if (m_tblList == null || m_tblList.Count <= 0) return;

        GetExistChar();

        GenerateRareWordTxt();
    }

    // 获取策划配置的表的路径
    private static void FindTbls(string path)
    {
        if (!Directory.Exists(path))
            return;

        DirectoryInfo dirInfo = new DirectoryInfo(path);
        var files = dirInfo.GetFileSystemInfos();
        for (int i = 0; i < files.Length; ++i)
        {
            var fileName = files[i].Name;
            if (fileName.Contains(".") && !fileName.Contains(".meta"))//文件
            {
                var fileFullName = files[i].FullName;
                m_tblList.Add(fileFullName);
            }
            else//文件夹
                FindTbls(files[i].FullName);
        }
    }

    // 获取已经添加的字库
    private static void GetExistChar()
    {
        if (m_existCharList == null)
            m_existCharList = new List<char>();
        else
            m_existCharList.Clear();

        for (int i = 0; i < m_existText.Count; ++i)
        {
            string tempExistText = Application.dataPath + "/" + m_existText[i];
            try
            {
                StreamReader reader = new StreamReader(tempExistText);
                var content = reader.ReadToEnd().Trim();
                reader.Close();

                var tempList = new List<char>(content.ToCharArray());
                m_existCharList.AddRange(tempList);
            }
            catch (Exception e)
            {
                Debug.Log("GetExistChar - Failed: " + e.Message);
            }
        }
       
    }

    // 获取未添加的字库
    private static void GenerateRareWordTxt()
    {
        string rareCharacterAbsolutePath = Application.dataPath + "/" + m_rareCharacterRelativePath;
        if (File.Exists(rareCharacterAbsolutePath))
            File.Delete(rareCharacterAbsolutePath);

        FileStream fs = File.Create(rareCharacterAbsolutePath);
        if (fs != null)
            fs.Close();

        if (m_rareWordCharList == null)
            m_rareWordCharList = new List<char>();
        else
            m_rareWordCharList.Clear();

        string title = "正在生成生僻字";
        int size = m_tblList.Count;
        bool bIsCancel = false;
        for (int i = 0; i < size; ++i)
        {
            string filePath = m_tblList[i];
            try
            {
                StreamReader reader = new StreamReader(filePath);
                var content = reader.ReadToEnd().Trim();
                reader.Close();

                content = content.Replace("\t", "");
                content = content.Replace("\n", "");
                content = content.Replace(" ", "");

                for (int j = 0; j < m_existCharList.Count; ++j)
                    content = content.Replace(m_existCharList[j].ToString(), "");

                for (int j = 0; j < m_rareWordCharList.Count; ++j)
                    content = content.Replace(m_rareWordCharList[j].ToString(), "");

                // 去重复
                var tempList = new List<char>(content.ToCharArray());
                var newTempList = new List<char>();
                for(int j = 0; j < tempList.Count; ++j)
                {
                    if (!newTempList.Contains(tempList[j]))
                        newTempList.Add(tempList[j]);
                }

                m_rareWordCharList.AddRange(newTempList);
   
                if(newTempList.Count > 0)
                    Debug.LogWarning(new string(newTempList.ToArray()) + "|" + "表: " + filePath);
            }
            catch(Exception e)
            {
                Debug.LogError("GenerateRareWordTxt - Failed: fileName: " + filePath + "\nerror: " + e.Message);
            }

            string info = "对比" + filePath;
            float progress = i / (float)m_tblList.Count;
            if (EditorUtility.DisplayCancelableProgressBar(title, info, progress))
            {
                bIsCancel = true;
                break;
            } 
        }

        if(!bIsCancel)
        {
            string result = new string(m_rareWordCharList.ToArray());
            Debug.LogError("result: " + result);
            StreamWriter writer = new StreamWriter(rareCharacterAbsolutePath);
            writer.Write(result);
            writer.Flush();
            writer.Close();
        }

        EditorUtility.ClearProgressBar();
    }
}

 

  • 5
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 8
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值