Игра «Космические захватчики» на Python: Часть 1


ИГРА КОСМИЧЕСКИЕ ЗАХВАТЧИКИ В PYTHON

Это учебник по проекту на языке python с использованием pygame

Предварительные требования
Для работы над этим проектом вам понадобятся:

  • Базовое понимание синтаксиса Python3
  • Уверенное понимание классов в python
  • Уверенное понимание функций в python
  • Установленный PygameВот и все


Чтобы получить доступ к полному исходному коду проекта и файлам, посетите репозиторий на Github.

Pygame

Pygame — это коллекция мощных модулей python, которые управляют анимацией, графикой и даже звуком для создания мощных приложений, таких как игры и т.д.

УСТАНОВКА PYGAME

Чтобы установить pygame на свой компьютер, откройте терминал и выполните команду

После установки pygame вы можете начать использовать его в своих программах, импортируя его.

Теперь мы готовы к работе

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

Начало игрового проекта

Мы начнем создание игры с создания пустого окна Pygame. Позже
мы нарисуем элементы игры, такие как корабль и пришельцы, в этом окне.
доу. Мы также заставим нашу игру реагировать на ввод пользователя, установим цвет фона
и загружать изображение корабля.

Создание окна Pygame и реакция на ввод пользователя

Мы создадим пустое окно Pygame, создав класс для представления
игру

import sys

import pygame

class AlienInvasion:

    """Overall class to manage game assets and behavior."""

    def __init__(self):

        """Initialize the game, and create game resources."""

        pygame.init()

        self.screen = pygame.display.set_mode((1200, 800))  # Attribute representing the game window

        pygame.display.set_caption("Alien Invasion")

    def run_game(self):

        """Start the main loop for the game."""

        while True:

            # Watch for keyboard and mouse events.

            for event in pygame.event.get():

                if event.type == pygame.QUIT:

                sys.exit()

            # Make the most recently drawn screen visible.

            pygame.display.flip()

if __name__ == '__main__':

    # Make a game instance, and run the game.

    ai = AlienInvasion()

    ai.run_game()
Вход в полноэкранный режим Выход из полноэкранного режима

Сначала мы импортируем модули sys и pygame.
Модуль pygame содержит функциональность, необходимую для создания игры. Модуль sys содержит инструменты для выхода из игры, когда игрок выходит из игры.
Alien Invasion начинается как класс под названием AlienInvasion. В init()
функция pygame.init() инициализирует фоновые настройки, которые необходимы Pygame для правильной работы.
Pygame необходимы для правильной работы. Затем мы вызываем pygame.display.set_mode(), чтобы
создать окно дисплея, на котором мы будем рисовать все графические элементы игры. Аргумент (1200, 800) представляет собой кортеж, определяющий размеры
игрового окна, которое будет иметь размеры 1200 пикселей в ширину и 800 пикселей в высоту. (Вы
можете изменить эти значения в зависимости от размера вашего дисплея.) Мы присваиваем это
игровое окно атрибуту self.screen, поэтому оно будет доступно во всех методах
в классе.

Объект, который мы присвоили self.screen, называется поверхностью. Поверхность в
Pygame — это часть экрана, на которой может отображаться игровой элемент.
Каждый элемент в игре, например, инопланетянин или корабль, является своей собственной поверхностью. Поверхность
поверхность, возвращаемая display.set_mode(), представляет собой все игровое окно.
Когда мы активируем цикл анимации игры, эта поверхность будет перерисовываться
при каждом проходе через цикл, поэтому она может быть обновлена с учетом любых изменений, вызванных вводом пользователем.
вызванные вводом данных пользователем.

