Разделяем игру на классы
Пять классов с чёткими обязанностями — вместо одних глобальных переменных и списков.
Исторический код разделов 21.1–21.7 хранит корабль, врагов и пули как отдельные переменные
и списки Rect, а всю логику — прямо в теле игрового цикла. Это
работает для маленькой игры, но плохо растёт: чем больше правил, тем труднее понять, какой
код за что отвечает. Финальная версия делит игру на пять классов с чёткими обязанностями.
Bullet, Enemy и
Explosion — наследники pygame.sprite.Sprite
(раздел 20.19 уже показал, зачем спрайты нужны: у объекта появляются .image
и .rect, которые понимают готовые функции столкновений и группы).
Хранить их в pygame.sprite.Group, а не в обычном списке, удобно по
той же причине, что и в разделе 21.6: группа сама умеет удалять объект (.kill())
без риска «сломать» цикл перебора, а pygame.sprite.groupcollide()
(раздел 21.15) проверяет столкновения между целыми группами одним вызовом.
class Game:
def __init__(self, *, rng=None, debug=False):
pygame.init()
self.screen = pygame.display.set_mode((SHIRINA, VYSOTA))
self.clock = pygame.time.Clock()
self.assets = AssetStore(IMAGE_DIR, AUDIO_DIR)
self.rng = rng if rng is not None else random.Random()
self.state = GameStatus.MENU
self.bullets = pygame.sprite.Group()
self.enemies = pygame.sprite.Group()
self.explosions = pygame.sprite.Group()
self.player = self._make_player()
self.score = 0
self.lives = STARTING_LIVES
Game — в файле projects/pygame/space-shooter/space_shooter.py, который подробно разбирает раздел 21.25.