Справочник по pygame.sprite
Модуль pygame.sprite собирает игровые объекты в группы, рисует их пакетом и ищет столкновения. Учебная теория с примерами — Разработка игр на Python. Практика на готовых скриптах — мини-игры в Lab.
Содержание
- 1. Класс Sprite
- 2. Специализированные спрайты
- 3. Класс Group и наследники
- 4. Функции столкновений
- 5. Игровой цикл со спрайтами
- 6. Ускорение отрисовки
- Связанные материалы
1. Класс Sprite
pygame.sprite.Sprite — базовый класс без графики и логики. Вы наследуете его (class Enemy(pygame.sprite.Sprite)), в __init__ задаёте картинку и позицию, в update — поведение за кадр.
Обязательные поля для отрисовки
| Поле | Тип | Смысл |
|---|---|---|
image | pygame.Surface | Что рисуется. Файл — pygame.image.load(), заглушка — pygame.Surface + fill() |
rect | pygame.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. Специализированные спрайты
| Класс | Дополнительные поля | Область применения |
|---|---|---|
DirtySprite | dirty, visible, layer | Игры с RenderUpdates / LayeredDirty, где перерисовывают только изменившиеся прямоугольники |
WeakSprite | слабые ссылки на группы | Редкий случай; группа может быть собрана GC, если на неё не осталось сильных ссылок |
Поля DirtySprite
| Поле | Значение по умолчанию | Поведение |
|---|---|---|
dirty | 1 | 0 — пропустить кадр; 1 — перерисовать спрайт; 2 — перерисовать и очистить фон под ним |
visible | 1 | 0 — не рисовать в draw() |
layer | 0 | Номер слоя (аналог _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 | Хранит только последний добавленный спрайт |
OrderedUpdates | draw() в порядке добавления (поздние — поверх ранних) |
LayeredUpdates | draw() по возрастанию _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:
- Каждый тип объекта — класс-наследник
Spriteсimage,rect,update. - Группа
all_sprites— дляupdate()иdraw(). - Отдельные группы
enemies,bullets,pickups— для коллизий. - При создании объекта —
sprite.add(all_sprites, enemies)(или нужные группы). - В цикле — события,
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() |
enemies | spritecollide(player, enemies, ...) |
bullets | groupcollide(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.
Связанные материалы
- Разработка игр на Python — теория, игровой цикл, поверхности, анимация sprite sheet
- Pygame — мини-игры — змейка, Pong, шутер, Breakout
- Практикум разработки игр — Tetris, Match3, Space Invaders
- Разработка игр — о разделе — контекст индустрии
- Справочник по Python — язык и стандартная библиотека
- ООП в Python — наследование классов спрайтов