(十二)文字与短音效
1. 字体把字符串绘制成 Surface
pygame.font.Font(None, 36) 使用自带字体,按 36 像素的字号建立字体对象;None 所在位置也可以传字体文件路径。再用 font.render(文字, True, 颜色) 生成文字图像,随后和普通图像一样 blit。True 表示对文字边缘做抗锯齿处理。
示例用 Pygame 自带字体绘制英文提示。字体文件决定包含哪些字形;改成中文界面时,可以在 assets 放入含相应中文字形的字体文件,再把 Font 的 None 换成那个资源路径。
2. 一次动作播放一次短音效
继续把 SoundBank 写进同一个 assets.py:
# 续写同一文件:dodge_project/src/dodgegame/assets.py
# 音效在启动时加载一次;关闭声音后保留同一调用接口,只跳过实际播放。
class SoundBank:
def __init__(self, muted=False):
self.muted = muted
self.sounds = {}
try:
if pygame.mixer.get_init() is None:
pygame.mixer.init(frequency=22050, size=-16, channels=1)
self.sounds = {
name: pygame.mixer.Sound(ASSET_DIR / f"{name}.wav")
for name in ("score", "hit")
}
for sound in self.sounds.values():
sound.set_volume(0.18)
except pygame.error as error:
logger.warning("声音设备未准备好,继续显示游戏画面:%s", error)
def toggle(self):
self.muted = not self.muted
def play(self, name):
if not self.muted and name in self.sounds:
self.sounds[name].play()mixer 处理声音。示例选择每秒 22050 个样本、16 位有符号采样和单声道;Sound 预先载入短 WAV,play 才安排播放,set_volume 调低音量。声音播放后主循环继续推进,不需要等整段音效结束。mixer 与 Sound
游戏逻辑交回 score、hit 这样的动作消息,输入层再播放对应声音;结束状态的后续每帧没有新的 hit 消息,就不会连续重播撞击声。M 只改变 muted,声音设备未准备好时保留日志,窗口与逻辑继续运行。
# 项目文件:demos/resource_preview.py
# 图像和字体预先加载,循环内重用;一次点击播放短音效,关闭时释放全部模块。
import pygame
from dodgegame.assets import Images, SoundBank
def main():
pygame.init()
try:
screen = pygame.display.set_mode((480, 320))
images, sounds = Images(), SoundBank()
icon = images.get("player", (96, 72))
font = pygame.font.Font(None, 36)
label = font.render("IMAGE + TEXT", True, "#24324A")
clock, running = pygame.time.Clock(), True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
elif event.type == pygame.MOUSEBUTTONDOWN and event.button == 1:
sounds.play("score")
if not running:
break
screen.fill("#F5F7FB")
screen.blit(icon, icon.get_rect(center=(240, 135)))
screen.blit(label, label.get_rect(center=(240, 220)))
pygame.display.flip()
clock.tick(60)
finally:
pygame.quit()
if __name__ == "__main__":
main()这个窗口组合了图像与文字,左键点击时播放一次短音效。image.get_rect(center=(240, 135)) 取得与图像同样大小的 Rect,并将中心放到给定坐标;blit 再使用这个 Rect 的左上角放置图像。载入和缩放发生在循环外,循环内只处理事件并复用已经准备好的资源。