在游戏开发中,尤其是对于移动端的游戏开发来说,直接使用TTF来进行渲染是非常消耗资源的;而且一般的游戏用到的字的个数都是有限的。针对以上几个弊端,就有人按照着活字印刷术的原理来设计了一个在游戏中常用的位图导出工具,比如windows下的bmfont、java写的hiero等等,用到文字比较多的一般是RPG游戏,如下图所示:
以下是BMFont官网的简介:
此程序将允许您从TrueType字体生成位图字体。应用程序生成图像文件和字符描述,游戏可以读取这些文件和字符描述,以便轻松呈现字体。
位图在游戏引擎中一般都会有封装好的,比如cocos2dx在2.x时代提供了LabelBMFont,在3,x后为Label。
本节主要讲解的就是如何通过python来实现根据用到的文字导出位图文件。
1.安装BMFont
首先需要安装BMFont。BMFont的安装很简单,这个软件同时提供了界面和命令行,不过美中不足的就是只能在windows下使用。对于批量导出来说,命令行尤其重要。至于BMFont的简单使用,可以参考下面这个帖子或者自行百度:
https://blog.youkuaiyun.com/u013654125/article/details/78672809
2.配置Path
由于批量导出使用的得是命令行,所以在python程序运行时,需要知道BMFont的安装路径。
假设此时的BMFont安装在D盘的bmfont下,那么在Path中则添加下面一条:
D:\BMFont
之后可以在dos中确定是否可以找得到这个软件,键入bmfont,如果直接显示的是bmfont的界面,则表示Path的路径配置成功。
注:这一步是非必须的,如果不想配置的话,在python代码中得需要明确bmfont的安装路径。
3.从配置|源文件文件中提取文本
一般情况下,像上图这种对话的文本是写在配置文件或者脚本文件中的,所以需要有一个规则来提取要显示的文本。
以下面这个脚本为例:
function Map01_01:firstIn()
-- 第一次运行,执行脚本
base.setGameState(GameState.Script);
--获取主角名字
local playerName = party.getName(0);
--旁白
message.showText("***","一群小鬼(初三的模样)在网吧坐在一块玩游戏", TextPosition.Middle,true);
end
上面的示例是我写的RPG游戏的部分脚本代码。可以看到,文本显示主要是message.showText函数的前两个参数。所以,我们需要提取的就是这两个参数的文本。然后再把这个操作扩展到所有的脚本文件,挨个提取完之后导出为一个文本,以供BMFont所使用。
import os
import re
def generate_text(path, filename):
"""
遍历path路径下的所有文件,并正则提取出所有文本,然后生成utf-8的txt文件
:param path: 要遍历的路径名
:param filename: 导出的文件名
:return:
"""
# 获取路径下的所有文件
paths = os.listdir(path)
# 正则匹配要显示的文本
pattern = re.compile(r'showText\(\"(.*?)\"\s*,\s*\"(.*?)\"')
# 用得到数字
contents = ["1234567890"]
# 遍历
for name in paths:
fp = open(os.path.join(path, name), "r", encoding="utf-8")
lines = fp.readlines()
text = "".join(lines)
results = re.findall(pattern, text)
if len(results) == 0:
continue
print(results)
for result in results:
contents.append(result[0])
contents.append(result[1])
# 写入文件
with open(filename, "w", encoding="utf-8") as fp:
fp.writelines(contents)
print("写入文件成功:%s" % filename)
以上代码的流程图大致如下:
值得一提的就是正则提取文本的规则,大家可以根据自己的需要来改变提取规则。如果提取规则过于麻烦,或者有多于一个的提取规则,则可以考虑封装不同的函数来进行提取。
4.导出位图
位图的导出则相对来说比较简单了。
def generate_fnt(bmfc, input, path, filename):
"""
根据配置文件和输入的文本文件来导出对应的fnt文件和png文件
:param bmfc: BMFont的配置文件
:param input: 文本文件
:param path: 输出路径
:param filename: 输出文件名称
:return:
"""
# 判断输出文件夹是否存在
if not os.path.exists(path):
os.mkdir(path)
print("创建文件夹成功", path)
ret = os.system("bmfont -c %s -t %s -o %s" % (bmfc, input, os.path.join(path, filename)))
# 导出成功
if ret == 0:
print("fnt文件导出成功")
bmfont的命令行:
- -c 配置文件,扩展名为*.bmfc
- - t 文本文件
- -o 导出文件
os.system()的返回值就是命令的返回值,一般情况下返回0则表示操作成功。
最后就是上面两个函数的整合了。
if __name__ == '__main__':
# 主目录
base_path = os.path.join(".", "RPGGame", "Resources")
# 先提取出要用到的文本,并生成文件
generate_text(os.path.join(base_path, "script"), "1.txt")
# 使用bmfont 命令行导出资源文件,并放到对应的文件夹中
generate_fnt("1.bmfc", "1.txt", os.path.join(base_path, "fonts"), "1.fnt")
由于不同操作系统的路径分隔符是不同的,所以上面的代码中用到了os.path.join()。