项目已经在大厂正式上线半个月了,忙碌了大半年的时间啊。时间实在是太赶了,上线的那几天,一堆问题,通宵达旦的修复问题,几乎没这么睡过,想想都心累呀!
*************************************************分割线***********************************************************
之前有说过,聊天界面是之前留下来的锅,卡顿问题已经解决,图片长度也可以处理。但在大厂的一个月测试的时候发现,聊天有很多问题,很严重:乱码问题,表情偏移等问题。发现这应该是占位符问题导致,而且是偶现,切换后台啥的又突然好了,应该是底层渲染的时候计算有问题导致。不清楚是不是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();
}
}