Перейти к основному содержимому

Справочник по pygame.sprite


Модуль pygame.sprite собирает игровые объекты в группы, рисует их пакетом и ищет столкновения. Учебная теория с примерами — Разработка игр на Python. Практика на готовых скриптах — мини-игры в Lab.


Содержание


1. Класс Sprite

pygame.sprite.Sprite — базовый класс без графики и логики. Вы наследуете его (class Enemy(pygame.sprite.Sprite)), в __init__ задаёте картинку и позицию, в update — поведение за кадр.

Обязательные поля для отрисовки

ПолеТипСмысл
imagepygame.SurfaceЧто рисуется. Файл — pygame.image.load(), заглушка — pygame.Surface + fill()
rectpygame.RectГде на экране. Обычно self.image.get_rect() и сдвиг center, topleft и т.д.

Подробнее про Surface и Rect — в главе 312.

Управление членством в группах

МетодДействие
add(*groups)Вступить в одну или несколько групп
remove(*groups)Выйти из перечисленных групп
kill()Выйти из всех групп (убрать объект из игры)
alive()True, пока спрайт хотя бы в одной группе
groups()Список групп, где спрайт сейчас состоит

Метод update

МетодДействие
update(*args, **kwargs)Код одного кадра. Group.update() вызывает его у каждого спрайта; аргументы можно передать из главного цикла (all_sprites.update(dt))

Шаблон снаряда

class Bullet(pygame.sprite.Sprite):
def __init__(self, x, y, dx, dy):
super().__init__()
self.image = pygame.Surface((8, 8))
self.image.fill((255, 255, 0))
self.rect = self.image.get_rect(center=(x, y))
self.dx, self.dy = dx, dy

def update(self):
self.rect.x += self.dx
self.rect.y += self.dy
if not screen.get_rect().colliderect(self.rect):
self.kill()

Разбор стрельбы и groupcollideшутер в Lab.


2. Специализированные спрайты

КлассДополнительные поляОбласть применения
DirtySpritedirty, visible, layerИгры с RenderUpdates / LayeredDirty, где перерисовывают только изменившиеся прямоугольники
WeakSpriteслабые ссылки на группыРедкий случай; группа может быть собрана GC, если на неё не осталось сильных ссылок

Поля DirtySprite

ПолеЗначение по умолчаниюПоведение
dirty10 — пропустить кадр; 1 — перерисовать спрайт; 2 — перерисовать и очистить фон под ним
visible10 — не рисовать в draw()
layer0Номер слоя (аналог _layer у LayeredUpdates)

Наследуйте DirtySprite, если в проекте уже используете RenderUpdates или LayeredDirty (§6).


3. Класс Group и наследники

Group — набор спрайтов с общими операциями. Один спрайт может одновременно входить в несколько групп (схема в главе 312).

Методы базового Group

МетодДействие
add(*sprites)Добавить спрайты
remove(*sprites)Удалить спрайты
has(*sprites)Проверить, есть ли спрайт в группе
empty()Очистить группу
sprites()Вернуть список спрайтов
update(*args, **kwargs)Вызвать update() у каждого
draw(surface)Нарисовать все image по координатам rect
clear(surface_dest, background)Закрасить области, где в прошлом кадре работал draw(), цветом или фоновой Surface

clear() удобен для анимированного фона без полного display.flip() каждый кадр.

Специализированные группы

КлассПоведение
GroupSingleХранит только последний добавленный спрайт
OrderedUpdatesdraw() в порядке добавления (поздние — поверх ранних)
LayeredUpdatesdraw() по возрастанию _layer у спрайта
RenderUpdatesКак OrderedUpdates; draw() возвращает список изменённых Rect
LayeredDirtyДля DirtySprite; частичная перерисовка по флагу dirty

Пример LayeredUpdates