Игра управляется методом run_game(). Этот метод содержит
цикл while, который выполняется непрерывно. Цикл while содержит цикл событий
и код, управляющий обновлением экрана. Событие — это действие, которое пользователь
выполняет во время игры, например, нажимает клавишу или перемещает мышь.
мышь. Чтобы заставить нашу программу реагировать на события, мы пишем цикл событий, чтобы
прослушивать события и выполнять соответствующие задачи в зависимости от типа
событий, которые происходят. Цикл for в строке (76) является циклом событий.
Для доступа к событиям, которые обнаруживает Pygame, мы будем использовать функцию pygame.event.get(). Эта функция возвращает список событий, которые произошли
с момента последнего вызова этой функции. Любое событие клавиатуры или мыши
приведет к запуску цикла for. Внутри цикла мы напишем серию операторов if
для обнаружения и реагирования на определенные события. Например, когда
игрок нажимает на кнопку закрытия окна игры, обнаруживается событие pygame.QUIT
и мы вызываем sys.exit() для выхода из игры.

Вызов pygame.display.flip() указывает Pygame сделать видимым последний
последний нарисованный экран видимым. В данном случае он просто рисует пустой экран
при каждом проходе через цикл while, стирая старый экран, чтобы был виден только новый.
чтобы был виден только новый экран. Когда мы перемещаем игровые элементы, pygame.display.flip() постоянно обновляет экран, показывая новые позиции игровых элементов и скрывая старые.
элементов и скрывает старые, создавая иллюзию плавного движения.

В конце файла мы создаем экземпляр игры, а затем вызываем функцию
run_game(). Мы помещаем run_game() в блок if, который запускается только в том случае, если файл
вызывается напрямую. Когда вы запустите этот файл alien_invasion.py, вы должны увидеть
пустое окно Pygame.

Установка цвета фона

По умолчанию Pygame создает черный экран. Мы можем установить другой цвет фона. Мы сделаем это в конце метода init().

def __init__(self):
    --snip--
    pygame.display.set_caption("Alien Invasion")
    # Set the background color.
    self.bg_color = (230, 230, 230)

def run_game(self):
    --snip--
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
        sys.exit()
    # Redraw the screen during each pass through the loop.
    self.screen.fill(self.bg_color)
Вход в полноэкранный режим Выход из полноэкранного режима

Цвета в Pygame задаются как цвета RGB: смесь красного, зеленого,
и синего. Значение каждого цвета может варьироваться от 0 до 255. Значение цвета (255,
0, 0) — красный, (0, 255, 0) — зеленый, а (0, 0, 255) — синий. Вы можете смешивать различные
значения RGB для создания до 16 миллионов цветов. Значение цвета (230, 230,
230) смешивает равные количества красного, синего и зеленого цветов, что дает светло
серый цвет фона. Мы присваиваем этот цвет self.bg_color в строке (146).
В строке (154) мы заполняем экран фоновым цветом с помощью метода fill()
который действует на поверхности и принимает только один аргумент: цвет.

Создание класса настроек

Каждый раз, когда мы вводим в игру новую функциональность, мы обычно
создаем и новые настройки. Вместо того чтобы добавлять настройки по всему
код, давайте напишем модуль под названием settings, который будет содержать класс под названием
Settings для хранения всех этих значений в одном месте. Такой подход позволяет нам
работать только с одним объектом настроек каждый раз, когда нам нужно получить доступ к отдельным
настройке. Это также облегчает модификацию внешнего вида и
поведение по мере роста нашего проекта: чтобы изменить игру, мы просто изменим
некоторые значения в файле settings.py, который мы создадим далее, вместо того, чтобы искать
различные настройки по всему проекту.

class Settings:

"""A class to store all settings for Alien Invasion."""

    def __init__(self):

        """Initialize the game's settings."""

        # Screen settings

        self.screen_width = 1200

        self.screen_height = 800

        self.bg_color = (230, 230, 230)

Вход в полноэкранный режим Выход из полноэкранного режима

Затем нам нужно будет создать экземпляр Settings в проекте и использовать его для доступа к нашим настройкам, изменив alien_invasion.py следующим образом:

# AlienInvasion.py 
import pygame

from settings import Settings

class AlienInvasion:

    """Overall class to manage game assets and behavior."""

    def __init__(self):

        """Initialize the game, and create game resources."""

        pygame.init()

        self.settings = Settings()

        self.screen = pygame.display.set_mode((self.settings.screen_width, 
        self.settings.screen_height))

        pygame.display.set_caption("Alien Invasion")

    def run_game(self):

        --snip--
        # Redraw the screen during each pass through the loop.

        self.screen.fill(self.settings.bg_color)

        # Make the most recently drawn screen visible.

        pygame.display.flip()
