Библиотека Pygame / Часть 2. Работа со спрайтами
Вторая часть серии руководств «Разработка игр с помощью Pygame». Она предназначена для программистов начального и среднего уровней, которые заинтересованы в создании игр и улучшении собственных навыков кодирования на Python. Начать стоит с урока: «Библиотека Pygame / Часть 1. Введение».
Что такое спрайт?
Спрайт — это элемент компьютерной графики, представляющий объект на экране, который может двигаться. В двухмерной игре все, что вы видите на экране, является спрайтами. Спрайты можно анимировать, заставлять их взаимодействовать между собой или передавать управление ими игроку.
Для загрузки и отрисовки спрайтов в случай этой игры их нужно добавить в разделы “Обновление” и “Визуализация” игрового цикла. Несложно представить, что если в игре много спрайтов, то цикл довольно быстро станет большим и запутанным. В Pygame для этого есть решение: группировка спрайтов.
Набор спрайтов — это коллекция спрайтов, которые могут отображаться одновременно. Вот как нужно создавать группу спрайтов в игре:
clock = pygame.time.Clock() all_sprites = pygame.sprite.Group()
Теперь этой возможностью можно воспользоваться, добавив группу целиком в цикл:
# Обновление all_sprites.update() <span style="box-sizing: border-box; font-weight: inherit !important; font-size: inherit; padding-left: 0px; color: rgb(243, 228, 203);" class="token comment"># Отрисовка</span> screen<span style="box-sizing: border-box; font-weight: inherit !important; font-size: inherit; color: rgb(255, 255, 238);" class="token punctuation">.</span>fill<span style="box-sizing: border-box; font-weight: inherit !important; font-size: inherit; color: rgb(255, 255, 238);" class="token punctuation">(</span>BLACK<span style="box-sizing: border-box; font-weight: inherit !important; font-size: inherit; color: rgb(255, 255, 238);" class="token punctuation">)</span> all_sprites<span style="box-sizing: border-box; font-weight: inherit !important; font-size: inherit; color: rgb(255, 255, 238);" class="token punctuation">.</span>draw<span style="box-sizing: border-box; font-weight: inherit !important; font-size: inherit; color: rgb(255, 255, 238);" class="token punctuation">(</span>screen<span style="box-sizing: border-box; font-weight: inherit !important; font-size: inherit; color: rgb(255, 255, 238);" class="token punctuation">)</span>
Теперь при создании каждого спрайта, главное убедиться, что он добавлен в группу all_sprites. Такой спрайт будет автоматически отрисован на экране и обновляться в цикле.
Создание спрайта
Можно переходить к созданию первого спрайта. В Pygame все спрайты выступают объектами. Если вы не работали с этим типом данных в Python, то для начала достаточно знать, что это удобный способ группировки данных и кода в единую сущность. Поначалу это может путать, но спрайты Pygame — отличная возможность попрактиковаться в работе с объектами и понять, как они работают.
Начнем с определения нового спрайта:
class Player(pygame.sprite.Sprite):
class сообщает Python, что определяется новый объект, который будет спрайтом игрока. Его тип pygame.sprite.Sprite. Это значит, что он будет основан на заранее определенном в Pygame классе Sprite.
Первое, что нужно в определении class — специальная функция init(), включающая код, который будет запущен при создании нового объекта этого типа. Также у каждого спрайта в Pygame должно быть два свойства: image и rect.
class Player(pygame.sprite.Sprite): def init(self): pygame.sprite.Sprite.init(self) self.image = pygame.Surface((50, 50)) self.image.fill(GREEN) self.rect = self.image.get_rect()
Первая строка, Pygame.sprite.Sprite.__init__(self) требуется в Pygame — она запускает инициализатор встроенных классов Sprite. Далее необходимо определить свойство image. Сейчас просто создадим квадрат размером 50х50 и заполним его зеленым (GREEN) цветом. Чуть позже вы узнаете, как сделать image спрайта красивее, используя, например, персона��а или космический корабль, но сейчас достаточно сплошного квадрата.
Дальше необходимо определить rect спрайта. Это сокращенное от rectangle (прямоугольник). Прямоугольники повсеместно используются в Pygame для отслеживания координат объектов. Команда get_rect() оценивает изображение image и высчитывает прямоугольник, способный окружить его.
rect можно использовать для размещения спрайта в любом месте. Начнем с создания спрайта по центру:
class Player(pygame.sprite.Sprite): def __init__(self): pygame.sprite.Sprite.__init__(self) self.image = pygame.Surface((50, 50)) self.image.fill(GREEN) self.rect = self.image.get_rect() self.rect.center = (WIDTH / 2, HEIGHT / 2)
Теперь, после определения спрайта игрока Player, нужно отрисовать (создать) его, инициализировав экземпляр (instance) класса Player. Также нужно обязательно добавить спрайт в группу all_sprites.
all_sprites = pygame.sprite.Group() player = Player() all_sprites.add(player)
Сейчас, если запустить программу, по центру окна будет находиться зеленый квадрат. Увеличьте значения WIDTH и HEIGHT в настройках программы, чтобы создать достаточно пространства для движения спрайта в следующем шаге.
Движение спрайта
В игровом цикле есть функция all_sprites.update(). Это значит, что для каждого спрайта в группе Pygame ищет функцию update() и запускает ее. Чтобы спрайт двигался, нужно определить его правила обновления:
class Player(pygame.sprite.Sprite): def __init__(self): pygame.sprite.Sprite.__init__(self) self.image = pygame.Surface((50, 50)) self.image.fill(GREEN) self.rect = self.image.get_rect() self.rect.center = (WIDTH / 2, HEIGHT / 2) <span style="box-sizing: border-box; font-weight: inherit !important; font-size: inherit; color: rgb(128, 255, 255);" class="token keyword keyword-def">def</span> <span style="box-sizing: border-box; font-weight: inherit !important; font-size: inherit; color: rgb(255, 128, 176);" class="token function">update</span><span style="box-sizing: border-box; font-weight: inherit !important; font-size: inherit; color: rgb(255, 255, 238);" class="token punctuation">(</span>self<span style="box-sizing: border-box; font-weight: inherit !important; font-size: inherit; color: rgb(255, 255, 238);" class="token punctuation">)</span><span style="box-sizing: border-box; font-weight: inherit !important; font-size: inherit; color: rgb(255, 255, 238);" class="token punctuation">:</span> self<span style="box-sizing: border-box; font-weight: inherit !important; font-size: inherit; color: rgb(255, 255, 238);" class="token punctuation">.</span>rect<span style="box-sizing: border-box; font-weight: inherit !important; font-size: inherit; color: rgb(255, 255, 238);" class="token punctuation">.</span>x <span style="box-sizing: border-box; font-weight: inherit !important; font-size: inherit; color: rgb(255, 222, 164);" class="token operator">+=</span> <span style="box-sizing: border-box; font-weight: inherit !important; font-size: inherit; color: rgb(255, 148, 255);" class="token number">5</span>
Это значит, что при каждом игровом цикле x-координата спрайта будет увеличиваться на 5 пикселей. Запустите программу, чтобы посмотреть, как он скрывается за пределами экрана, достигая правой стороны.
Исправить это можно, заставив спрайт двигаться по кругу — когда он добирается до правой стороны экрана, просто переносить его влево. Это легко сделать, используя элемент управления rect спрайта:
Так, если левая сторона rect пропадает с экрана, просто задаем значение правого края равное 0:
class Player(pygame.sprite.Sprite): def __init__(self): pygame.sprite.Sprite.__init__(self) self.image = pygame.Surface((50, 50)) self.image.fill(GREEN) self.rect = self.image.get_rect() self.rect.center = (WIDTH / 2, HEIGHT / 2) <span style="box-sizing: border-box; font-weight: inherit !important; font-size: inherit; color: rgb(128, 255, 255);" class="token keyword keyword-def">def</span> <span style="box-sizing: border-box; font-weight: inherit !important; font-size: inherit; color: rgb(255, 128, 176);" class="token function">update</span><span style="box-sizing: border-box; font-weight: inherit !important; font-size: inherit; color: rgb(255, 255, 238);" class="token punctuation">(</span>self<span style="box-sizing: border-box; font-weight: inherit !important; font-size: inherit; color: rgb(255, 255, 238);" class="token punctuation">)</span><span style="box-sizing: border-box; font-weight: inherit !important; font-size: inherit; color: rgb(255, 255, 238);" class="token punctuation">:</span> self<span style="box-sizing: border-box; font-weight: inherit !important; font-size: inherit; color: rgb(255, 255, 238);" class="token punctuation">.</span>rect<span style="box-sizing: border-box; font-weight: inherit !important; font-size: inherit; color: rgb(255, 255, 238);" class="token punctuation">.</span>x <span style="box-sizing: border-box; font-weight: inherit !important; font-size: inherit; color: rgb(255, 222, 164);" class="token operator">+=</span> <span style="box-sizing: border-box; font-weight: inherit !important; font-size: inherit; color: rgb(255, 148, 255);" class="token number">5</span> <span style="box-sizing: border-box; font-weight: inherit !important; font-size: inherit; color: rgb(128, 255, 255);" class="token keyword keyword-if">if</span> self<span style="box-sizing: border-box; font-weight: inherit !important; font-size: inherit; color: rgb(255, 255, 238);" class="token punctuation">.</span>rect<span style="box-sizing: border-box; font-weight: inherit !important; font-size: inherit; color: rgb(255, 255, 238);" class="token punctuation">.</span>left <span style="box-sizing: border-box; font-weight: inherit !important; font-size: inherit; color: rgb(255, 222, 164);" class="token operator">></span> WIDTH<span style="box-sizing: border-box; font-weight: inherit !important; font-size: inherit; color: rgb(255, 255, 238);" class="token punctuation">:</span> self<span style="box-sizing: border-box; font-weight: inherit !important; font-size: inherit; color: rgb(255, 255, 238);" class="token punctuation">.</span>rect<span style="box-sizing: border-box; font-weight: inherit !important; font-size: inherit; color: rgb(255, 255, 238);" class="token punctuation">.</span>right <span style="box-sizing: border-box; font-weight: inherit !important; font-size: inherit; color: rgb(255, 222, 164);" class="token operator">=</span> <span style="box-sizing: border-box; font-weight: inherit !important; font-size: inherit; color: rgb(255, 148, 255);" class="token number">0</span>
Теперь можно видеть, как спрайт будто бы двигается по кругу.
На этом все. Отправляйтесь изучать и экспериментировать, но не забывайте, что все, что вы помещаете в метод update(), будет происходить в каждом кадре. Попробуйте научить спрайт двигаться сверху вниз (изменив координату y) или заставить его отталкиваться от стен (изменяя направлении по достижении края).
