Python 现代开发学习笔记

(十二)文字与短音效

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 的左上角放置图像。载入和缩放发生在循环外,循环内只处理事件并复用已经准备好的资源。

逻辑本步产生一次计分或碰撞消息,声音层消费消息后播放,后续画面不重复触发同一次声音

笔记正文与全部题解 · Ctrl / ⌘ K