Ресурсы игры: графика и звук
Настоящие спрайты вместо прямоугольников — и класс, который загружает их ровно один раз.
До сих пор корабль, враги и пули рисовались простыми прямоугольниками и кругами — удобно для первых шагов (раздел 20.3). Финальная версия использует собственные спрайты, нарисованные специально для этого проекта, вместо геометрических заглушек.
Спрайты проекта
Все изображения сохранены как файлы .png с прозрачным фоном.
При загрузке они попадают в Surface, которая поддерживает альфа-канал (флаг
pygame.SRCALPHA при создании такой Surface, раздел 20.17, —
это свойство самой Surface в pygame, а не PNG-файла), поэтому прозрачные пиксели остаются
прозрачными и на экране. Спрайты нарисованы напрямую через
pygame.draw в отдельном скрипте
scripts/generate_chapter_21_assets.py, а не скачаны откуда-то —
простые геометрические фигуры, без единого существующего коммерческого спрайта.
| Файл | Роль | Особенность |
|---|---|---|
| player_ship.png | Корабль игрока | Стреловидный силуэт, светлая кабина, свечение двигателя |
| enemy_scout.png | Быстрый, дешёвый враг | Маленький, оранжево-красный треугольник |
| enemy_fighter.png | Медленный, дорогой враг | Крупнее, пурпурно-красный, с боковыми модулями |
| bullet.png | Снаряд игрока | Маленькая яркая жёлтая капсула |
| explosion_sheet.png | Анимация взрыва | 6 кадров в ряд — раздел 21.20 режет их через subsurface() |
AssetStore — загрузка один раз
Раздел 20.24 уже предупреждал: загрузка файла внутри игрового цикла — частая причина просадок кадров. Здесь всё загружается один раз в момент создания игры, в отдельном классе:
class AssetStore:
def __init__(self, image_dir, audio_dir):
self.images = {{}}
for key in ("player_ship", "enemy_scout", "enemy_fighter", "bullet"):
self.images[key] = pygame.image.load(image_dir / f"{{key}}.png").convert_alpha()
self.sounds = {{}}
for key in ("laser", "explosion", "player_hit"):
path = audio_dir / f"{{key}}.wav"
try:
self.sounds[key] = pygame.mixer.Sound(str(path))
except (pygame.error, FileNotFoundError):
self.sounds[key] = None
pygame.image.load(...) уже сохраняет прозрачность загруженного PNG сама по себе — .convert_alpha() не «создаёт» прозрачность, а лишь готовит копию в формате пикселей экрана для быстрой повторной отрисовки (раздел 20.19). Здесь она вызывается сразу после загрузки, пока изображений мало и это не нужно откладывать.pygame.mixer.Sound(...) может завершиться ошибкой — тогда self.sounds[key] остаётся None, а игра всё равно запускается и работает, просто без звука. Раздел 21.21 показывает, как проигрывание учитывает это на каждом вызове.