Войти в полноэкранный режим Выйти из полноэкранного режима

Мы импортируем Settings в основной файл программы. Затем мы создаем
экземпляр Settings и присваиваем его self.settings в строке (212), после вызова pygame.init(). Когда мы создаем экран, мы используем атрибуты screen_width и
screen_width и screen_height атрибуты self.settings, а затем мы используем self.settings для
доступа к цвету фона при заполнении экрана.
Когда вы запустите alien_invasion.py сейчас, вы еще не увидите никаких изменений,
потому что все, что мы сделали, это переместили настройки, которые мы уже использовали, в другое место.
куда. Теперь мы готовы начать добавлять новые элементы на экран.

Добавление изображения корабля

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

Вы можете создать папку images и добавить в нее изображение корабля (рекомендуется растровое изображение).

Создание класса «Корабль

После выбора изображения для корабля нам нужно отобразить его на экране. Чтобы
использовать наш корабль, мы создадим новый модуль корабля, который будет содержать класс Ship.
Этот класс будет управлять большей частью поведения корабля игрока:

#ship.py
import pygame

class Ship:
    """A class to manage the ship."""

    def __init__(self, ai_game):

        """Initialize the ship and set its starting position."""

        self.screen = ai_game.screen

        self.screen_rect = ai_game.screen.get_rect()

        # Load the ship image and get its rect.

        self.image = pygame.image.load('images/ship.bmp')

        self.rect = self.image.get_rect()

        # Start each new ship at the bottom center of the screen.

        self.rect.midbottom = self.screen_rect.midbottom

    def blitme(self):

        """Draw the ship at its current location."""

        self.screen.blit(self.image, self.rect)

Вход в полноэкранный режим Выход из полноэкранного режима

Pygame эффективен, потому что позволяет обращаться со всеми элементами как с прямоугольниками (rects), даже если они не совсем прямоугольной формы. Обращение с элементом как с прямоугольником эффективно, потому что прямоугольники — это простые геометрические фигуры. Например, когда Pygame нужно выяснить, столкнулись ли два элемента, он может сделать это быстрее, если будет рассматривать каждый объект как прямоугольник. Такой подход обычно работает достаточно хорошо, чтобы никто из играющих не заметил, что мы не работаем с точной формой каждого элемента игры. В этом классе мы будем рассматривать корабль и экран как прямоугольники.

Перед определением класса мы импортируем модуль pygame. Метод init()
метода Ship принимает два параметра: ссылку на себя и ссылку на
текущий экземпляр класса AlienInvasion. Это даст Ship доступ ко
всем игровым ресурсам, определенным в AlienInvasion. В строке(261) мы присваиваем экран
атрибуту Ship, чтобы мы могли легко получить к нему доступ во всех методах этого
класса. В строке(263) мы получаем доступ к атрибуту rect экрана с помощью метода get_rect() и присваиваем его self.screen_rect. Это позволяет нам поместить корабль в правильное место на экране. Чтобы загрузить изображение, мы вызываем pygame.image.load() и указываем ей местоположение нашего изображения корабля. Эта функция возвращает поверхность, представляющую корабль, которую мы присваиваем self.image. Когда изображение загружено, мы вызываем функцию get_rect() для доступа к атрибуту rect поверхности корабля, чтобы впоследствии использовать его для размещения корабля.

При работе с объектом rect можно использовать x- и y-координаты верхнего, нижнего, левого и правого краев прямоугольника, а также центр.
центр, для размещения объекта. Вы можете задать любое из этих значений, чтобы установить
текущее положение прямоугольника. Когда вы центрируете игровой элемент, работайте с параметрами
с атрибутами center, centerx или centery прямоугольника. При работе
на краю экрана, используйте атрибуты top, bottom, left или right.
Существуют также атрибуты, объединяющие эти свойства, например midbottom,
midbottom, midtop, midleft и midright. При настройке горизонтального или вертикального
вертикальное расположение прямоугольника, вы можете просто использовать атрибуты x и y, которые представляют собой
x- и y-координаты его левого верхнего угла.

