如何查找和加载游戏字体?以及获取和设置字体样式等问题
关注 1800
虽然本节的示例中包含绘制文本的代码,但本节不会讲解与文本绘制相关的问题,要了解文本绘制,请查看在表面中绘制图像和文本(字体)一段。
如何在 Pygame 中加载字体,以及获取和设置样式视频演示 YouTube如何在 Pygame 中加载字体,以及获取和设置样式视频演示 Bilibili
Pygame 中的 font 模块
Pygame 包的font模块,包含了与字体相关的功能,主要涉及字体的加载(获取),以及字体的绘制(本节内容不涉及此部分),当你导入pygame模块时,font模块会被pygame模块导入。
初始化 font 模块
与pygame模块一样,font模块拥有用于初始化的函数init,该函数会在pygame模块的init函数中被调用,这意味着一旦使用pygame模块进行初始化,调用font模块的init函数将是没有必要的。
init()
可以重复调用 init 函数
你可以反复调用init函数,这没有任何问题,即便在调用quit函数之后。
# 导入模块 font
from pygame import font
# 初始化
font.init()判断 font 模块是否已经初始化
与pygame模块一样,font模块拥有判断font模块是否已经初始化的函数get_init。
get_init()
- 返回值
如果
get_init函数返回True,那么表示font模块已经进行了初始化。
在调用 quit 函数之后,get_init 函数将返回 False
在调用quit函数之后,get_init函数将返回False,这表示再次调用init函数将产生实际效果,他会重新初始化font模块。
# …
print(f'font 已经初始化?{font.get_init()}')font 已经初始化?True取消初始化 font 模块
与pygame模块一样,font模块拥有用于取消初始化的函数quit,该函数会在pygame模块的quit函数中被调用,这意味着一旦使用pygame模块取消了初始化,调用font模块的quit函数将是没有必要的。
quit()
可以重复调用 quit 函数
和init函数一样,你可以反复调用quit函数,这没有任何的问题。
获取所有可用字体的名称
font模块的get_fonts函数,可用于获取所有可用的字体的名称。
get_fonts()
- 返回值
get_fonts函数的返回值是一个 Python 字符串列表,每一个字符串对应一个字体名称。
在 Pygame 2.1.3 以及之后的版本中,除了系统字体,函数get_fonts还会检索用户字体,对于 Windows 操作系统而言。
get_fonts 函数会简化字体名称
get_fonts函数会将字体名称改为小写,同时,对于字体名称中包含的空格或标点,get_fonts会尝试去除他们。
# …
# 获取所有可用字体的名称
print(font.get_fonts())['arial', 'arialblack', 'bahnschrift', …]获取默认字体的文件名
font模块的get_default_font函数,可用于获取 Pygame 默认字体的文件名称。
get_default_font()
- 返回值
get_default_font函数的返回值是一个 Python 字符串,表示默认字体的文件名称(不是文件路径)。
Pygame 包所使用的默认字体
Pygame 包所使用的默认字体并非操作系统的默认字体,一般情况下,Pygame 的默认字体文件(freesansbold.ttf)所在的目录与pygame模块所在的目录相同,但默认字体文件也可能被捆绑在其他文件中。
这里需要指出,即便 Pygame 包所使用的默认字体文件不存在,font模块的get_default_font函数还是会返回其名称。
# …
# 获取默认字体的文件名称
print(font.get_default_font())freesansbold.ttf获取指定字体的文件路径
font模块的match_font函数,可用于获取最符合给出条件的字体的文件路径,当然,该函数所找到的字体可能并不完全符合你的要求。
就像 CSS 的font-family一样,你可以为font模块的match_font函数指定多个字体名称,match_font将依次检索这些字体名称以及其他条件(粗体,斜体),当某个字体可用时,将返回该字体的文件路径。
match_font(name, bold=False, italic=False)
- name 参数
name参数可以是一个字符串,表示需要获取文件路径的字体的名称,多个字体名称使用,进行分隔。name参数也可以是包含多个字体名称的迭代器对象,比如包含多个字体名称的 Python 元组。如果你不知道应该如何书写字体名称,那么可以使用
get_fonts函数来查看可用的字体名称有哪些,详情请参考获取所有可用字体的名称一段。- bold 参数
bold参数是一个布尔值,如果设置为True,那么将尝试获取粗体字体的文件路径。- italic 参数
italic参数是一个布尔值,如果设置为True,那么将尝试获取斜体字体的文件路径。- 返回值
match_font函数将返回包含字体文件路径的字符串,如果未找到字体,则返回空值None。
在 Pygame 2.1.3 以及之后的版本中,除了系统字体,函数match_font还会检索用户字体,对于 Windows 操作系统而言。
match_font 函数会简化字体名称
match_font函数会将字体名称改为小写,如果name参数所表示的字体名称包含空格或标点符号(不包括英文,),那么match_font将尝试去除空格和标点符号。
在下面的示例中,我们给出了两个字体名称,由于第一个字体tahoma有效,虽然只找到了粗体样式(没有找到粗斜体样式),因此,第二个字体不会被检测,第二个字体名称Sitka Text等同于sitkatext。
# …
# 获取字体文件的路径
print(font.match_font('tahoma,Sitka Text', True, True))# Windows 中的输出结果
C:\WINDOWS\Fonts\tahomabd.ttf为游戏加载字体
font模块的Font类,可将指定的字体文件加载到游戏中,只需要在创建其实例时,指定字体文件的路径以及字体的大小。
Font(name, size)
- name 参数
name参数是表示字体文件路径的字符串,或包含字体文件路径的类路径(path-like)对象,或包含字体数据的IO对象。如果未设置参数
name或该参数为空值None,那么 Pygame 将使用默认字体。如果字体文件不存在,那么将导致异常FileNotFoundError。- size 参数
size参数是一个表示字体大小的 Python 整数,默认大小为12。
无法通过 Font 对象修改字体大小
需要说明的是,一旦创建了Font类的实例,你将无法通过该实例修改字体的大小。
在下面的示例中,我们首先使用match_font函数获取了字体Microsoft JhengHei的文件路径,然后根据该路径创建了一个Font对象,以将对应的字体载入到游戏中。
# 导入并初始化 font 模块
from pygame import font
font.init()
# 获取字体文件的路径,并创建一个字体对象
path = font.match_font('Microsoft JhengHei')
# 字体将采用默认大小 12
f = font.Font(path)
# 创建游戏窗口,并使用字体对象 f 绘制文字
from pygame import display
w = display.set_mode((800, 600))
# 在游戏窗口中绘制文字
ts = f.render('你好!', False, [255, 255, 255])
w.blit(ts, [200, 200])
display.flip()
# 等待 3 秒
import time
time.sleep(3)获取和设置字体是否拥有粗体样式
Font对象的get_bold和set_bold方法,以及bold变量,可用于获取和设置游戏字体是否拥有粗体样式。
如果 Pygame 所加载的字体文件本身为粗体样式,那么使用Font对象的set_bold方法或修改其bold变量,将不会产生任何效果,即你不能以非粗体样式来绘制粗体文本。如果 Pygame 所加载的字体文件本身为非粗体样式,那么也应尽量避免使用Font对象的set_bold方法或修改其bold变量,以粗体样式来绘制非粗体文本(因为这需要计算),实现粗体效果应首先考虑加载对应的粗体字体文件。
get_bold()
- 返回值
如果
get_bold返回True,则表示以粗体样式绘制文本。
set_bold(value)
- value 参数
value参数是一个布尔值,如果为True,则表示以粗体样式绘制文本。
font.bold
font.bold = bold
- bold 值
bold是一个布尔值,如果为True,则表示以粗体样式绘制文本。
在下面的示例中,我们加载了一个非粗体字体文件,通过修改bold变量,游戏中的文本将以粗体样式绘制。
# 导入并初始化 font 模块
from pygame import font
font.init()
# 加载一个非粗体字体文件,字体大小 24
f = font.Font(font.match_font('Microsoft JhengHei'), 24)
# 修改为粗体样式
f.bold = True
print(f'粗体?{f.get_bold()}')
# 创建游戏窗口,并使用字体对象 f 绘制文字
from pygame import display
w = display.set_mode((800, 600))
# 在游戏窗口中绘制文字
ts = f.render('以粗体样式绘制', False, [255, 0, 0])
w.blit(ts, [50, 50])
display.flip()
# 等待 3 秒
import time
time.sleep(3)粗体?True获取和设置字体是否拥有斜体样式
Font对象的get_italic和set_italic方法,以及italic变量,可用于获取和设置游戏字体是否拥有斜体样式。
如果 Pygame 所加载的字体文件本身为斜体样式,那么使用Font对象的set_italic方法或修改其italic变量,将不会产生任何效果,即你不能以非斜体样式来绘制斜体文本。如果 Pygame 所加载的字体文件本身为非斜体样式,那么也应尽量避免使用Font对象的set_italic方法或修改其italic变量,以斜体样式来绘制非斜体文本(因为这需要计算),实现斜体效果应首先考虑加载对应的斜体字体文件。
get_italic()
- 返回值
如果
get_italic返回True,则表示以斜体样式绘制文本。
set_italic(value)
- value 参数
value参数是一个布尔值,如果为True,则表示以斜体样式绘制文本。
font.italic
font.italic = italic
- italic 值
italic是一个布尔值,如果为True,则表示以斜体样式绘制文本。
在下面的示例中,我们加载了一个斜体字体文件,虽然尝试通过set_italic方法为字体取消斜体样式,但这不会产生任何效果。
# 导入并初始化 font 模块
from pygame import font
font.init()
# 加载一个斜体字体文件
f = font.Font(font.match_font('Arial', italic=True), 30)
# 无法将斜体修改为非斜体
f.set_italic(False)
print(f'斜体?{f.get_italic()}')
# 创建游戏窗口,并使用字体对象 f 绘制文字
from pygame import display
w = display.set_mode([800, 600])
# 在游戏窗口中绘制文字
ts = f.render('Draw in italic style', True, (0, 255, 0))
w.blit(ts, (200, 200))
display.flip()
# 等待 3 秒
import time
time.sleep(3)斜体?True获取和设置字体是否拥有下划线样式
Font对象的get_underline和set_underline方法,以及underline变量,可用于获取和设置游戏字体是否拥有下划线样式。
get_underline()
- 返回值
如果
get_underline返回True,则表示以下划线样式绘制文本。
set_underline(value)
- value 参数
value参数是一个布尔值,如果为True,则表示以下划线样式绘制文本。
font.underline
font.underline = underline
- underline 值
underline是一个布尔值,如果为True,则表示以下划线样式绘制文本。
# 导入并初始化 font 模块
from pygame import font
font.init()
# 加载 Pygame 默认字体,字体大小 30
f = font.Font(size=30)
# 修改为下划线样式
f.set_underline(True)
# 创建游戏窗口,并使用字体对象 f 绘制文字
from pygame import display
w = display.set_mode((800, 600))
# 在游戏窗口中绘制文字
w.blit(f.render('Underline', False, [255, 0, 255]), [200, 200])
display.flip()
# 等待 3 秒
import time
time.sleep(3)获取和设置字体是否拥有删除线样式
Font对象的get_strikethrough和set_strikethrough方法,以及strikethrough变量,可用于获取和设置游戏字体是否拥有删除线样式。
get_strikethrough()
- 返回值
如果
get_strikethrough返回True,则表示以删除线样式绘制文本。
set_strikethrough(value)
- value 参数
value参数是一个布尔值,如果为True,则表示以删除线样式绘制文本。
font.strikethrough
font.strikethrough = strikethrough
- strikethrough 值
strikethrough是一个布尔值,如果为True,则表示以删除线样式绘制文本。
# 导入并初始化 font 模块
from pygame import font
font.init()
# 加载第一个可用的字体
fontname = font.get_fonts()[0]
f = font.Font(font.match_font(fontname))
# 修改为删除线样式
f.strikethrough = True
# 创建游戏窗口,并使用字体对象 f 绘制文字
from pygame import display
w = display.set_mode((800, 600))
# 在游戏窗口中绘制文字
w.blit(f.render('Strikethrough', False, [255, 255, 255]), [300, 300])
display.flip()
# 等待 3 秒
import time
time.sleep(3)获取绘制文本所需的空间大小
Font对象的size方法,可用于计算绘制指定文本所需的空间大小,该方法通常用于布局操作,比如,你可以在获取绘制所需的空间大小之后,判断文本是否能够完全显示在按钮之内。
size(text)
- text 参数
text参数是一个字符串,size方法将计算绘制该字符串所需的空间大小。- 返回值
size方法返回一个形式类似于(width,height)的 Python 元组,其中width表示绘制文本所需空间的宽度,其中height表示绘制文本所需空间的高度。
Font 对象的 size 方法不会处理字符串中的转义序列
Font对象的size方法不会处理字符串中的转义序列,比如,换行符\n和制表符\t,这些转义序列可能会被表示为一个或数个空心方块,因此,size方法所返回的空间大小可能和你预期的不一样。
在下面的示例中,绘制换行符和制表符仅需要很少的空间。
# 导入并初始化 font 模块
from pygame import font
font.init()
# 加载默认字体,字体大小 24
f = font.Font(size=24)
print(f'绘制 A 所需的空间大小:{f.size('A')}')
# 绘制空间不会增加一个行的高度
print(f'绘制 A\\n 所需的空间大小:{f.size('A\n')}')
# 绘制空间不会增加一个制表宽度
print(f'绘制 A\\t\\n 所需的空间大小:{f.size('A\t\n')}')绘制 A 所需的空间大小:(12, 16)
绘制 A\n 所需的空间大小:(19, 16)
绘制 A\t\n 所需的空间大小:(26, 16)大部分字体会对特定的字母组合进行字符间距微调
对于一些字母的组合,比如ae,大部分字体会对组合中的字母之间的距离进行微调(字偶距微调),以改善文本的可读性,因此,一次性绘制所有文本所需要的空间宽度,可能与单独绘制文本中的每个字符所需的空间宽度不同。
# …
# 加载字体 tahoma
f = font.Font(font.match_font('tahoma'))
# 计算一次性绘制所需的空间宽度
print(f'一次性绘制 Appearance 所需的空间宽度:{f.size("Appearance")[0]}')
# 计算单独绘制每个字符所需的空间宽度
width = 0
for i in 'Appearance':
width += f.size(i)[0]
print(f'单独绘制 Appearance 中的每个字符所需的空间宽度:{width}')一次性绘制 Appearance 所需的空间宽度:62
单独绘制 Appearance 中的每个字符所需的空间宽度:65获取字体的行高
Font对象的get_linesize方法,可以获取字体的行高,该方法通常用于在绘制多行文本时计算下一行文本的位置。
Font 对象的 get_linesize 与 get_height 方法的返回值可能不同
需要注意,Font对象的get_linesize方法的返回值与get_height方法的返回值可能不相等,如果不相等,那么字体行高一般大于字体高度。
get_linesize()
- 返回值
get_linesize方法的返回值是表示字体行高的整数。
# 导入并初始化 font 模块
from pygame import font
font.init()
# 加载默认字体,字体大小 120
f = font.Font(size=120)
# 获取字体行高
print(f'字体行高:{f.get_linesize()}')字体行高:90获取字体的高度
Font对象的get_height方法,可用于获取字体的高度,该高度为字体中所有字形的平均高度。
get_height()
- 返回值
get_height方法的返回值是表示字体高度的整数。
# …
# 获取字体高度
print(f'字体高度:{f.get_height()}')字体高度:82获取字体的上移量和下移量
Font对象的get_ascent和get_descent方法,可用于获取字体的上移量和下移量,上移量(正整数)表示字体基线与字体顶部之间的距离,下移量(负整数)表示字体基线与字体底部之间的距离,字体上移量和下移量的绝对值之和等于字体的高度(而非行高)。
get_ascent()
- 返回值
get_ascent方法的返回值是表示字体上移量的正整数。
get_descent()
- 返回值
get_descent方法的返回值是表示字体下移量的负整数。
在下面的示例中,字体的上移量为66,字体的下移量为-16,两者的绝对值之和为82,等于字体的高度。
# 导入并初始化 font 模块
from pygame import font
font.init()
# 加载默认字体,字体大小 120
f = font.Font(size=120)
print(f'字体上移量:{f.get_ascent()},字体下移量:{f.get_descent()}')
print(f'字体高度:{f.get_height()}')字体上移量:66,字体下移量:-16
字体高度:82获取字体的度量值
Font对象的metrics方法,可用于获取字体中某些字符的度量值。
metrics(text)
- text 参数
text参数是一个字符串,metrics方法将计算字符串中的每个字符的度量值。- 返回值
metrics方法的返回值是一个包含元组的 Python 列表,每一个元组的形式均类似于(minx,maxx,miny,maxy,advance),其中minx表示字符在 X 轴上的最小偏移值,maxx表示字符在 X 轴上的最大偏移值,miny表示字符在 Y 轴上的最小偏移值,maxy表示字符在 Y 轴上的最大偏移值,advance表示字符的前进偏移值。
在下面的示例中,我们获取了字符A,e,p的度量值。
# 导入并初始化 font 模块
from pygame import font
font.init()
# 加载默认字体,字体大小 120
f = font.Font(size=120)
# 获取每个字符的度量值
print(f'{f.metrics('Aep')}')[(2, 58, 0, 60, 59), (1, 44, -2, 44, 46), (4, 48, -18, 44, 50)]为文字整形设置文字编码
Font对象的set_script方法,可用于为文字整形设置文字编码。
set_script(script_code)
- script_code 参数
script_code参数是一个表示文字编码(符合 ISO 15924 标准,由四个字符组成)的字符串。
Font 对象的 set_script 方法需要 SDL_ttf 2.20.0 或更高版本
要正常使用Font对象的set_script方法,需要 SDL_ttf 的版本为 2.20.0 或更高,否则会导致异常。
什么是文字整形?
文字整形用于对显示的文字进行调整,以达到一种最佳的视觉效果,Pygame 使用 HarfBuzz 作为文字整形的引擎。
# 导入并初始化 font 模块
from pygame import font
font.init()
# 将文字整形设置为阿拉伯文
f = font.Font()
f.set_script('Arab')获取 SDL_ttf 的版本信息
font模块构建在 SDL_ttf 之上,该模块的get_sdl_ttf_version函数,其返回值是一个元组,元组包含了 SDL_ttf 的版本信息。
get_sdl_ttf_version(linked=True)
- linked 参数
如果
linked参数为True,则函数get_sdl_ttf_version返回当前所使用的 SDL_ttf 的版本信息,否则返回 Pygame 包在编译时所针对的 SDL_ttf 版本。- 返回值
get_sdl_ttf_version函数的返回值是一个形式类似于(major,minor,patch)的 Python 元组,其中major表示主要版本号,minor表示次要版本号,patch表示补丁号。
from pygame import font
# 获取 SDL_ttf 版本
print(f'当前使用的 SDL_ttf 版本:{font.get_sdl_ttf_version()}')
print(f'编译时针对的 SDL_ttf 版本:{font.get_sdl_ttf_version(False)}')当前使用的 SDL_ttf 版本:(2, 20, 1)
编译时针对的 SDL_ttf 版本:(2, 20, 1)源码
讲解视频
如何在 Pygame 中加载字体,以及获取和设置样式·YouTube如何在 Pygame 中加载字体,以及获取和设置样式·Bilibili