Вывод количества кораблей

We use cookies. Read the Privacy and Cookie Policy

Остается вывести количество кораблей, оставшихся у игрока, но на этот раз информация будет выводиться в графическом виде. Как во многих классических аркадных играх, в левом верхнем углу экрана программа рисует несколько изображений корабля. Каждый корабль обозначает одну оставшуюся попытку.

Для начала нужно сделать так, чтобы класс Ship наследовал от Sprite, — это необходимо для создания группы кораблей:

ship.py

import pygame

from pygame.sprite import Sprite

(1) class Ship(Sprite):

. .

def __init__(self, ai_settings, screen):

"""Инициализирует корабль и задает его начальную позицию."""

(2) . . . .super(Ship, self).__init__()

...

Здесь мы импортируем Sprite, объявляем о наследовании Ship от Sprite (1) и вызываем super() в начале __init__() (2).

Далее необходимо изменить Scoreboard и создать группу кораблей для вывода на экран. Команды import и метод __init__() выглядят так:

scoreboard.py

import pygame.font

from pygame.sprite import Group

from ship import Ship

class Scoreboard():

"""Класс для вывода игровой информации."""

def __init__(self, ai_settings, screen, stats):

...

self.prep_level()

. . . .self.prep_ships()

...

Так как мы собираемся создать группу кораблей, программа импортирует классы Group и Ship. Метод prep_ships() будет вызываться после prep_level(). Он выглядит так:

scoreboard.py

. .def prep_ships(self):

. . . ."""Сообщает количество оставшихся кораблей."""

(1) . . . .self.ships = Group()

(2) . . . .for ship_number in range(self.stats.ships_left):

. . . . . .ship = Ship(self.ai_settings, self.screen)

(3) . . . . . .ship.rect.x = 10 + ship_number * ship.rect.width

(4) . . . . . .ship.rect.y = 10

(5) . . . . . .self.ships.add(ship)

Метод prep_ships() создает пустую группу self.ships для хранения экземпляров кораблей (1) . В ходе заполнения этой группы цикл выполняется по одному разу для каждого корабля, оставшегося у игрока (3). В цикле создается новый корабль, а координата x этого корабля задается так, чтобы корабли размещались рядом друг с другом, разделенные интервалами величиной 10 пикселов (3). Координата y задается так, чтобы корабли были смещены на 10 пикселов от верхнего края экрана и были выровнены по изображению текущего счета (4). Наконец, каждый корабль добавляется в группу ships (5).

Следующим шагом становится вывод кораблей на экран:

scoreboard.py

def show_score(self):

...

self.screen.blit(self.level_image, self.level_rect)

. .# Вывод кораблей.

. .self.ships.draw(self.screen)

При выводе кораблей на экран мы вызываем метод draw() для группы, а Pygame рисует каждый отдельный корабль.

Чтобы игрок видел, сколько попыток у него в начале игры, мы вызываем prep_ships() при запуске новой игры. Это происходит в функции check_play_button() из файла game_functions.py:

game_functions.py

def check_play_button(ai_settings, screen, stats, sb, play_button, ship,

aliens, bullets, mouse_x, mouse_y):

"""Запускает новую игру при нажатии кнопки Play."""

button_clicked = play_button.rect.collidepoint(mouse_x, mouse_y)

if button_clicked and not stats.game_active:

...

# Сброс изображений счетов и уровня.

sb.prep_score()

sb.prep_high_score()

sb.prep_level()

. . . .sb.prep_ships()

...

Метод prep_ships() также вызывается при столкновении пришельца с кораблем, чтобы изображение обновлялось при потере корабля:

game_functions.py

(1) def update_aliens(ai_settings, screen, stats, sb, ship, aliens, bullets):

...

# Проверка коллизий "пришелец-корабль".

if pygame.sprite.spritecollideany(ship, aliens):

(2) . . . .ship_hit(ai_settings, screen, stats, sb, ship, aliens, bullets)

. .

# Проверяет, добрались ли пришельцы до нижнего края экрана.

(3) . .check_aliens_bottom(ai_settings, screen, stats, sb, ship, aliens, bullets)

(4)def ship_hit(ai_settings, screen, stats, sb, ship, aliens, bullets):

"""Обрабатывает столкновение корабля с пришельцем."""

if stats.ships_left > 0:

# Уменьшение ships_left.

stats.ships_left -= 1

. . . .

. . . .# Обновление игровой информации.

(5) . . . .sb.prep_ships()

# Очистка списков пришельцев и пуль.

...

Сначала параметр sb добавляется в определение update_aliens() (1) . Затем программа передает sb функциям ship_hit() (2) и check_aliens_bottom(), чтобы эти функции имели доступ к объекту Scoreboard (3).

Затем определение ship_hit() изменяется с включением sb (4). Метод prep_ships() вызывается после уменьшения значения ships_left (5), так что при каждой потере корабля выводится правильное количество изображений.

Вызов ship_hit() также включен в check_aliens_bottom(), так что эту функцию тоже нужно обновить:

game_functions.py

def check_aliens_bottom(ai_settings, screen, stats, sb, ship, aliens,

. . . .bullets):

"""Проверяет, добрались ли пришельцы до нижнего края экрана."""

screen_rect = screen.get_rect()

for alien in aliens.sprites():

if alien.rect.bottom >= screen_rect.bottom:

# Происходит то же, что при столкновении с кораблем.

. . . . . .ship_hit(ai_settings, screen, stats, sb, ship, aliens, bullets)

break

Так как check_aliens_bottom() теперь получает параметр sb, мы добавляем аргумент sb в вызов ship_hit().

Остается добавить sb в вызов update_aliens() в файле alien_invasion.py:

alien_invasion.py

# Запуск основного цикла игры.

while True:

...

if stats.game_active:

ship.update()

gf.update_bullets(ai_settings, screen, stats, sb, ship, aliens,

bullets)

. . . .gf.update_aliens(ai_settings, screen, stats, sb, ship, aliens,

. . . . . .bullets)

...

На рис. 14.6 показана полная игровая информация на экране, с количеством оставшихся кораблей в левой верхней части экрана.

Рис. 14.6. Полная игровая информация в Alien Invasion

Упражнения

14-4. Исторический рекорд: в текущей версии рекорд сбрасывается каждый раз, когда игрок закрывает и перезапускает Alien Invasion. Чтобы этого не происходило, запишите рекорд в файл перед вызовом sys.exit() и загрузите его при инициализации значения в GameStats.

14-5. Рефакторинг: найдите функции и методы, которые решают более одной задачи, и проведите рефакторинг, улучшающий структуру и эффективность кода. Например, переместите часть кода функции check_bullet_alien_collisions(), которая запускает новый уровень при уничтожении флота, в функцию start_new_level(). Также переместите четыре метода, вызываемых в методе __init__() класса Scoreboard, в метод prep_images() для сокращения длины __init__(). Метод prep_images() также может оказать помощь check_play_button() или start_game(), если вы уже провели рефакторинг check_play_button().

примечание

Прежде чем браться за рефакторинг проекта, обратитесь к приложению Г. В нем рассказано, как восстановить рабочее состояние проекта, если в ходе рефакторинга были допущены ошибки.

14-6. Расширение Alien Invasion: подумайте над возможными расширениями Alien Invasion. Например, пришельцы тоже могут стрелять по кораблю, или же вы можете добавить укрытия, за которыми может скрываться корабль (укрытия могут разрушаться пулями с обеих сторон). Или добавьте звуковые эффекты (например, взрывы или звуки выстрелов) средствами модуля pygame.mixer.