class Star(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((4, 4))
self.image.fill((200, 200, 255))
self.rect = self.image.get_rect()
self._layer = 0

class Ship(pygame.sprite.Sprite):
def __init__(self):
super().__init__()
self.image = pygame.Surface((48, 32))
self.image.fill((0, 200, 100))
self.rect = self.image.get_rect(center=(400, 300))
self._layer = 5

all_sprites = pygame.sprite.LayeredUpdates()
# слой можно сменить: all_sprites.change_layer(ship, 20)

Учебный пример с фоном и HUD — глава 312, LayeredUpdates.

RenderUpdates и частичный flip

all_sprites = pygame.sprite.RenderUpdates()
# ... update(), затем:
dirty_rects = all_sprites.draw(screen)
pygame.display.update(dirty_rects)

display.update(rects) обновляет только перечисленные прямоугольники экрана. Имеет смысл при большом статичном фоне. Если каждый кадр заливаете весь экран через screen.fill(), выигрыш небольшой.

GroupSingle

current_weapon = pygame.sprite.GroupSingle()
current_weapon.add(Sword())
current_weapon.add(Gun()) # Sword удалён из группы, остался Gun

Подходит для "текущего оружия", "активного диалога", одного курсора.


4. Функции столкновений

Коллизия — пересечение двух объектов. Хитбокс в Pygame чаще всего совпадает с rect спрайта.

Все функции ниже принимают необязательный collided — функцию (sprite_a, sprite_b) -> bool. Если не передать, Pygame сравнивает прямоугольники rect.

Пара спрайтов (функции-колбэки)

ФункцияЧто сравнивает
collide_rect(a, b)Пересечение rect
collide_circle(a, b)Вписанные окружности в rect
collide_circle_ratio(a, b, ratio)Окружности с радиусом min(w,h)/2 * ratio
collide_mask(a, b)Непрозрачные пиксели по маскам
collide_point(sprite, point)Точка (x, y) внутри rect

Маска — битовая карта непрозрачных пикселей image. Создаётся через pygame.mask.from_surface(surface) или хранится в sprite.mask.

Один спрайт и группа

ФункцияВозвращаетПараметр dokill
spritecollide(sprite, group, dokill, collided=None)Список всех столкнувшихсяTrue — вызвать kill() у каждого из списка
spritecollideany(sprite, group, collided=None)Первый столкнувшийся или None

Две группы

ФункцияВозвращаетdokill1, dokill2
groupcollide(g1, g2, dokill1, dokill2, collided=None){спрайт_из_g1: [спрайты_из_g2]}Удаление из групп для каждой стороны отдельно

Типичная связка — groupcollide(bullets, enemies, True, True) (пошаговый пример).

Пример с маской

class Player(pygame.sprite.Sprite):
def __init__(self, image):
super().__init__()
self.image = image
self.rect = self.image.get_rect()
self.mask = pygame.mask.from_surface(self.image)

hits = pygame.sprite.spritecollide(
player, enemies, False, collided=pygame.sprite.collide_mask
)

Точность и скорость

МетодТочностьСкоростьПримеры в играх
collide_rectПрямоугольник (AABB)ВысокаяПули, тайлы, платформы
collide_circleОкружность в rectВысокаяАстероиды, шары
collide_maskСилуэт PNGНизкаяПлатформер с прыжками на край платформы

На больших уровнях часто делают грубую проверку collide_rect, а collide_mask — только для близких пар.


5. Игровой цикл со спрайтами

Сборка из главы 312:

  1. Каждый тип объекта — класс-наследник Sprite с image, rect, update.
  2. Группа all_sprites — для update() и draw().
  3. Отдельные группы enemies, bullets, pickups — для коллизий.
  4. При создании объекта — sprite.add(all_sprites, enemies) (или нужные группы).
  5. В цикле — события, update, проверки столкновений, draw, flip / update(rects).
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# спавн пуль, меню ...

all_sprites.update()

if pygame.sprite.spritecollideany(player, enemies):
game_over = True

pygame.sprite.groupcollide(bullets, enemies, True, True)

all_sprites.draw(screen)
pygame.display.flip()
clock.tick(60)

Роли групп (один спрайт — несколько списков)

ГруппаЗадача
all_spritesОбщий update() и draw()
enemiesspritecollide(player, enemies, ...)
bulletsgroupcollide(bullets, enemies, ...)
pickupsСбор монет без перебора врагов

Объект в памяти один; группы — разные списки ссылок на него для разных подсистем (игровой цикл, события).


6. Ускорение отрисовки

ЗадачаИнструмент
Стабильный порядок слоёвLayeredUpdates + _layer
Обновить только часть экранаRenderUpdates.draw()display.update(rects)
Перерисовать только движущиеся спрайтыDirtySprite + LayeredDirty
Быстрее искать столкновенияУзкие группы (enemies, не весь all_sprites)
Дорогая маскаcollide_rect на дистанции, collide_mask вблизи

Связь с pygame.display.update и flipокно и поверхности. Ограничение FPS — модуль time.


Связанные материалы