Главная страница
Навигация по странице:

  • УПРАЖНЕНИЯ 14.1. Запуск игры клавишей P

  • 14.2. Стрельба по мишени

  • Мэтиз. Изучаем Python. Crash course2 n d e d i t i o na h a n d s o n, p r o j e c t b a s e d i n t r o d u c t i o n t o p r o g r a m m i n g


    Скачать 6.2 Mb.
    НазваниеCrash course2 n d e d i t i o na h a n d s o n, p r o j e c t b a s e d i n t r o d u c t i o n t o p r o g r a m m i n g
    Дата28.06.2022
    Размер6.2 Mb.
    Формат файлаpdf
    Имя файлаМэтиз. Изучаем Python.pdf
    ТипДокументы
    #618322
    страница33 из 52
    1   ...   29   30   31   32   33   34   35   36   ...   52
    УПРАЖНЕНИЯ
    13.6. Конец игры: в упражнении «Боковая стрельба» в коде из упражнения 13.5 (с. 285) подсчитывайте, сколько пришельцев было сбито игроком и сколько раз произошло стол- кновение с кораблем. Определите разумное условие завершения игры и останавливайте игру при возникновении этой ситуации.

    292 Глава 13 • Осторожно, пришельцы!
    Итоги
    В этой главе вы научились добавлять в игру большое количество одинаковых элементов на примере флота пришельцев. Вы узнали, как использовать вложен- ные циклы для создания сетки с элементами, а также привели игровые элементы в движение, вызывая метод update()
    каждого элемента. Вы научились управлять перемещением объектов на экране и обрабатывать различные события (например, достижение края экрана). Вы также узнали, как обнаруживать коллизии и реаги- ровать на них (на примере попадания снарядов в пришельцев и столкновения при- шельцев с кораблем). В завершение главы рассматривалась тема ведения игровой статистики и использования флага game_active для проверки окончания игры.
    В последней главе этого проекта будет добавлена кнопка
    Play
    , чтобы игрок мог самостоятельно запустить свою первую игру, а также повторить игру после ее за- вершения. После каждого уничтожения вражеского флота скорость игры будет возрастать, а мы реализуем систему подсчета очков. В результате вы получите полностью работоспособную игру.

    14
    Ведение счета
    В этой главе построение игры Alien Invasion будет завершено. Мы добавим кнопку
    Play для запуска игры по желанию игрока или перезапуска игры после ее завер- шения. Мы также изменим игру, чтобы она ускорялась при переходе игрока на следующий уровень, а также реализуем систему подсчета очков. К концу главы вы будете знать достаточно, чтобы заняться разработкой игр, сложность которых нарастает по ходу игры и в которых реализована система подсчета очков.
    Добавление кнопки Play
    В этом разделе мы добавим кнопку
    Play
    , которая отображается перед началом игры и появляется после ее завершения, чтобы игрок мог сыграть снова.
    В текущей версии игра начинается сразу же после запуска alien_invasion .py
    . После очередных изменений игра будет запускаться в неактивном состоянии и предла- гать игроку нажать кнопку
    Play для запуска. Для этого включите следующий код в метод
    __init__()
    класса
    GameStats
    :
    game_stats.py
    def __init__(self, ai_game):
    """Инициализирует статистику."""
    self.settings = ai_game.settings self.reset_stats()
    # Игра запускается в неактивном состоянии.
    self.game_active = False
    Итак, программа запускается в неактивном состоянии, а игру можно запустить только нажатием кнопки
    Play
    Создание класса Button
    Так как в Pygame не существует встроенного метода создания кнопок, мы напишем класс
    Button для создания заполненного прямоугольника с текстовой надписью.

    294 Глава 14 • Ведение счета
    Следующий код может использоваться для создания кнопок в любой игре. Ниже приведена первая часть класса
    Button
    ; сохраните ее в файле button .py
    :
    button.py
    import pygame.font class Button():

    def __init__(self, ai_game, msg):
    """Инициализирует атрибуты кнопки."""
    self.screen = ai_game.screen self.screen_rect = self.screen.get_rect()
    # Назначение размеров и свойств кнопок.

    self.width, self.height = 200, 50
    self.button_color = (0, 255, 0)
    self.text_color = (255, 255, 255)

    self.font = pygame.font.SysFont(None, 48)
    # Построение объекта rect кнопки и выравнивание по центру экрана.

    self.rect = pygame.Rect(0, 0, self.width, self.height)
    self.rect.center = self.screen_rect.center
    # Сообщение кнопки создается только один раз.

    self.prep_msg(msg)
    Сначала программа импортирует модуль pygame .font
    , который позволяет Pygame выводить текст на экран. Метод
    __init__()
    получает параметры self
    , объект ai_game и строку msg с текстом кнопки . Размеры кнопки задаются в точке , по- сле чего атрибуты button_color и text_color задаются так, чтобы прямоугольник кнопки был окрашен в ярко-зеленый цвет, а текст выводился белым цветом.
    В точке  происходит подготовка атрибута font для вывода текста. Аргумент
    None сообщает Pygame, что для вывода текста должен использоваться шрифт по умолчанию, а значение
    48
    определяет размер текста. Чтобы выровнять кнопку по центру экрана, мы создаем объект rect для кнопки  и задаем его атрибут center в соответствии с одноименным атрибутом экрана.
    Pygame выводит строку текста в виде графического изображения. В точке  эта задача решается методом
    _prep_msg()
    Код
    _prep_msg()
    выглядит так:
    button.py
    def _prep_msg(self, msg):
    """Преобразует msg в прямоугольник и выравнивает текст по центру."""

    self.msg_image = self.font.render(msg, True, self.text_color,
    self.button_color)
    ❷ self.msg_image_rect = self.msg_image.get_rect()
    self.msg_image_rect.center = self.rect.center

    Добавление кнопки Play 295
    Метод
    _prep_msg()
    должен получать параметр self и текст, который нужно вы- вести в графическом виде (
    msg
    ). Вызов font.render()
    преобразует текст, храня- щийся в msg
    , в изображение, которое затем сохраняется в self.msg_image
    . Ме- тоду font.render()
    также передается логический признак режима сглаживания текста. В остальных аргументах передаются цвет шрифта и цвет фона. В нашем примере режим сглаживания включен (
    True
    ), а цвет фона совпадает с цветом фона кнопки. (Если цвет фона не указан, Pygame пытается вывести шрифт с про- зрачным фоном.)
    В точке  изображение текста выравнивается по центру кнопки, для чего создается объект rect изображения, а его атрибут center приводится в соответствие с одно- именным атрибутом кнопки.
    Остается создать метод draw_button()
    , который может вызываться для отображе- ния кнопки на экране:
    button.py
    def draw_button(self):
    # Отображение пустой кнопки и вывод сообщения.
    self.screen.fill(self.button_color, self.rect)
    self.screen.blit(self.msg_image, self.msg_image_rect)
    Вызов метода screen.fill()
    рисует прямоугольную часть кнопки. Затем вызов screen.blit()
    выводит изображение текста на экран, с передачей изображения и объекта rect
    , связанного с изображением. Класс
    Button готов.
    Вывод кнопки на экран
    В программе класс
    Button используется для создания кнопки
    Play
    . Мы создадим кнопку прямо в файле alien_invasion .py
    :
    alien_invasion.py
    from game_stats import GameStats from button import Button
    Так как нам нужна только одна кнопка
    Play
    , мы создадим ее в методе
    __init__()
    класса
    AlienInvasion
    . Этот код можно разместить в самом конце
    __init__()
    :
    alien_invasion.py
    def __init__(self):
    self._create_fleet()
    # Создание кнопки Play.
    self.play_button = Button(self, "Play")

    296 Глава 14 • Ведение счета
    Программа создает экземпляр
    Button с текстом
    Play
    , но не выводит кнопку на экран. Чтобы кнопка появилась на экране, мы вызовем метод draw_button()
    кнопки в
    _update_screen()
    :
    alien_invasion.py
    def _update_screen(self):
    self.aliens.draw(self.screen)
    # Кнопка Play отображается в том случае, если игра неактивна.
    if not self.stats.game_active:
    self.play_button.draw_button()
    pygame.display.flip()
    Чтобы кнопка
    Play не закрывалась другими элементами экрана, мы отображаем ее после всех остальных игровых элементов, но перед переключением на новый экран. Код заключается в блок if
    , чтобы кнопка отображалась только в неактивном состоянии игры.
    Теперь при запуске Alien Invasion в центре экрана отображается кнопка
    Play
    (рис. 14.1).
    Рис. 14.1. Кнопка Play выводится тогда, когда игра неактивна
    Запуск игры
    Чтобы при нажатии кнопки
    Play запускалась новая игра, добавьте в конец
    _check_
    events()
    следующий блок elif для отслеживания событий мыши над кнопкой:

    Добавление кнопки Play 297
    alien_invasion.py
    def _check_events(self):
    """Обрабатывает нажатия клавиш и события мыши."""
    for event in pygame.event.get():
    if event.type == pygame.QUIT:

    elif event.type == pygame.MOUSEBUTTONDOWN:

    mouse_pos = pygame.mouse.get_pos()

    self._check_play_button(mouse_pos)
    Pygame обнаруживает событие
    MOUSEBUTTONDOWN
    , когда игрок щелкает в любой точке экрана , но мы хотим ограничить игру, чтобы она реагировала только на щелчки на кнопке
    Play
    . Для этого будет использоваться метод pygame.mouse.get_pos()
    , возвращающий кортеж с координатами x
    и y
    точки щелчка . Эти значения пере- даются новому методу
    _check_play_button()
    .
    Ниже приведен код
    _check_play_button()
    , который я решил разместить после
    _check_events()
    :
    alien_invasion.py
    def _check_play_button(self, mouse_pos):
    """Запускает новую игру при нажатии кнопки Play."""

    if self.play_button.rect.collidepoint(mouse_pos):
    self.stats.game_active = True
    Метод collidepoint()
    используется для проверки того, находится ли точка щелчка в пределах области, определяемой прямоугольником кнопки Play . Если точка находится в пределах кнопки, флаг game_active переводится в состояние
    True и игра начинается!
    К этому моменту вы сможете запустить и сыграть полноценную игру. После за- вершения игры значение game_active становится равным
    False
    , а кнопка
    Play снова появится на экране.
    Сброс игры
    Только что написанный нами код работает при первом нажатии кнопки
    Play
    , но не работает после завершения первой игры, потому что условия, приводящие к окон- чанию игры, еще не были сброшены.
    Чтобы игра сбрасывалась при каждом нажатии кнопки
    Play
    , необходимо сбросить игровую статистику, стереть старых пришельцев и снаряды, построить новый флот и вернуть корабль в центр нижней стороны:
    alien_invasion.py
    def _check_play_button(self,mouse_pos):
    """Запускает новую игру при нажатии кнопки Play."""
    if self.play_button.rect.collidepoint(mouse_pos):
    # Сброс игровой статистики.

    298 Глава 14 • Ведение счета

    self.stats.reset_stats()
    self.stats.game_active = True
    # Очистка списков пришельцев и снарядов.

    self.aliens.empty()
    self.bullets.empty()
    # Создание нового флота и размещение корабля в центре.

    self._create_fleet()
    self.ship.center_ship()
    В точке  обновляется игровая статистика, вследствие чего игрок получает три новых корабля. После этого флаг game_active переводится в состояние
    True
    (чтобы игра началась сразу же после выполнения кода функции), группы aliens и bullets очищаются , создается новый флот, а корабль выравнивается по центру .
    После этих изменений игра будет правильно переходить в исходное состояние при каждом нажатии
    Play
    , и вы сможете сыграть столько раз, сколько вам захочется!
    Блокировка кнопки Play
    У кнопки
    Play в нашем приложении есть одна проблема: область кнопки на экране продолжает реагировать на щелчки, даже если кнопка
    Play не отображается. Если случайно щелкнуть на месте кнопки
    Play после начала игры, то игра перезапустится!
    Чтобы исправить этот недостаток, следует запускать игру только в том случае, если флаг game_active находится в состоянии
    False
    :
    alien_invasion.py
    def _check_play_button(self, mouse_pos):
    """Запускает новую игру при нажатии кнопки Play."""

    button_clicked = self.play_button.rect.collidepoint(mouse_pos)

    if button_clicked and not self.stats.game_active:
    # Сброс игровой статистики.
    self.stats.reset_stats()
    Флаг button_clicked содержит значение
    True или
    False
    , а игра перезапускается только в том случае, если пользователь нажал кнопку
    Play и при этом игра неактив- на в настоящий момент . Чтобы протестировать это поведение, запустите новую игру и многократно щелкайте в том месте, где должна находиться кнопка
    Play
    . Если все работает так, как положено, нажатия кнопки
    Play не должны влиять на ход игры.
    Сокрытие указателя мыши
    Указатель мыши должен быть видимым, чтобы пользователь мог начать игру, но после начала игры он только мешает. Чтобы исправить этот недостаток, мы скроем указатель мыши после того, как игра станет активной. Это можно сделать в блоке if в конце
    _check_play_button()
    :

    Повышение сложности 299
    alien_invasion.py
    def _check_play_button(self, mouse_pos):
    """Запускает новую игру при нажатии кнопки Play."""
    button_clicked = self.play_button.rect.collidepoint(mouse_pos)
    if button_clicked and not self.stats.game_active:
    # Указатель мыши скрывается.
    pygame.mouse.set_visible(False)
    Вызов set_visible()
    со значением
    False приказывает Pygame скрыть указатель, когда он находится над окном игры.
    После завершения игры указатель должен появляться снова, чтобы игрок мог на- жать кнопку
    Play для запуска новой игры. Эту задачу решает следующий код:
    alien_invasion.py
    def _ship_hit(self):
    """Обрабатывает столкновение корабля с пришельцем."""
    if self.stats.ships_left > 0:
    else:
    self.stats.game_active = False pygame.mouse.set_visible(True)
    Указатель снова появляется сразу же после того, как игра становится неактивной, что происходит в
    _ship_hit()
    . Внимание к подобным деталям сделает вашу игру более профессиональной, а игрок сможет сосредоточиться на игре вместо того, чтобы разбираться в сложностях пользовательского интерфейса.
    УПРАЖНЕНИЯ
    14.1. Запуск игры клавишей P: так как в Alien Invasion игрок управляет кораблем с кла- виатуры, для запуска игры также лучше использовать клавиатуру. Добавьте код, с которым игрок сможет запустить игру нажатием клавиши
    P
    . Возможно, часть кода из
    _check_play_
    button()
    стоит переместить в функцию start_game()
    , которая будет вызываться из
    _check_
    play_button()
    и
    _check_keydown_events()
    14.2. Стрельба по мишени: создайте у правого края экрана прямоугольник, который двига- ется вверх и вниз с постоянной скоростью. У левого края располагается корабль, который перемещается вверх и вниз игроком и стреляет по движущейся прямоугольной мишени.
    Добавьте кнопку
    Play для запуска игры. После трех промахов игра заканчивается, а на экра- не снова появляется кнопка
    Play
    . Нажатие этой кнопки перезапускает игру.
    Повышение сложности
    В текущей версии после того, как весь флот пришельцев будет уничтожен, игрок переходит на новый уровень, но сложность игры остается неизменной. Давайте немного оживим игру и усложним ее; для этого скорость игры будет повышаться каждый раз, когда игрок уничтожает весь флот.

    300 Глава 14 • Ведение счета
    Изменение настроек скорости
    Начнем с реорганизации класса
    Settings и разделения настроек игры на две кате- гории: постоянные и изменяющиеся. Также необходимо проследить за тем, чтобы настройки, изменяющиеся в ходе игры, сбрасывались в исходное состояние в на- чале новой игры. Метод
    __init__()
    из файла settings .py выглядит так:
    settings.py
    def __init__(self):
    """Инициализирует статические настройки игры."""
    # Настройки экрана self.screen_width = 1200
    self.screen_height = 800
    self.bg_color = (230, 230, 230)
    # Настройки корабля self.ship_limit = 3
    # Настройки снарядов self.bullet_width = 3
    self.bullet_height = 15
    self.bullet_color = 60, 60, 60
    self.bullets_allowed = 3
    # Настройки пришельцев self.fleet_drop_speed = 10
    # Темп ускорения игры

    self.speedup_scale = 1.1

    self.initialize_dynamic_settings()
    Значения, которые остаются неизменными, по-прежнему инициализируются в ме- тоде
    __init__()
    . В точке  добавляется настройка speedup_scale
    , управляющая быстротой нарастания скорости; со значением 2 скорость удваивается каждый раз, когда игрок переходит на следующий уровень, а со значением 1 скорость остается постоянной. С таким значением, как 1,1, скорость будет увеличиваться в достаточ- ной степени, чтобы игра усложнилась, но не стала невозможной. Наконец, вызов initialize_dynamic_settings()
    инициализирует значения атрибутов, которые должны изменяться в ходе игры .
    Код initialize_dynamic_settings()
    выглядит так:
    settings.py
    def initialize_dynamic_settings(self):
    """Инициализирует настройки, изменяющиеся в ходе игры."""
    self.ship_speed_factor = 1.5
    self.bullet_speed_factor = 3.0
    self.alien_speed_factor = 1.0
    # fleet_direction = 1 обозначает движение вправо; а -1 - влево.
    self.fleet_direction = 1

    Повышение сложности 301
    Метод задает исходные значения скоростей корабля, снарядов и пришельцев. Эти скорости будут увеличиваться по ходу игры и сбрасываться каждый раз, когда игрок запускает новую игру. Мы включаем в этот метод fleet_direction
    , чтобы пришельцы в начале новой игры всегда двигались вправо. Увеличивать значение fleet_drop_speed не нужно, потому что когда пришельцы быстрее двигаются по горизонтали, они также будут быстрее перемещаться по вертикали.
    Для увеличения скорости корабля, снарядов и пришельцев каждый раз, когда игрок достигает нового уровня, мы напишем новый метод increase_speed()
    :
    settings.py
    def increase_speed(self):
    """Увеличивает настройки скорости."""
    self.ship_speed_factor *= self.speedup_scale self.bullet_speed_factor *= self.speedup_scale self.alien_speed_factor *= self.speedup_scale
    Чтобы увеличить скорость этих игровых элементов, мы умножаем каждую на- стройку скорости на значение speedup_scale
    Темп игры повышается вызовом increase_speed()
    в check_bullet_alien_
    collisions()
    при уничтожении последнего пришельца во флоте, но перед созда- нием нового флота:
    alien_invasion.py
    def _check_bullet_alien_collisions(self):
    if not self.aliens:
    # Уничтожение снарядов, повышение скорости и создание нового флота.
    self.bullets.empty()
    self._create_fleet()
    self.settings.increase_speed()
    Изменения значений настроек скорости ship_speed
    , alien_speed и bullet_speed достаточно для того, чтобы ускорить всю игру.
    Сброс скорости
    Каждый раз, когда игрок начинает новую игру, все измененные настройки должны вернуться к исходным значениям, иначе каждая новая игра будет начинаться с по- вышенными настройками скорости предыдущей игры:
    1   ...   29   30   31   32   33   34   35   36   ...   52


    написать администратору сайта