BMFontCreator.cs 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153
  1. using System.Collections.Generic;
  2. using System.IO;
  3. using System.Text.RegularExpressions;
  4. using UnityEditor;
  5. using UnityEngine;
  6. // 创建bmfont
  7. namespace FL.Editor
  8. {
  9. public class BMFontCreator
  10. {
  11. [MenuItem("Assets/Create/XGame/CreateBMFont")]
  12. static void Create()
  13. {
  14. var creator = new BMFontCreator();
  15. creator.Start();
  16. }
  17. private void Start()
  18. {
  19. var obj = Selection.activeObject;
  20. string fntPath = AssetDatabase.GetAssetPath(obj);
  21. if (fntPath.IndexOf(".fnt") == -1)
  22. {
  23. // 不是字体文件
  24. Debug.LogError("请先选择一个*.fnt!");
  25. return;
  26. }
  27. //if (!File.Exists(customFontPath))
  28. //{
  29. // Debug.LogError("The .fontsettings file not exists");
  30. // return;
  31. //}
  32. Debug.Log(fntPath);
  33. using var reader = new StreamReader(new FileStream(fntPath, FileMode.Open));
  34. var charInfos = new List<CharacterInfo>();
  35. var reg = new Regex(@"char id=(?<id>\d+)\s+x=(?<x>\d+)\s+y=(?<y>\d+)\s+width=(?<width>\d+)\s+height=(?<height>\d+)\s+xoffset=(?<xoffset>(-|\d)+)\s+yoffset=(?<yoffset>(-|\d)+)\s+xadvance=(?<xadvance>\d+)\s+");
  36. string line = reader.ReadLine();
  37. int lineHeight = 65;
  38. int texWidth = 512;
  39. int texHeight = 512;
  40. var pngName = "";
  41. while (line != null)
  42. {
  43. if (line.IndexOf("char id=") != -1)
  44. {
  45. var match = reg.Match(line);
  46. if (match.Success)
  47. {
  48. var id = System.Convert.ToInt32(match.Groups["id"].Value);
  49. var x = System.Convert.ToInt32(match.Groups["x"].Value);
  50. var y = System.Convert.ToInt32(match.Groups["y"].Value);
  51. var width = System.Convert.ToInt32(match.Groups["width"].Value);
  52. var height = System.Convert.ToInt32(match.Groups["height"].Value);
  53. var xoffset = System.Convert.ToInt32(match.Groups["xoffset"].Value);
  54. var yoffset = System.Convert.ToInt32(match.Groups["yoffset"].Value);
  55. var xadvance = System.Convert.ToInt32(match.Groups["xadvance"].Value);
  56. Debug.Log($"字符:{(char)id} id:{id} width:{width} height:{height}");
  57. if (height > lineHeight)
  58. lineHeight = height;
  59. var info = new CharacterInfo
  60. {
  61. index = id
  62. };
  63. //uv左下角(0,0)->右上角(1,1)
  64. float uvx = 1f * x / texWidth;
  65. float uvy = 1 - (1f * y / texHeight);
  66. float uvw = 1f * width / texWidth;
  67. float uvh = 1f * height / texHeight;
  68. info.uvBottomLeft = new Vector2(uvx, uvy - uvh);
  69. info.uvBottomRight = new Vector2(uvx + uvw, uvy - uvh);
  70. info.uvTopLeft = new Vector2(uvx, uvy);
  71. info.uvTopRight = new Vector2(uvx + uvw, uvy);
  72. info.minX = xoffset;
  73. //glyphHeight赋值时内部会加上高度,需要提前减掉高度
  74. //文本上对齐时: - height,居中对其时: - height / 2
  75. //下对齐时不用减
  76. info.minY = yoffset - height / 2;
  77. info.glyphWidth = width;
  78. info.glyphHeight = height;
  79. info.advance = xadvance;
  80. //info.size = 18;
  81. //info.style = FontStyle.Italic;
  82. charInfos.Add(info);
  83. }
  84. }
  85. else if (line.IndexOf("scaleW=") != -1)
  86. {
  87. var reg2 = new Regex(@"common lineHeight=(?<lineHeight>\d+)\s+.*scaleW=(?<scaleW>\d+)\s+scaleH=(?<scaleH>\d+)");
  88. var match = reg2.Match(line);
  89. if (match.Success)
  90. {
  91. lineHeight = System.Convert.ToInt32(match.Groups["lineHeight"].Value);
  92. texWidth = System.Convert.ToInt32(match.Groups["scaleW"].Value);
  93. texHeight = System.Convert.ToInt32(match.Groups["scaleH"].Value);
  94. }
  95. }
  96. else if (line.IndexOf("file=") != -1)
  97. {
  98. var match = Regex.Match(line, @"\s+.*file=""(.+?)""");
  99. if (match.Success)
  100. {
  101. pngName = match.Groups[1].Value;
  102. }
  103. }
  104. line = reader.ReadLine();
  105. }
  106. Debug.Log($"字体贴图 Name:{pngName} Width:{texWidth} Height:{texHeight} ");
  107. if (string.IsNullOrEmpty(pngName))
  108. {
  109. Debug.LogError($"字体贴图名字为空, 请检查*.fnt文件.");
  110. return;
  111. }
  112. var texturePath = Path.Combine(Path.GetDirectoryName(fntPath), pngName);
  113. var texture = AssetDatabase.LoadAssetAtPath<Texture>(texturePath);
  114. if (texture == null)
  115. {
  116. Debug.LogError($"找不到字体贴图. Path:{texturePath}");
  117. return;
  118. }
  119. var customFontPath = fntPath.Replace(".fnt", ".fontsettings");
  120. var customFont = AssetDatabase.LoadAssetAtPath<Font>(customFontPath);
  121. if (customFont == null)
  122. {
  123. customFont = new Font(Path.GetFileNameWithoutExtension(fntPath));
  124. AssetDatabase.CreateAsset(customFont, customFontPath);
  125. }
  126. var matiralPath = fntPath.Replace(".fnt", ".mat");
  127. var material = AssetDatabase.LoadAssetAtPath<Material>(matiralPath);
  128. if (material == null)
  129. {
  130. material = new Material(Shader.Find("XGame/Text Shader"));
  131. AssetDatabase.CreateAsset(material, matiralPath);
  132. }
  133. material.mainTexture = texture;
  134. customFont.material = material;
  135. customFont.characterInfo = charInfos.ToArray();
  136. EditorUtility.SetDirty(material);
  137. EditorUtility.SetDirty(customFont);
  138. AssetDatabase.SaveAssets();
  139. AssetDatabase.Refresh();
  140. if (customFont.lineHeight < lineHeight)
  141. {
  142. Debug.LogWarning($"需要手动修改字体的LineSpacing. 当前:{customFont.lineHeight} 推荐:{lineHeight}");
  143. }
  144. Debug.Log($"字体生成完成. Path:{customFontPath}");
  145. }
  146. }
  147. }