如何查找和加载游戏字体?以及获取和设置字体样式等问题
关注 1260
虽然本节的示例中包含绘制文本的代码,但本节不会讲解与文本绘制相关的问题,要了解文本绘制,请查看在表面中绘制图像和文本(字体)一段。
如何在 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