Вызов update() для группы (2) приводит к автоматическому вызову update() для каждого спрайта в группе. Строка bullets.update() вызывает bullet.update() для каждой пули, включенной в группу bullets.
В файле game_functions.py необходимо внести изменения в метод check_keydown_events(), чтобы при нажатии клавиши «пробел» происходил выстрел. Изменять check_keyup_events() не нужно, потому что при отпускании клавиши ничего не происходит. Также необходимо изменить update_screen() и вывести каждую пулю на экран перед вызовом flip(). Ниже представлены соответствующие изменения в game_functions.py:
game_functions.py
...
from bullet import Bullet
(1) def check_keydown_events(event, ai_settings, screen, ship, bullets):
...
(2) . .elif event.key == pygame.K_SPACE:
. . . .# Создание новой пули и включение ее в группу bullets.
. . . .new_bullet = Bullet(ai_settings, screen, ship)
. . . .bullets.add(new_bullet)
...
(3)def check_events(ai_settings, screen, ship, bullets):
"""Обрабатывает нажатия клавиш и события мыши."""
for event in pygame.event.get():
...
elif event.type == pygame.KEYDOWN:
. . . . . .check_keydown_events(event, ai_settings, screen, ship, bullets)
...
(4)def update_screen(ai_settings, screen, ship, bullets):
...
. .# Все пули выводятся позади изображений корабля и пришельцев.
(5) . .for bullet in bullets.sprites():
. . . .bullet.draw_bullet()
ship.blitme()
...
Рис. 12.3. Экран игры после серии выстрелов
Группа bullets передается check_keydown_events() (1) . Когда игрок нажимает пробел, создается новая пуля (экземпляр Bullet с именем new_bullet), которая добавляется в группу bullets (2) методом add(); код bullets.add(new_bullet) сохраняет новую пулю в группе bullets.
Группу bullets необходимо добавить в число параметров в определении check_events() (3), а также передать в аргументе при вызове check_keydown_events().
Параметр bullets передается функции update_screen() (4), которая рисует пули на экране. Метод bullets.sprites() возвращает список всех спрайтов в группе bullets. Чтобы нарисовать все выпущенные пули на экране, программа перебирает спрайты в bullets и вызывает для каждого draw_bullet() (5).
Если запустить alien_invasion.py сейчас, вы сможете двигать корабль влево и вправо и выпускать сколько угодно пуль. Пули перемещаются вверх по экрану и исчезают при достижении верхнего края (рис. 12.3). Размер, цвет и скорость пуль можно изменить при помощи настроек в settings.py.
На данный момент пули исчезают по достижении верхнего края, но только потому, что Pygame не может нарисовать их выше края экрана. На самом деле пули продолжают существовать; их координата y продолжает уменьшаться. И это создает проблему, потому что пули продолжают потреблять память и вычислительные мощности.
От старых пуль необходимо избавиться, иначе игра замедлится из-за большого объема лишней работы. Для этого необходимо определить момент, когда атрибут bottom прямоугольника пули достигнет 0, — это означает, что пуля вышла за верхний край экрана:
alien_invasion.py
# Запуск основного цикла игры.
while True:
gf.check_events(ai_settings, screen, ship, bullets)
ship.update()
bullets.update()
. .
. . . .# Удаление пуль, вышедших за край экрана.
(1) . . . .for bullet in bullets.copy():
(2) . . . . . .if bullet.rect.bottom <= 0:
(3) . . . . . . . . bullets.remove(bullet)
(4) . . . .print(len(bullets))
gf.update_screen(ai_settings, screen, ship, bullets)
Удалять элементы из списка или группы в цикле for не следует, поэтому перебирать нужно копию группы. Метод copy() используется для создания цикла for (1) , в котором возможно изменять содержимое bullets. Программа проверяет каждую пулю и определяет, вышла ли она за верхний край экрана (2). Если пуля пересекла границу, она удаляется из bullets (3). В точке (4) добавляется команда print, которая сообщает, сколько пуль сейчас существует в игре; по выведенному значению можно убедиться в том, что пули действительно были удалены.
Если код работает правильно, вы можете понаблюдать за выводом на терминале и убедиться в том, что количество пуль уменьшается до 0 после того, как очередной залп уходит за верхний край экрана. После того как вы запустите игру и убедитесь в том, что пули правильно удаляются из группы, удалите команду print. Если команда останется в программе, она существенно замедлит игру, потому что вывод на терминал занимает больше времени, чем отображение графики в игровом окне.
Многие игры-«стрелялки» ограничивают количество пуль, одновременно находящихся на экране, чтобы у игроков появился стимул стрелять более метко. То же самое будет сделано и в игре Alien Invasion.
Сначала сохраним максимально допустимое количество пуль в settings.py:
settings.py
# Параметры пули
self.bullet_width = 3
self.bullet_height = 15
self.bullet_color = 60, 60, 60
self.bullets_allowed = 3