前言
unity打包资源压缩,其中字体就占用很大空间,包含全中文汉字的字体尤其大,所以需要精简,可以自己制作常用汉字的字体,但是也很大,下面介绍一个可以扫描项目中配置表文本,代码中所有文本,预制体上所有文本,并将其塞进预先建立的字体静态库中。
话不多说,直接上代码
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Text;
using TMPro;
using UnityEditor;
using UnityEngine;
public class FontScan : Editor
{
[MenuItem("MyTools/FontScan")]
public static void ScanWord()
{
ScaneCSharpScript();
StringBuilder sbr = new StringBuilder();
sbr.Append(ScaneCSharpScript());
sbr.Append(ScanPrefabText());
sbr.Append(ScanJsonCfg());
sbr.Append(GetCommonString());
var characters = DeRepeat(sbr.ToString());
// 设置静态字体
var imp = AssetImporter.GetAtPath("Assets/AddRes/Fonts/TestFont.ttf") as TrueTypeFontImporter;
imp.customCharacters = characters;
AssetDatabase.ImportAsset("Assets/AddRes/Fonts/TestFont.ttf");
Debug.Log(characters);
string path = Path.Combine(Application.dataPath, "../", "Tools", "FontSubsetPack", "字符.txt");
using var writer = new StreamWriter(path, false, Encoding.UTF8);
writer.Write(characters);
Debug.LogError("扫描完成");
}
// 字符去重
public static string DeRepeat(string str)
{
var sbr = new StringBuilder();
var charDic = new Dictionary<char, object>();
for (int i = 0, len = str.Length; i < len; ++i)
{
if (!charDic.ContainsKey(str[i]))
{
charDic.Add(str[i], null);
sbr.Append(str[i]);
}
}
Debug.Log("总字数: " + charDic.Count);
return sbr.ToString();
}
// 通用标点符号、数字、字母等
static string GetCommonString()
{
return @"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
}
// 配置文本扫描
static string ScanJsonCfg()
{
var sbr = new StringBuilder();
string[] fs = Directory.GetFiles(Application.dataPath + "/AddRes/ConfigTables", "*.json", SearchOption.AllDirectories);
for (int i = 0, flen = fs.Length; i < flen; ++i)
{
var f = fs[i];
EditorUtility.DisplayProgressBar("扫描中", f, (float)i / flen);
var path = f.Replace(Application.dataPath, "Assets");
var cfg_text = AssetDatabase.LoadAssetAtPath<TextAsset>(path).text;
// TODO 可自行做正则表达式匹配
// ...
sbr.AppendLine(cfg_text);
}
EditorUtility.ClearProgressBar();
return sbr.ToString();
}
// cs文件扫描
static string ScaneCSharpScript()
{
var sbr = new StringBuilder();
var fs = Directory.GetFiles(Application.dataPath + "/Scripts", "*.cs", SearchOption.AllDirectories);
for (int i = 0, flen = fs.Length; i < flen; i++)
{
var f = fs[i];
EditorUtility.DisplayProgressBar("扫描中", f, (float)i / flen);
using (var reader = new StreamReader(f))
{
var line = reader.ReadLine();
while (line != null)
{
sbr.Append(line);
line = reader.ReadLine();
}
}
}
EditorUtility.ClearProgressBar();
return sbr.ToString();
}
// 预设文本扫描
static string ScanPrefabText()
{
var sbr = new StringBuilder();
string[] fs = Directory.GetFiles(Application.dataPath + "/Resources/", "*.prefab", SearchOption.AllDirectories);
for (int i = 0, flen = fs.Length; i < flen; ++i)
{
var f = fs[i];
EditorUtility.DisplayProgressBar("扫描中", f, (float)i / flen);
var path = f.Replace(Application.dataPath, "Assets");
var go = AssetDatabase.LoadAssetAtPath<GameObject>(path);
var texts = go.GetComponentsInChildren<UnityEngine.UI.Text>(true);
for (int j = 0, len = texts.Length; j < len; ++j)
{
sbr.Append(texts[j].text);
}
// 通过反射获取所有脚本的public string的成员----------------------------------------
var triggers = go.GetComponentsInChildren<MonoBehaviour>(true);
for (int j = 0, len = triggers.Length; j < len; ++j)
{
var fields = triggers[j].GetType().GetFields(BindingFlags.Public | BindingFlags.Instance);
foreach (var field in fields)
{
if (field.FieldType == typeof(string))
{
var txt = (string)field.GetValue(triggers[j]);
sbr.Append(txt);
}
}
}
}
EditorUtility.ClearProgressBar();
return sbr.ToString();
}
}
上面就是代码的实现,直接将代码放到项目的Editor文件夹下,就可以在unity的编辑器扩展目录栏看到对应的工具目录了。
使用方法:将脚本中的各个文本路径改成自己项目中各个文本对应的路径,然后自己新建一个字体文件将路径填到代码中对应的生成路径中就好了。
看到这里了,点个赞再走吧~