Примечание:
В Pygame начало координат (0, 0) находится в левом верхнем углу экрана, а координаты увеличиваются по мере продвижения вниз и вправо. На экране размером 1200 на 800 начало координат находится в левом верхнем углу, а правый нижний угол имеет координаты (1200, 800).
Эти координаты относятся к игровому окну, а не к физическому экрану.

Мы расположим корабль в центре нижней части экрана. Для этого,
чтобы значение self.rect.midbottom совпадало с атрибутом midbottom атрибута
прямоугольника экрана. Pygame использует эти атрибуты прямоугольника для позиционирования корабля
так, чтобы он был отцентрирован по горизонтали и выровнен с нижней частью
экрана.
В строке(275) мы определяем метод blitme(), который выводит изображение на
экране в позиции, указанной self.rect.

Рисование корабля на экране

Теперь давайте обновим файл alien_invasion.py, чтобы он создал корабль и вызвал его метод
blitme():

#Alien_invasion.py
--snip--

from settings import Settings

from ship import Ship

class AlienInvasion:
    """Overall class to manage game assets and behavior."""

    def __init__(self):

        --snip--

        pygame.display.set_caption("Alien Invasion")

        self.ship = Ship(self)

    def run_game(self):

        --snip--

        # Redraw the screen during each pass through the loop.

        self.screen.fill(self.settings.bg_color)

        self.ship.blitme()

        # Make the most recently drawn screen visible.

        pygame.display.flip()

        --snip--
Вход в полноэкранный режим Выход из полноэкранного режима

Мы импортируем Ship, а затем создаем экземпляр Ship после того, как экран
был создан. Для вызова Ship() требуется один аргумент — экземпляр
AlienInvasion. Аргумент self здесь относится к текущему экземпляру
AlienInvasion. Это параметр, который дает Ship доступ к ресурсам игры.
ресурсам игры, таким как объект экрана. Мы присваиваем этому экземпляру Ship значение
self.ship.
После заполнения фона мы рисуем корабль на экране, вызывая команду
ship.blitme(), чтобы корабль появился поверх фона.
Когда вы запустите файл alien_invasion.py, вы увидите пустой игровой экран с ракетным кораблем, сидящим поверх фона.
экран с ракетным кораблем, сидящим в центре внизу.

Рефакторинг нашего кода

Рефакторинг упрощает структуру кода, который вы уже написали.
упрощает структуру уже написанного кода, делая его более удобным для дальнейшего использования. В этом разделе мы разобьем метод run_game()
который становится все длиннее, на два вспомогательных метода. Вспомогательный метод
работает внутри класса, но не предназначен для вызова через экземпляр. В
Python один символ подчеркивания указывает на вспомогательный метод.

Метод _check_events()

Мы перенесем код, управляющий событиями, в отдельный метод под названием
_check_events(). Это упростит выполнение run_game() и изолирует цикл управления событиями
цикл управления событиями. Изоляция цикла управления событиями позволяет вам управлять событиями отдельно
от других аспектов игры, таких как обновление экрана.
Вот класс AlienInvasion с новым методом _check_events(),
который влияет только на код в run_game():

#Alien_invasion.py

def run_game(self):

    """Start the main loop for the game."""

    while True:

        self._check_events()# Redraw the screen during each pass through the loop.

        --snip--

def _check_events(self):

    """Respond to keypresses and mouse events."""

    for event in pygame.event.get():

        if event.type == pygame.QUIT:

        sys.exit()
Вход в полноэкранный режим Выход из полноэкранного режима

Метод _update_screen()

Чтобы еще больше упростить run_game(), мы перенесем код для обновления экрана
в отдельный метод _update_screen():

#Alien_invasion.py
def run_game(self):

    """Start the main loop for the game."""

    while True:

        self._check_events()

        self._update_screen()

def _check_events(self):

    --snip--

