原因
在使用 Unity 开发的游戏中,避免使用 Resources 文件夹,而使用 AssetBundle 打包,但是 TextMesh Pro 组件自带了 Resources 文件夹,此时 AssetBundle 资源如果引用了它,那么就会把 TextMesh Pro 打成 AssetBundle,造成冗余。但是如果仅把 TextMesh Pro 的 Resources 文件夹改名掉,就会造成【TMP_Settings】读取失败,字体完全无法显示。
分析
【TMP_Settings】类是个单例,在初始使用的时候,会去 Resources 文件夹读取资源配置,反射看代码如下:
public static TMP_Settings instance
{
get
{
if ((UnityEngine.Object) TMP_Settings.s_Instance == (UnityEngine.Object) null)
TMP_Settings.s_Instance = UnityEngine.Resources.Load<TMP_Settings>("TMP Settings");
return TMP_Settings.s_Instance;
}
}
也没有接口可以用来赋值TMP_Settings.s_Instance
,所以造成后面读取默认字体等失败。
解决(obsolete)
既然没有接口可以直接赋值,那么就损失点性能使用反射来对其进行赋值,因为只需赋值一次,所以性能可以忽略。将 Resources 文件夹改名成其他名称,然后把TMP_Settings.asset
文件移到 AssetBundle 预制读取目录。最后在游戏资源检测完毕后,调用如下代码:
public class TMPHelper
{
public static void LoadSettings()
{
TMP_Settings settings = ResManager.LoadAsset<TMP_Settings>("Prefab/Configs/TMPPro/TMP_Settings.asset");
var settingsType = settings.GetType();
var settingsInstanceInfo = settingsType.GetField("s_Instance", BindingFlags.Static | BindingFlags.NonPublic);
settingsInstanceInfo.SetValue(null, settings);
}
}
这样子游戏运行起来就会自动赋值TMP_Settings.s_Instance
,但是在编辑器下就无法使用 TextMesh Pro 组件,所以也需要在编辑器下对其进行赋值,添加编辑器类,代码如下:
[InitializeOnLoad]
public class GameLauncher
{
static GameLauncher()
{
LoadSettings();
}
public static void LoadSettings()
{
TMP_Settings settings = ResManagerEditor.LoadAssetEditor<TMP_Settings>("Prefab/Configs/TMPPro/TMP_Settings.asset");
var settingsType = settings.GetType();
var settingsInstanceInfo = settingsType.GetField("s_Instance", BindingFlags.Static | BindingFlags.NonPublic);
settingsInstanceInfo.SetValue(null, settings);
}
}
这样,只要编辑器一打开就会自动调用赋值。
其他问题
更改了 Resources 文件夹,会导致文本解析标签失败,即无法内嵌子字体,无法使用如下语法:
Would you like <font="Impact SDF">a different font?</font> or just <font="NotoSans" material="NotoSans Outline">a different material?
因为内部解析的时候,会去 Resources 文件夹下的 Fonts & Materials 文件夹寻找字体,寻找不到所以就显示失败。综合考虑不使用这种写法。
更新方法
不使用反射方式,直接修改源码:
public static TMP_Settings instance
{
get
{
if (s_Instance == null)
{
//s_Instance = Resources.Load<TMP_Settings>("TMP Settings");
#if UNITY_EDITOR
s_Instance =
UnityEditor.AssetDatabase.LoadAssetAtPath<TMP_Settings>(
"Assets/AB/Prefab/Configs/TMPPro/TMP_Settings.asset");
// Make sure TextMesh Pro UPM packages resources have been added to the user project
if (s_Instance == null && Time.frameCount != 0)
{
// Open TMP Resources Importer
TMP_PackageResourceImporterWindow.ShowPackageImporterWindow();
}
#endif
}
return s_Instance;
}
set { TMP_Settings.s_Instance = value; }
}
增加运行时赋值接口(AssetBundle 加载后赋值),以及在编辑器下的获取方式。