当前位置:编程学习 > python >>

[利用 Python 快速制作游戏字库](一)基础篇+分割字库图片

 

原始出处: Your life just a MOD

前言

其实早就打算写相关文章的,但因为抽不出时间还是一直没动笔。最近又想起来,然后翻开近半年前的草稿一看,居然一字未动。现在回想起来,当初定的目标似乎太遥远了,所以我打算把原来准备一次写完的内容拆成一小段一小段来写。这样有空就写一小段,似乎更实际一点。

 

在开始读这篇心得前,本人假定你对Python语言已有足够的了解,并已能写一些小程序;清楚游戏字库特别是图片类字库的原理、构造、作用,已做过或有充分准备可以制作一种字库。对于文章中出现的一些库和模块的功能,我会进行一定程度的讲解,更多需要你自行查阅。

 

准备

 

1、你需要安装python 2.7.x(目前我使用2.7.2),可以在这里找到:http://python.org/getit/

 

2、安装PIL(python的一个第三方图像处理库),当前最新版是1.1.7,点此下载,最新版本在此查看:http://www.pythonware.com/products/pil/

 

3、NVIDIA Texture Tools,可以将其他格式图片转换为dds格式,而且效率较高,还支持很多选项。但不单独提供,这是我提取出来的版本。点此下载

 

4、[可选]本人制作的字库生成器,你也可以使用其他类似软件代替,但本篇中提到字库生成器都以此为准。点此下载

 

5、urfFontReader(Urf字库生成器字体读取脚本)。很多例子都会用到,点此下载(记得点download)

 

转换bmp至png格式

 

字库生成的方法参考字库生成器的文章,这里不再详述。

 

 

 

由于字库生成器生成的bmp图片不方便接下来的操作,而且文件相对较大,所以推荐转换为png格式保存。png格式可以包含透明层,体积也很小,而且读取速度不慢。假设生成的图片为“1.bmp”,然后看下面的代码:  

 

import Image #导入PIL的基本处理模块

 

#打开bmp文件并转换为RGBA模式

bmp = Image.open('1.bmp').convert('RGBA')

#用一个列表保存像素数据

rgba = []

#将所有像素用简单公式转换为灰度作为透明层,底图使用白色

for pix in bmp.getdata():

    rgba.append((255, 255 ,255 ,int( pix[0]*0.299 + pix[1]*0.587 + pix[2]*0.114 )))

#保存修改

bmp.putdata(rgba)

bmp.save('1.png')

 

以上代码可以稍加修改,然后将此脚本作为一个命令行工具使用。

 

读取字体数据

 

我提供的urfFontReader可以很方便的读出保存在bin文件中的字体信息。这样就可以将相关数据转换为游戏需要的格式。下面通过分析该脚本的代码,初步了解二进制数据的处理方法。

 

#从struct模块引入必要函数

from struct import pack,unpack

 

def ReadUrfFontInfo(fontname):

    #以二进制模式打开文件并读取

    fl=open(fontname+'.bin','rb')

    #解开文件头中的数据

    img_w,img_h,nums,ch,stp1,stp2=unpack('6i',fl.read(24))

    #解开所有字符数据

    data = unpack('='+'H4i'*nums,fl.read(-1)) #+’='使之采用标准数据大小

    #用一个字典保存字符数据,方便使用

    db={}

    #转换成字典

    for i in xrange(nums):

        c,w,h,x,y = data[i*5:i*5+5]

        db[c]=(w,h,x,y)

    #返回数据

    return (img_w,img_h,nums,ch),db

 

 整个脚本主要使用了struct模块的upack函数来解构二进制数据。因为python并不能直接处理二进制数据(虽然可以当作字符串来处理,当其他数据类型就另当别论了)。upack函数的第一个参数用来描述数据结构,第二个参数是以字符串形式保存的数据。因为我这个字库当初设计得很简单,所以只用到二中类型,分别是:“H”无符号短整数;“i”有符号整数。与C程序中相应类型对应。

 