def _update_screen(self):

    """Update images on the screen, and flip to the new screen."""

    self.screen.fill(self.settings.bg_color)

    self.ship.blitme()

    pygame.display.flip()
Вход в полноэкранный режим Выход из полноэкранного режима

Пилотирование корабля

Далее мы дадим игроку возможность перемещать корабль вправо и влево. Мы
напишем код, который будет реагировать на нажатие игроком клавиши со стрелкой вправо или влево.
Сначала мы сосредоточимся на движении вправо, а затем применим те же принципы для управления движением влево.
ципы для управления движением влево. По мере добавления этого кода вы узнаете, как
управлять движением изображений на экране и реагировать на ввод пользователя.

Реакция на нажатие клавиши

Каждый раз, когда игрок нажимает клавишу, это нажатие регистрируется в Pygame как
событие. Каждое событие перехватывается методом pygame.event.get(). Нам нужно
указать в нашем методе _check_events(), какие события мы хотим, чтобы игра
чтобы игра проверяла их. Каждое нажатие клавиши регистрируется как событие KEYDOWN.
Когда Pygame обнаруживает событие KEYDOWN, нам нужно проверить, является ли нажатая клавиша той.
была ли нажата клавиша, которая вызывает определенное действие. Например, если
игрок нажимает клавишу со стрелкой вправо, мы хотим увеличить значение rect.x корабля.
чтобы переместить корабль вправо:

#Alien_invasion.py

def _check_events(self):
    """Respond to keypresses and mouse events."""

    for event in pygame.event.get():

        if event.type == pygame.QUIT:

            sys.exit()

        elif event.type == pygame.KEYDOWN:

            if event.key == pygame.K_RIGHT:

            # Move the ship to the right.

            self.ship.rect.x += 1
~~~{% endraw %}

Inside _check_events() we add an elif block to the event loop to respond
when Pygame detects a KEYDOWN event. We check whether the key pressed,
event.key, is the right arrow key. The right arrow key is represented by
pygame.K_RIGHT. If the right arrow key was pressed, we move the ship to the
right by increasing the value of self.ship.rect.x by 1.
When you run alien_invasion.py now, the ship should move to the right
one pixel every time you press the right arrow key. That’s a start, but it’s not
an efficient way to control the ship. Let’s improve this control by allowing
continuous movement.

#### Allowing Continuous Movement

When the player holds down the right arrow key, we want the ship to
continue moving right until the player releases the key. We’ll have the
game detect a pygame.KEYUP event so we’ll know when the right arrow key is
released; then we’ll use the KEYDOWN and KEYUP events together with a flag
called moving_right to implement continuous motion.

When the moving_right flag is False, the ship will be motionless. When
the player presses the right arrow key, we’ll set the flag to True, and when the
player releases the key, we’ll set the flag to False again.
The Ship class controls all attributes of the ship, so we’ll give it an attri-
bute called moving_right and an update() method to check the status of the
moving_right flag. The update() method will change the position of the ship if
the flag is set to True. We’ll call this method once on each pass through the
while loop to update the position of the ship.
Here are the changes to Ship:
{% raw %}


