</>
Topic 6 of 6

Course materials are currently available in Russian only.

Спрайты и «Змейка»

Когда объектов в игре много — звёзды, враги, пули, монеты, — удобно описывать каждый как спрайт, а похожие объединять в группы. Группа сама обновит, нарисует и проверит столкновения для всех своих спрайтов.

Спрайт

Спрайт — класс-наследник pygame.sprite.Sprite с двумя обязательными полями: image (как выглядит) и rect (где находится).

class Enemy(pygame.sprite.Sprite):
    def __init__(self, x, y):
        super().__init__()                       # обязательно
        self.image = pygame.Surface((30, 30))
        self.image.fill((220, 60, 60))
        self.rect = self.image.get_rect(topleft=(x, y))

    def update(self):                            # поведение за один кадр
        self.rect.x += 2

image.get_rect(topleft=…) создаёт прямоугольник по размеру картинки и сразу ставит его в нужную точку.

Группа

enemies = pygame.sprite.Group()
enemies.add(Enemy(0, 0), Enemy(50, 0))

enemies.update()        # вызывает update() у каждого спрайта
enemies.draw(screen)    # рисует image каждого спрайта в его rect
print(len(enemies))     # сколько спрайтов в группе

sprite.kill() убирает спрайт из всех групп. Так убирают объекты, ушедшие за экран, сбитых врагов, собранные монеты. Если забыть их убирать, группа растёт, и игра постепенно тормозит.

Столкновения спрайтов

hits = pygame.sprite.spritecollide(player, enemies, False)   # список врагов, которых касается игрок
hits = pygame.sprite.spritecollide(player, coins, True)      # и сразу убрать их из группы
one = pygame.sprite.spritecollideany(player, enemies)        # любой один или None
pairs = pygame.sprite.groupcollide(bullets, enemies, True, True)   # пули × враги

Третий аргумент dokill решает, убирать ли задетые спрайты. Для бонусов и монет он почти всегда True, иначе один и тот же предмет засчитается каждый кадр, пока игрок на нём стоит.

Игровая логика отдельно от рисования

Самое ценное в игре — правила: что происходит за один шаг. Их удобно писать отдельной функцией, которая получает состояние и возвращает новое, ничего не рисуя. Например, шаг «Змейки»:

  1. вычислить новую клетку головы;
  2. проверить, съедена ли еда;
  3. решить, где будет тело: если еда съедена, хвост остаётся, иначе — последний сегмент уходит;
  4. проверить гибель: выход за поле или столкновение с новым телом;
  5. собрать новую змейку: голова + тело.

Порядок шагов 3 и 4 важен: хвост, который уходит на этом шаге, не препятствие.

Такую функцию легко проверить без окна — именно так и проверяются задачи этого курса.

Итог

  • спрайт: image, rect, update(); super().__init__() обязательно;
  • группа: add, update, draw, len; kill() убирает спрайт;
  • spritecollide(sprite, group, dokill), spritecollideany, groupcollide;
  • правила игры — в отдельной функции «состояние → новое состояние».