关于struct模块的更详细信息可以在网上搜索相关例程,或者在python控制台用help函数查看内部文档,之后不再详述。

 

下面是一个从其他脚本调用urfFontReader的实例。

 

#直接导入所需函数

from urfFontReader import ReadUrfFontInfo

#使用该函数读取字体bin文件,返回值分别存入等号前的变量

(img_w,img_h,nums,ch),font_data = ReadUrfFontInfo(r'mydir\myfont')

#打印图片的宽、高,包含的字符数和字符默认高度

print """image : %dx%d

number of chars : %d

general height : %d"""%(img_w,img_h,nums,ch)

#打印所有字符数据(unicode代码、宽、高、坐标x、y)

for char in font_data:

    w,h,x,y=font_data[char]

    print "X"%char,x,y,w,h

 

转换数据为游戏所需格式

 

字库生成器为了通用性,所以设计上是输出部分关键数据,然后根据具体游戏再转换为对应格式。

 

以下以相对较为简单的Chrome4引擎为例。该引擎的字库使用纯文本定义,每个字符需要6个相关参数。具体如下:

 

Char( unicode值, 实际宽度, 左顶点x坐标, 左顶点y坐标, 右下顶点x坐标, 右下顶点y坐标)

 

根据上面的定义,有些数据在读取后可以直接使用,而有些则需要进行计算。因此得到以下代码:

 

from urfFontReader import ReadUrfFontInfo

(img_w,img_h,nums,ch),font_data = ReadUrfFontInfo(r'1')

#创建一个文件用于写入输出文件

fm = open('mid_28.fm','w')

#先写入游戏字库需要的基本信息

fm.write('''Name("mid")

MapWidth(%d)

MapHeight(%d)

FontHeight(%d)

'''%(img_w,img_h,ch))

#遍历所有数据,写入每个字符的定义

for char,(w,h,x,y) in font_data.iteritems():

    fm.write("Char(%d, %d, %d, %d, %d, %d)\n"%(char, w, x, y, x+w, y+ch))

 

由于字典类型是没有顺序的,所以输出的文件会有点乱。但稍加改动就可以按unicode代码的顺序输出数据。

 

 #先将所有项的列表保存到一个变量

data = font_data.items()

#对这个列表排序

data.sort()

#再通过排序后的列表输出

for char,(w,h,x,y) in data:

    fm.write("Char(%d, %d, %d, %d, %d, %d)\n"%(char, w, x, y, x+w, y+ch))

 

以上介绍了一个相对简单的,保存为游戏可用格式的例子。在以后的文章中我会提供更多更复杂的例子。

 

分割字库图片

 

有很多情况需要分割字库图片。比如对于一些老显卡,可能不支持2048x2048以上的纹理大小,某些游戏只支持固定大小纹理等等。分割字库的思路很简单。先打开一个字库,然后将字符挨个复制到新大小的图片中,当装不下时就保存当前图片再新建另外一张图片。借助PIL库,很容易完成这个任务。

 

import Image

from urfFontReader import ReadUrfFontInfo

(img_w,img_h,nums,ch),font_data = ReadUrfFontInfo(r'1')

#设置分割成多大

max_w = 512 #目标宽度

max_h = 512 #目标高度

#打开我们的字库图片

img_in = Image.open('1.png')

 

img_idx = 0 #图片序号/计数器

cx = 0 #在目标图片中的x坐标

cy = 0 #在目标图片中的y坐标

#新建一张图像用于输出

img_out = Image.new("RGBA",(max_w,max_h))

#遍历所有数据进行分割

for char,(w,h,x,y) in font_data.iteritems():

    #如果下一个字符粘贴后超出目标宽度则切换到下一行

    if cx + w > max_w:

        cy += ch #换行

        #如果余下高度不足容纳一个字符则新建另一张图片

        if cy + ch > max_h:

            cy = 0 #y坐标归零

            img_out.save('s

补充:Web开发 , Python ,
CopyRight © 2022 站长资源库 编程知识问答 zzzyk.com All Rights Reserved
部分文章来自网络,