```python
ship.py
class Ship:
"""A class to manage the ship."""
    def __init__(self, ai_game):

        --snip--

        # Start each new ship at the bottom center of the screen.

        self.rect.midbottom = self.screen_rect.midbottom

        # Movement flag

        self.moving_right = False

    def update(self):

        """Update the ship's position based on the movement flag."""

        if self.moving_right:

            self.rect.x += 1

    def blitme(self):

        --snip--
Войти в полноэкранный режим Выйти из полноэкранного режима

Мы добавляем атрибут self.moving_right в метод init() и устанавливаем его
первоначальное значение False.
Затем мы добавляем update(), который перемещает корабль вправо, если флаг
флаг равен True.
Метод update() будет вызван через экземпляр
Ship, поэтому он не считается вспомогательным методом.

Теперь нам нужно изменить _check_events() так, чтобы move_right устанавливался в True
когда нажата клавиша со стрелкой вправо, и False, когда клавиша отпущена:

#Alien_invasion.py

def _check_events(self):

    """Respond to keypresses and mouse events."""

    for event in pygame.event.get():

        --snip--

    elif event.type == pygame.KEYDOWN:

        if event.key == pygame.K_RIGHT:

            self.ship.moving_right = True

    elif event.type == pygame.KEYUP:

        if event.key == pygame.K_RIGHT:

            self.ship.moving_right = False

Вход в полноэкранный режим Выход из полноэкранного режима

Мы изменим реакцию игры на нажатие игроком кнопки
стрелку вправо: вместо того, чтобы напрямую менять положение корабля, мы просто
установим для параметра moving_right значение True. Затем мы добавляем новый блок elif в строке (556), который реагирует на события KEYUP. Когда игрок отпускает клавишу со стрелкой вправо (K_RIGHT), мы устанавливаем значение moving_right в False.

Далее мы модифицируем цикл while в run_game(), чтобы он вызывал метод update() корабля.
при каждом проходе по циклу:

#Alien_invasion.py
def run_game(self):

    """Start the main loop for the game."""

    while True:

        self._check_events()

        self.ship.update()

        self._update_screen()

Вход в полноэкранный режим Выход из полноэкранного режима

Позиция корабля будет обновляться после того, как мы проверим наличие событий от клавиатуры
и до обновления экрана. Это позволяет обновлять положение корабля
обновляться в ответ на ввод игрока и гарантирует, что обновленная позиция будет
будет использоваться при отрисовке корабля на экране.

Когда вы запускаете файл alien_invasion.py и удерживаете нажатой клавишу со стрелкой вправо, корабль
корабль будет непрерывно двигаться вправо, пока вы не отпустите клавишу.

Движение как влево, так и вправо

Теперь, когда корабль может непрерывно двигаться вправо, добавить движение в
влево не составит труда. Опять же, мы изменим класс Ship и метод check
_events(). Вот соответствующие изменения в __init_() и update()
в Ship:

ship.py
def __init__(self, ai_game):

    --snip--

    # Movement flags

    self.moving_right = False

    self.moving_left = False

def update(self):

    """Update the ship's position based on movement flags."""

    if self.moving_right:

        self.rect.x += 1

    if self.moving_left:

        self.rect.x -= 1
Вход в полноэкранный режим Выход из полноэкранного режима

В init() мы добавляем флаг self.moving_left. В update() мы используем два
отдельных блока if, а не elif, чтобы значение rect.x корабля можно было
увеличиваться, а затем уменьшаться при нажатии обеих клавиш со стрелками. Это
приводит к тому, что корабль стоит на месте. Если бы мы использовали elif для движения влево, правая клавиша со стрелкой всегда имела бы приоритет. При таком подходе
движения более точными при переключении справа налево, когда игрок
может на мгновение зажать обе клавиши.

Мы должны внести две поправки в _check_events():

#Alien_invasion.py

def _check_events(self):

    """Respond to keypresses and mouse events."""

    for event in pygame.event.get():

        --snip--

        elif event.type == pygame.KEYDOWN:

            if event.key == pygame.K_RIGHT:

                self.ship.moving_right = True

            elif event.key == pygame.K_LEFT:

                self.ship.moving_left = True

        elif event.type == pygame.KEYUP:

            if event.key == pygame.K_RIGHT:

                self.ship.moving_right = False

            elif event.key == pygame.K_LEFT:

                self.ship.moving_left = False

Вход в полноэкранный режим Выход из полноэкранного режима

Если происходит событие KEYDOWN для клавиши K_LEFT, мы устанавливаем moving_left в True. Если
KEYUP для клавиши K_LEFT, мы устанавливаем значение moving_left в False. Мы можем использовать
блоки elif, потому что каждое событие связано только с одной клавишей. Если игрок
нажмет обе клавиши одновременно, будут обнаружены два отдельных события.

Когда вы запустите файл alien_invasion.py, вы должны иметь возможность перемещать корабль
непрерывно перемещать корабль вправо и влево. Если вы удерживаете обе клавиши, корабль должен
перестанет двигаться.

Далее мы еще больше усовершенствуем движение корабля. Давайте настроим скорость корабля
скорость и ограничим расстояние, на которое корабль может двигаться, чтобы он не мог исчезнуть за пределами
экрана.

Настройка скорости корабля

В настоящее время корабль перемещается на один пиксель за цикл while, но мы можем более тонко контролировать скорость корабля.
мы можем более тонко контролировать скорость корабля, добавив атрибут ship_speed в класс
класса Settings. Мы будем использовать этот атрибут, чтобы определить, на какое расстояние перемещать корабль
корабль при каждом проходе через цикл.

#Settings.py
class Settings:

    """A class to store all settings for Alien Invasion."""

    def __init__(self):

        --snip--

        # Ship settings

        self.ship_speed = 1.5
Вход в полноэкранный режим Выход из полноэкранного режима

Мы установим начальное значение ship_speed равным 1,5. Когда корабль движется
теперь, его положение корректируется на 1,5 пикселя, а не на 1 пиксель при каждом проходе
через цикл.

Однако атрибуты прямоугольника, такие как x, хранят только целочисленные значения, поэтому нам необходимо
внести некоторые изменения в Ship:

#ship.py

class Ship:

    """A class to manage the ship."""

    def __init__(self, ai_game):

        """Initialize the ship and set its starting position."""

        self.screen = ai_game.screen

        self.settings = ai_game.settings

        --snip--

        # Start each new ship at the bottom center of the screen.

        --snip--

        # Store a decimal value for the ship's horizontal position.

        self.x = float(self.rect.x)

        # Movement flags

        self.moving_right = False

        self.moving_left = False

    def update(self):

        """Update the ship's position based on movement flags."""

        # Update the ship's x value, not the rect.

        if self.moving_right:

            self.x += self.settings.ship_speed

        if self.moving_left:

            self.x -= self.settings.ship_speed

        # Update rect object from self.x.

        self.rect.x = self.x

    def blitme(self):

    --snip--
Войти в полноэкранный режим Выход из полноэкранного режима

Мы создадим атрибут настроек для Ship, чтобы использовать его в update().
Поскольку мы изменяем положение корабля на доли пикселя, нам необходимо
необходимо присвоить позицию переменной, которая может хранить десятичное значение. Вы
можно использовать десятичное значение для установки атрибута rect, но rect будет хранить только
хранить только целую часть этого значения. Чтобы отслеживать положение корабля
мы определяем новый атрибут self.x, который может хранить десятичные значения.
Мы используем функцию float() для преобразования значения self.rect.x в десятичную дробь
и присваиваем это значение атрибуту self.x.
Теперь, когда мы изменяем положение корабля в update(), значение self.x
изменяется на величину, хранящуюся в settings.ship_speed. После того как self.x
обновляется, мы используем новое значение для обновления self.rect.x, который управляет
положением корабля. Только целочисленная часть self.x будет сохранена
в self.rect.x, но это вполне подходит для отображения корабля.

Теперь мы можем изменить значение ship_speed, и любое значение, большее чем
1, заставит корабль двигаться быстрее. Это поможет заставить корабль реагировать
достаточно быстро, чтобы сбивать пришельцев, а также позволит нам изменить темп
игры по мере продвижения игрока в игровом процессе.

Ограничение дальности полета корабля

На этом этапе корабль исчезнет за любым краем экрана, если вы
долго удерживать клавишу со стрелкой. Давайте исправим это, чтобы корабль перестал
двигаться, когда он достигает края экрана. Мы сделаем это, изменив метод
update() в методе Ship:

#ship.py
def update(self):
    """Update the ship's position based on movement flags."""

    # Update the ship's x value, not the rect.

    if self.moving_right and self.rect.right < self.screen_rect.right:

        self.x += self.settings.ship_speed

    if self.moving_left and self.rect.left > 0:

        self.x -= self.settings.ship_speed

    # Update rect object from self.x.

    self.rect.x = self.x
Войти в полноэкранный режим Выйти из полноэкранного режима

Этот код проверяет положение корабля перед изменением значения
self.x. Код self.rect.right возвращает x-координату правого края
прямоугольника корабля. Если это значение меньше, чем значение, возвращаемое self.screen
_rect.right, то корабль не достиг правого края экрана. То же самое
происходит и с левым краем: если значение левой стороны прямоугольника больше
нуля, корабль не достиг левого края экрана.

Это гарантирует, что корабль находится в этих границах, прежде чем корректировать значение self.x.
Когда вы запустите alien_invasion.py, корабль должен прекратить движение на
у любого края экрана. Это довольно круто; все, что мы сделали, это добавили условный тест в оператор if, но это похоже на то, что корабль ударяется о стену или силовое поле на любом краю экрана!

Рефакторинг _check_events()

Метод _check_events() будет увеличиваться по мере того, как мы будем продолжать разработку
игру, поэтому давайте разобьем _check_events() еще на два метода: один, обрабатывающий события KEYDOWN, и другой, обрабатывающий события KEYDOWN.
обрабатывает события KEYDOWN и другой, который обрабатывает события KEYUP:

#Alien_invasion.py

def _check_events(self):

    """Respond to keypresses and mouse events."""

    for event in pygame.event.get():

        if event.type == pygame.QUIT:

            sys.exit()

        elif event.type == pygame.KEYDOWN:

            self._check_keydown_events(event)

        elif event.type == pygame.KEYUP:

            self._check_keyup_events(event)

def _check_keydown_events(self, event):

        """Respond to keypresses."""

        if event.key == pygame.K_RIGHT:

            self.ship.moving_right = True

        elif event.key == pygame.K_LEFT:

            self.ship.moving_left = True

def _check_keyup_events(self, event):

    """Respond to key releases."""

    if event.key == pygame.K_RIGHT:

        self.ship.moving_right = False

    elif event.key == pygame.K_LEFT:

        self.ship.moving_left = False
Вход в полноэкранный режим Выход из полноэкранного режима

Мы создаем два новых вспомогательных метода: _check_keydown_events() и _check
_keyup_events(). Каждому из них нужен параметр self и параметр event. В
тела этих двух методов скопированы из _check_events(), и мы
заменили старый код на вызовы новых методов. Метод _check_events()
стал более простым с этой более чистой структурой кода, что облегчит
легче разрабатывать дальнейшие реакции на ввод данных игроком

Нажатие Q для выхода из игры

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

#Alien_invasion.py

def _check_keydown_events(self, event):

    --snip--

    elif event.key == pygame.K_LEFT:

        self.ship.moving_left = True

    elif event.key == pygame.K_q:

        sys.exit()
Войти в полноэкранный режим Выход из полноэкранного режима

В _check_keydown_events() мы добавим новый блок, который завершает игру, когда
игрок нажимает Q. Теперь при тестировании вы можете нажать Q, чтобы закрыть игру
а не использовать курсор для закрытия окна.

Запуск игры в полноэкранном режиме

В Pygame есть полноэкранный режим, который может понравиться вам больше, чем запуск игры в обычном окне.
игры в обычном окне. Некоторые игры выглядят лучше в полноэкранном режиме, и
пользователи macOS могут увидеть лучшую производительность в полноэкранном режиме.
Чтобы запустить игру в полноэкранном режиме, сделайте следующие изменения в функции
init():


#Alien_invasion.py

def __init__(self):

    """Initialize the game, and create game resources."""

    pygame.init()

    self.settings = Settings()

    self.screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)

    self.settings.screen_width = self.screen.get_rect().width

    self.settings.screen_height = self.screen.get_rect().height

    pygame.display.set_caption("Alien Invasion")
Войти в полноэкранный режим Выйти из полноэкранного режима

При создании поверхности экрана мы передаем размер (0, 0) и параметр
параметр pygame.FULLSCREEN. Это дает команду Pygame определить размер окна.
которое будет заполнять экран. Поскольку мы не знаем ширину и высоту
экрана заранее, мы обновляем эти параметры после создания экрана.
Мы используем атрибуты ширины и высоты прямоугольника экрана для обновления объекта
объект настроек.

Следующая часть: Стрельба пулями

Оцените статью
devanswers.ru
Добавить комментарий