Ссылка на проект занятия (lesson 10.flowballs.zip): https://github.com/selfedu-rus/pygame
На предыдущем
занятии мы с вами сделали небольшой макет игры, в которой шарики падали на
землю. Здесь же разовьем это приложение, добавим телегу, которая будет ловить
наши шары и начисляться соответствующие очки. То есть, у нас должна получиться
практически полноценная игра.
Так вот, чтобы
ловить шары телегой мы должны уметь определять момент столкновения шариков с
тележкой. Для этого в классе
pygame.Rect
имеются
следующие основные методы:
-
collidepoint(x,
y) – проверка попадания точки в прямоугольник;
-
colliderect(Rect)
– проверка пересечения двух прямоугольников;
-
collidelist(list)
– проверка пересечения хотя бы с одним прямоугольником из списка
прямоугольников list;
-
collidelistall(list)
– проверка пересечения со всеми прямоугольниками из списка прямоугольников list.
Полный их список
и описание можно посмотреть на странице официальной документации:
https://www.pygame.org/docs/ref/rect.html
Прежде чем
использовать контроль столкновений, добавим в приложение телегу и ее управление
с помощью курсорных клавиш вправо/влево. Вначале загрузим изображение тележки и
определим ее координаты внизу окна:
telega = pygame.image.load('images/telega.png').convert_alpha()
t_rect = telega.get_rect(centerx=W//2, bottom=H-5)
Затем, перед
главным циклом определим скорость перемещения телеги:
и ее
непосредственное перемещение при нажатии на курсорные клавиши:
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
t_rect.x -= speed
if t_rect.x < 0:
t_rect.x = 0
elif keys[pygame.K_RIGHT]:
t_rect.x += speed
if t_rect.x > W-t_rect.width:
t_rect.x = W-t_rect.width
Далее, выполняем
рисование всех объектов в окне программы:
sc.blit(bg, (0, 0))
balls.draw(sc)
sc.blit(telega, t_rect)
pygame.display.update()
Обратите
внимание на очередность прорисовки. Сначала рисуется фон, затем, шары и в
последнюю очередь тележка. Это важный момент, т.к. полагается, что телега
должна заслонять шары.
Отлично, это мы
сделали. Но шары пока еще не отлавливаются. По логике нашей игры при попадании
шара в телегу игроку должны назначаться очки. Поэтому вначале переопределим
коллекцию balls_data в виде списка словарей:
balls_data = ({'path': 'ball_bear.png', 'score': 100},
{'path': 'ball_fox.png', 'score': 150},
{'path': 'ball_panda.png', 'score': 200})
И, соответственно,
изменим формирование коллекции balls_surf:
balls_surf = [pygame.image.load('images/'+data['path']).convert_alpha() for data in balls_data]
Теперь, в функции
createBall при создании
нового шара будем передавать не только его изображение, но и количество заработанных
очков. Для этого в конструктор передадим еще один параметр balls_data[indx]['score']:
def createBall(group):
indx = randint(0, len(balls_surf)-1)
x = randint(20, W-20)
speed = randint(1, 4)
return Ball(x, speed, balls_surf[indx], balls_data[indx]['score'], group)
И, разумеется,
этот же параметр нужно добавить в конструктор класса Ball:
def __init__(self, x, speed, surf, score, group):
pygame.sprite.Sprite.__init__(self)
self.image = surf
self.rect = self.image.get_rect(center=(x, 0))
self.speed = speed
self.score = score
self.add(group)
Теперь у нас все
готово для отслеживания столкновения шаров с телегой. В рамках данной программы
мы это сделаем с помощью функции:
pygame.Rect.collidepoint( (x, y) )
где (x, y) – центр шара. То есть, как только центр шара оказывается в области телеги, то он считается
пойманным:
Для отслеживания
такого столкновения шаров с телегой объявим вспомогательную функцию:
def collideBalls():
global game_score
for ball in balls:
if t_rect.collidepoint(ball.rect.center):
game_score += ball.score
ball.kill()
Мы здесь в цикле
перебираем группу из падающих шаров balls и для каждого
шара проверяем: попадает ли его центр в прямоугольник телеги t_rect. И если это
так, то увеличиваем число очков и удаляем шар из группы.
Затем, в главный
цикл игры добавляем вызов этой функции (последней строчкой):
Все, мы сделали
контроль столкновения и начисления очков при поимке того или иного шара
телегой.
Осталось
добавить последний штрих – отображать текущее число очков в игровом
пространстве. Для этого, мы загрузим фоновое изображение для очков:
score = pygame.image.load('images/score_fon.png').convert_alpha()
определим шрифт
для отображения цифр:
f = pygame.font.SysFont('arial', 30)
И, затем, в
главном игровом цикле, отобразим всю эту информацию:
sc.blit(bg, (0, 0))
balls.draw(sc)
sc.blit(score, (0, 0))
sc_text = f.render(str(game_score), 1, (94, 138, 14))
sc.blit(sc_text, (20, 10))
sc.blit(telega, t_rect)
pygame.display.update()
Опять же
обратите внимание на последовательность прорисовки: очки отображаются поверх
шаров, т.е. шары не закрывают эту область, а располагаются за ней. В результате
у нас получилась вот такая простая игра ловли шаров.
На следующем
занятии мы добавим звуковые эффекты и завершим это творение.