Arcade: Учебное пособие по игровому фреймворку Python
Оглавление
- Предыстория и настройка
- Базовая аркадная программа
- Концепции аркад
- Основы геймдизайна на Python
- Дополнительно
- Примечание об источниках
- Заключение
Компьютерные игры - отличный способ познакомить людей с программированием и компьютерными науками. Поскольку в юности я был игроком, желание писать видеоигры стало причиной того, что я научился программировать. Конечно, когда я изучал Python, моим первым побуждением было написать игру на Python.
В то время как Python делает обучение программированию более доступным для всех, выбор для написания видеоигр может быть ограничен, особенно если вы хотите создавать аркадные игры с великолепной графикой и запоминающимися звуковыми эффектами. В течение многих лет разработчики игр на Python были ограничены фреймворком pygame
. Теперь у нас есть другой выбор.
Библиотека arcade
- это современный фреймворк на Python для создания игр с привлекательной графикой и звуком. Объектно-ориентированный и созданный для Python версии 3.6 и выше, arcade
предоставляет программисту современный набор инструментов для создания великолепных игр на Python.
В этом руководстве вы узнаете, как:
- Установите библиотеку
arcade
- Нарисуйте элементов на экране
- Работайте с
arcade
игровым циклом Python - Управление графическими элементами на экране
- Обрабатывать пользовательский ввод
- Воспроизведение звуковых эффектов и музыки
- Опишите, чем программирование игр на Python с помощью
arcade
отличается отpygame
В этом руководстве предполагается, что вы разбираетесь в написании программ на Python. Поскольку arcade
является объектно-ориентированной библиотекой, вы также должны быть знакомы с объектно-ориентированным программированием. Весь код, изображения и звуки для этого руководства доступны для скачивания по ссылке ниже:
Загрузите ресурсы: Нажмите здесь, чтобы загрузить ресурсы, которые вы будете использовать для создания аркадной игры в этом руководстве.
Предыстория и настройка
Библиотека arcade
была написана Полом Винсентом Крейвеном, профессором компьютерных наук в Симпсон-колледже в Айове, США. Поскольку он построен поверх библиотеки окон и мультимедиа pyglet
, arcade
содержит различные улучшения, модернизацию и усовершенствования по сравнению с pygame
:
- Обладает современной графикой OpenGL
- Поддерживает Python 3 подсказки типа
- Улучшена поддержка анимированных спрайтов
- Содержит согласованные названия команд, функций и параметров
- Способствует отделению игровой логики от кода отображения
- Требуется меньше шаблонного кода
- Содержит больше документации, включая полные примеры игр на Python .
- Имеет встроенный физический движок для платформенных игр
Чтобы установить arcade
и его зависимости, используйте соответствующую команду pip
:
$ python -m pip install arcade
На компьютере Mac вам также необходимо установить PyObjC
:
$ python -m pip install PyObjC arcade
Полные инструкции по установке, основанные на вашей платформе, доступны для Windows, Mac, Linux и даже Raspberry Pi. Вы даже можете установить arcade
непосредственно из исходного кода, если хотите.
Примечание: В более поздних версиях arcade
используются классы данных, которые включены в Python только для версии 3.7 и более поздних версий.
Однако в PyPI для Python 3.6 доступен резервный порт, который вы можете установить с помощью pip
:
$ python -m pip install dataclasses
Смотрите Полное руководство по классам данных в Python 3.7 для получения дополнительной информации.
В этом руководстве предполагается, что вы используете arcade
версии 2.1 и Python 3.7.
Основные arcade
Программа
Прежде чем вы начнете, давайте взглянем на программу arcade
, которая откроет окно, зальет его белым цветом и нарисует синий круг посередине:
1# Basic arcade program
2# Displays a white window with a blue circle in the middle
3
4# Imports
5import arcade
6
7# Constants
8SCREEN_WIDTH = 600
9SCREEN_HEIGHT = 800
10SCREEN_TITLE = "Welcome to Arcade"
11RADIUS = 150
12
13# Open the window
14arcade.open_window(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
15
16# Set the background color
17arcade.set_background_color(arcade.color.WHITE)
18
19# Clear the screen and start drawing
20arcade.start_render()
21
22# Draw a blue circle
23arcade.draw_circle_filled(
24 SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, RADIUS, arcade.color.BLUE
25)
26
27# Finish drawing
28arcade.finish_render()
29
30# Display everything
31arcade.run()
Когда вы запустите эту программу, вы увидите окно, которое выглядит следующим образом:
Давайте разберем это построчно:
- Строка 5 импортирует библиотеку
arcade
. Без этого больше ничего не работает. - Строки с 8 по 11 определяют некоторые константы, которые вы будете использовать чуть позже, для наглядности.
- Строка 14 открывает главное окно. Вы задаете ширину, высоту и текст строки заголовка, а
arcade
делает все остальное. - Строка 17 устанавливает цвет фона, используя константу из пакета
arcade.color
. Вы также можете указать цвет RGB, используя список или кортеж . - Строка 20 переводит
arcade
в режим рисования. Все, что вы нарисуете после этой строки, будет отображено на экране. - Строки с 23 по 25 нарисуйте окружность, указав координаты центра по X и Y, радиус и цвет, который нужно использовать.
- Строка 28 завершает режим рисования.
- Строка 31 отображает ваше окно, которое вы можете видеть.
Если вы знакомы с pygame
, то вы заметите некоторые отличия:
- Нет
pygame.init()
. Вся инициализация выполняется при запускеimport arcade
. - Явно определенного цикла отображения нет. Это обрабатывается в
arcade.run()
. - Здесь также нет цикла обработки событий. Опять же,
arcade.run()
обрабатывает события и обеспечивает некоторые действия по умолчанию, такие как возможность закрыть окно. - Вы можете использовать заранее определенные цвета для рисования, а не определять их все самостоятельно.
- Вы должны начать и закончить рисование в аркаде, используя
start_render()
иfinish_render()
.
Давайте внимательно рассмотрим фундаментальные arcade
концепции, лежащие в основе этой программы.
arcade
Концепции
Например pygame
, arcade
код выполняется практически на каждой платформе, поддерживающей Python. Для этого требуется arcade
иметь дело с абстракциями для различных аппаратных различий на этих платформах. Понимание этих концепций и абстракций поможет вам проектировать и разрабатывать свои собственные игры, а понимание того, чем arcade
отличается от pygame
, поможет вам адаптироваться к их уникальной точке зрения.
Инициализация
Поскольку он работает с различными платформами, arcade
необходимо выполнить шаг инициализации, прежде чем вы сможете его использовать. Этот шаг выполняется автоматически при каждом импорте arcade
, поэтому вам не нужно писать дополнительный код. При импорте arcade
выполняется следующее:
- Убедитесь, что вы работаете на Python версии 3.6 или выше.
- Импортируйте библиотеку
pyglet_ffmeg2
для обработки звука, если она доступна. - Импортируйте библиотеку
pyglet
для работы с окнами и мультимедиа. - Установите констант для цветов и сопоставлений клавиш.
- Импортируйте оставшуюся
arcade
библиотеку.
Сравните это с pygame
, который требует отдельного шага инициализации для каждого модуля.
Окна и координаты
Все в arcade
происходит в окне, которое вы создаете с помощью open_window()
. В настоящее время arcade
поддерживает только одно окно отображения. Вы можете изменить размер окна при его открытии.
arcade
использует ту же декартову систему координат, которую вы, возможно, изучали на уроках алгебры. Окно находится в квадранте I, а исходная точка (0, 0) расположена в левом нижнем углу экрана. Координата x увеличивается при движении вправо, а координата y увеличивается при движении вверх:
Важно отметить, что такое поведение отличается от pygame
и многих других игровых фреймворков на Python. Возможно, вам потребуется некоторое время, чтобы привыкнуть к этой разнице.
Рисунок
В готовом виде arcade
содержит функции для рисования различных геометрических фигур, в том числе:
- Дуги
- Окружности
- Эллипсы
- Линии
- Параболы
- Точки
- Многоугольники
- Прямоугольники
- Треугольники
Все функции рисования начинаются с draw_
и соответствуют определенной схеме именования и параметров. Существуют различные функции для рисования заполненных и очерченных фигур:
Поскольку прямоугольники являются обычными, существуют три отдельные функции для их рисования различными способами:
draw_rectangle()
ожидает значения координат x и y центра прямоугольника, ширины и высоты.draw_lrtb_rectangle()
ожидаются левая и правая координаты x, за которыми следуют верхняя и нижняя координаты y.draw_xywh_rectangle()
используются координаты x и y нижнего левого угла, за которыми следуют ширина и высота.
Обратите внимание, что для каждой функции требуется четыре параметра. Вы также можете нарисовать любую фигуру, используя буферизованные функции рисования, которые используют вершинные буферы, чтобы передавать все данные непосредственно на видеокарту для невероятного повышения производительности. Все буферизованные функции рисования начинаются с create_
и соответствуют согласованным схемам именования и параметров.
Объектно-ориентированный дизайн
По своей сути, arcade
представляет собой объектно-ориентированную библиотеку. Подобно pygame
, вы можете написать arcade
код процедурно, как вы делали в примере выше. Однако реальная мощь arcade
проявляется при создании полностью объектно-ориентированных программ.
Когда вы вызвали arcade.open_window()
в приведенном выше примере, код создает объект arcade.Window
за кулисами для управления этим окном. Позже вы создадите свой собственный класс на основе arcade.Window
, чтобы написать полноценную игру на Python.
Сначала взгляните на исходный пример кода, в котором теперь используются объектно-ориентированные концепции, чтобы подчеркнуть основные различия:
# Basic arcade program using objects
# Displays a white window with a blue circle in the middle
# Imports
import arcade
# Constants
SCREEN_WIDTH = 600
SCREEN_HEIGHT = 800
SCREEN_TITLE = "Welcome to Arcade"
RADIUS = 150
# Classes
class Welcome(arcade.Window):
"""Main welcome window
"""
def __init__(self):
"""Initialize the window
"""
# Call the parent class constructor
super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
# Set the background window
arcade.set_background_color(arcade.color.WHITE)
def on_draw(self):
"""Called whenever you need to draw your window
"""
# Clear the screen and start drawing
arcade.start_render()
# Draw a blue circle
arcade.draw_circle_filled(
SCREEN_WIDTH / 2, SCREEN_HEIGHT / 2, RADIUS, arcade.color.BLUE
)
# Main code entry point
if __name__ == "__main__":
app = Welcome()
arcade.run()
Давайте рассмотрим этот код построчно:
-
Строки с 1 по 11 такие же, как в предыдущем примере процедуры.
-
Строка 15 - это то место, где начинаются различия. Вы определяете класс с именем
Welcome
на основе родительского классаarcade.Window
. Это позволяет при необходимости переопределять методы родительского класса. -
Строки с 18 по 26 определяют метод
.__init__()
. После вызова родительского метода.__init__()
с помощьюsuper()
для настройки окна необходимо задать цвет его фона, как вы делали ранее. -
Строки с 28 по 38 определяют
.on_draw()
. Это один из несколькихWindow
методов, которые вы можете переопределить, чтобы настроить поведение вашейarcade
программы. Этот метод вызывается каждый раз, когдаarcade
требуется отрисовать окно. Он начинается с вызоваarcade.start_render()
, за которым следует весь ваш код рисования. Однако вам не нужно вызыватьarcade.finish_render()
, так какarcade
вызовет это неявно, когда.on_draw()
завершится. -
Строки с 41 по 43 являются основной точкой входа в ваш код. После того, как вы впервые создадите новый объект
Welcome
с именемapp
, вы вызываетеarcade.run()
для отображения окна.
Этот объектно-ориентированный пример является ключом к получению максимальной отдачи от arcade
. Одна вещь, на которую вы, возможно, обратили внимание, - это описание .on_draw()
. arcade
будет вызывать эту функцию каждый раз, когда она захочет нарисовать что-либо в окне. Итак, как arcade
узнает, когда что-либо рисовать? Давайте взглянем на последствия этого.
Игровой цикл
Все действия практически в каждой игре происходят в центральном игровом цикле. Вы можете увидеть примеры игровых циклов даже в таких физических играх, как шашки, "Старая дева" или бейсбол. Игровой цикл начинается после того, как игра настроена и инициализирована, и заканчивается, когда игра запускается. Внутри этого цикла последовательно происходит несколько событий. Как минимум, игровой цикл выполняет следующие четыре действия:
- Программа определяет, окончена ли игра. Если это так, то цикл завершается.
- Вводимые пользователем данные обрабатываются.
- Состояния игровых объектов обновляются в зависимости от таких факторов, как вводимые пользователем данные или время.
- В игре отображаются визуальные эффекты и воспроизводятся звуковые эффекты, основанные на новом состоянии.
В pygame
вы должны явно настроить этот цикл и управлять им. В arcade
для вас предусмотрен игровой цикл Python, инкапсулированный в вызов arcade.run()
.
Во время встроенного игрового цикла arcade
вызывает набор Window
методов для реализации всех перечисленных выше функций. Все названия этих методов начинаются с on_
и могут рассматриваться как обработчики задач или событий. Когда игровому циклу arcade
необходимо обновить состояние всех игровых объектов Python, он вызывает .on_update()
. Когда ему нужно проверить движение мыши, он вызывает .on_mouse_motion()
.
По умолчанию ни один из этих методов не дает ничего полезного. Когда вы создаете свой собственный класс на основе arcade.Window
, вы переопределяете их по мере необходимости для обеспечения собственной игровой функциональности. Некоторые из предложенных методов включают следующее:
- Ввод с клавиатуры:
.on_key_press()
,.on_key_release()
- Ввод с помощью мыши:
.on_mouse_press()
,.on_mouse_release()
,.on_mouse_motion()
- Обновление игрового объекта:
.on_update()
- Рисование:
.on_draw()
Вам не нужно переопределять все эти методы, только те, для которых вы хотите обеспечить другое поведение. Вам также не нужно беспокоиться о , когда они вызываются, просто что делать, когда они вызываются. Далее вы узнаете, как можно объединить все эти концепции для создания игры.
Основы геймдизайна на Python
Прежде чем приступить к написанию любого кода, всегда полезно разработать дизайн. Поскольку в этом руководстве вы будете создавать игру на Python, вы также разработаете для нее игровой процесс:
- Игра представляет собой игру с горизонтальной прокруткой, в которой нужно избегать врагов.
- Проигрыватель запускается в левой части экрана.
- Враги появляются через равные промежутки времени в случайных местах справа.
- Враги движутся влево по прямой линии, пока не исчезнут с экрана.
- Игрок может двигаться влево, вправо, вверх или вниз, чтобы избежать столкновения с врагами.
- Игрок не может отойти от экрана.
- Игра заканчивается, когда в игрока попадает враг или пользователь закрывает окно.
Когда мой бывший коллега описывал проекты по разработке программного обеспечения, он как-то сказал: “Вы не знаете, что вы делаете, пока не узнаете, чего вы не делаете”. Имея это в виду, вот вот некоторые вещи, которые вы не будете рассматривать в этом руководстве:
- Нет нескольких жизней
- Нет подсчета очков
- Нет возможности атаковать игрока
- Нет повышения уровня
- Нет персонажей-“боссов”
Вы можете попробовать свои силы в добавлении этих и других функций в свою собственную программу.
Импорт и константы
Как и в случае с любой программой arcade
, вы начнете с импорта библиотеки:
# Basic arcade shooter
# Imports
import arcade
import random
# Constants
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
SCREEN_TITLE = "Arcade Space Shooter"
SCALING = 2.0
В дополнение к arcade
вы также импортируете random
, так как позже вы будете использовать случайных чисел. Константы задают размер окна и его название, но что такое SCALING
? Эта константа используется для увеличения размера окна и игровых объектов в нем, чтобы компенсировать использование экранов с высоким разрешением. В дальнейшем вы увидите, что она используется в двух местах. Вы можете изменить это значение в соответствии с размером вашего экрана.
Класс окна
Чтобы в полной мере воспользоваться игровым циклом arcade
Python и обработчиками событий, создайте новый класс на основе arcade.Window
:
35class SpaceShooter(arcade.Window):
36 """Space Shooter side scroller game
37 Player starts on the left, enemies appear on the right
38 Player can move anywhere, but not off screen
39 Enemies fly to the left at variable speed
40 Collisions end the game
41 """
42
43 def __init__(self, width, height, title):
44 """Initialize the game
45 """
46 super().__init__(width, height, title)
47
48 # Set up the empty sprite lists
49 self.enemies_list = arcade.SpriteList()
50 self.clouds_list = arcade.SpriteList()
51 self.all_sprites = arcade.SpriteList()
Ваш новый класс запускается точно так же, как в приведенном выше объектно-ориентированном примере. В строке 43 вы определяете свой конструктор, который принимает ширину, высоту и заголовок игрового окна и использует super()
для передачи их родительскому классу. Затем вы инициализируете несколько пустых списков спрайтов в строках с 49 по 51. В следующем разделе вы узнаете больше о спрайтах и списках спрайтов.
Спрайты и списки спрайтов
В вашем игровом проекте на Python требуется один игрок, который начинает игру слева и может свободно перемещаться по окну. Также требуются враги (другими словами, более одного), которые случайным образом появляются справа и перемещаются влево. Хотя вы могли бы использовать команды draw_
, чтобы нарисовать игрока и каждого врага, быстро стало бы трудно следить за тем, чтобы все было правильно.
Вместо этого в большинстве современных игр используются спрайты для отображения объектов на экране. По сути, спрайт - это двумерное изображение игрового объекта определенного размера, которое рисуется в определенном месте на экране. В arcade
спрайты - это объекты класса arcade.Sprite
, и вы будете использовать их как для изображения вашего игрока, так и врагов. Вы даже добавите несколько облаков, чтобы сделать фон более интересным.
Управлять всеми этими спрайтами может быть непросто. Вы создадите спрайт для одиночной игры, но также будете создавать многочисленных врагов и облачных спрайтов. Отслеживать их все - это задача для списка спрайтов. Если вы понимаете, как работают списки Python, то у вас есть инструменты для использования списков спрайтов arcade
. Списки спрайтов делают больше чем просто держаться за все спрайты. Они обеспечивают три важных вида поведения:
- Вы можете обновить все спрайты в списке одним вызовом
SpriteList.update()
. - Вы можете нарисовать все спрайты в списке одним вызовом
SpriteList.draw()
. - Вы можете проверить, не сталкивался ли отдельный спрайт с каким-либо другим спрайтом в списке.
Вы можете задаться вопросом, зачем вам нужны три разных списка спрайтов, если вам нужно всего лишь управлять несколькими врагами и облаками. Причина в том, что каждый из трех разных списков спрайтов существует, потому что вы используете их для трех разных целей:
- Вы используете
.enemies_list
для обновления позиций противника и проверки на наличие столкновений. - Вы используете
.clouds_list
для обновления местоположения облаков. - Наконец, вы используете
.all_sprites
, чтобы нарисовать все.
Теперь список полезен ровно настолько, насколько полезны содержащиеся в нем данные. Вот как вы заполняете списки спрайтов:
53def setup(self):
54 """Get the game ready to play
55 """
56
57 # Set the background color
58 arcade.set_background_color(arcade.color.SKY_BLUE)
59
60 # Set up the player
61 self.player = arcade.Sprite("images/jet.png", SCALING)
62 self.player.center_y = self.height / 2
63 self.player.left = 10
64 self.all_sprites.append(self.player)
Вы определяете .setup()
, чтобы инициализировать игру до известной начальной точки. Хотя вы могли бы сделать это в .__init__()
, полезно использовать отдельный метод .setup()
.
Представьте, что вы хотите, чтобы в вашей игре на Python было несколько уровней или чтобы у вашего игрока было несколько жизней. Вместо того чтобы перезапускать всю игру, вызывая .__init__()
, вы вызываете .setup()
, чтобы повторно инициализировать игру до известной начальной точки или настроить новый уровень. Несмотря на то, что в этой игре на Python не будет этих функций, настройка структуры ускорит их последующее добавление.
После того, как вы зададите цвет фона в строке 58, вы определите спрайт игрока:
-
Строка 61 создает новый объект
arcade.Sprite
, указывая изображение для отображения и коэффициент масштабирования. Рекомендуется организовать ваши изображения в одну подпапку, особенно в крупных проектах. -
Строка 62 устанавливает положение спрайта по оси y равным половине высоты окна.
-
Строка 63 устанавливает положение x для спрайта, располагая левый край на расстоянии нескольких пикселей от левого края окна.
-
Строка 64, наконец, использует
.append()
чтобы добавить спрайт в список.all_sprites
вы будете использовать его для рисования.
В строках 62 и 63 показаны два разных способа позиционирования вашего спрайта. Давайте подробнее рассмотрим все доступные варианты позиционирования спрайта.
Расположение спрайтов
Все спрайты в arcade
имеют определенный размер и положение в окне:
- Размер , указанный в параметрах
Sprite.width
иSprite.height
, определяется графическим изображением, используемым при создании спрайта. - Позиция изначально задана так, чтобы центр спрайта, указанный в
Sprite.center_x
иSprite.center_y
, был равен (0,0) в окне.
Как только координаты .center_x
и .center_y
известны, arcade
может использовать размер для вычисления Sprite.left
, Sprite.right
, Sprite.top
, а также Sprite.bottom
ребер.
Это также работает в обратном порядке. Например, если вы установите для Sprite.left
заданное значение, то для arcade
также будут пересчитаны остальные атрибуты позиции. Вы можете использовать любой из них, чтобы найти спрайт или переместить его в окне. Это чрезвычайно полезная и мощная характеристика arcade
спрайтов. Если вы будете использовать их, то для вашей игры на Python потребуется меньше кода, чем pygame
:
Теперь, когда вы определили спрайт игрока, вы можете поработать со спрайтами противника. Дизайн требует, чтобы вражеские спрайты появлялись через регулярные промежутки времени. Как ты можешь это делать?
Функции планирования
arcade.schedule()
предназначен именно для этой цели. Он принимает два аргумента:
- Имя функции для вызова
- Интервал времени ожидания между каждым вызовом, в секундах
Поскольку вы хотите, чтобы на протяжении всей игры появлялись как враги, так и облака, вы настраиваете одну запланированную функцию для создания новых врагов, а вторую - для создания новых облаков. Этот код содержится в .setup()
. Вот как выглядит этот код:
66# Spawn a new enemy every 0.25 seconds
67arcade.schedule(self.add_enemy, 0.25)
68
69# Spawn a new cloud every second
70arcade.schedule(self.add_cloud, 1.0)
Теперь все, что вам нужно сделать, это определить self.add_enemy()
и self.add_cloud()
.
Добавление врагов
Судя по вашему дизайну игры на Python, враги обладают тремя ключевыми свойствами:
- Они отображаются в произвольных местах в правой части окна.
- Они движутся влево по прямой линии.
- Они исчезают, когда исчезают с экрана.
Код для создания вражеского спрайта очень похож на код для создания игрового спрайта:
93def add_enemy(self, delta_time: float):
94 """Adds a new enemy to the screen
95
96 Arguments:
97 delta_time {float} -- How much time has passed since the last call
98 """
99
100 # First, create the new enemy sprite
101 enemy = arcade.Sprite("images/missile.png", SCALING)
102
103 # Set its position to a random height and off screen right
104 enemy.left = random.randint(self.width, self.width + 80)
105 enemy.top = random.randint(10, self.height - 10)
.add_enemy()
принимает единственный параметр delta_time
, который показывает, сколько времени прошло с момента последнего вызова. Это требуется в arcade.schedule()
, и хотя вы не будете использовать это здесь, это может быть полезно для приложений, требующих расширенного выбора времени.
Как и в случае со спрайтом игрока, вы сначала создаете новый arcade.Sprite
с изображением и коэффициентом масштабирования. Вы устанавливаете позицию, используя .left
и .top
, в произвольное положение где-то за пределами экрана справа:
Это позволяет противнику плавно перемещаться по экрану, а не просто появляться на нем. Итак, как заставить его двигаться?
Движущиеся спрайты
Для перемещения спрайта требуется изменить его положение на этапе обновления игрового цикла. Хотя вы можете сделать это самостоятельно, arcade
имеет некоторые встроенные функции, позволяющие снизить нагрузку. Каждый arcade.Sprite
имеет не только набор атрибутов положения, но и набор атрибутов движения. Каждый раз, когда спрайт обновляется, arcade
будет использовать атрибуты движения для обновления положения, придавая спрайту относительное движение.
Атрибут Sprite.velocity
представляет собой кортеж, состоящий из изменений в позициях x и y. Вы также можете напрямую обращаться к Sprite.change_x
и Sprite.change_y
. Как упоминалось выше, каждый раз, когда спрайт обновляется, его .position
изменяется на основе .velocity
. Все, что вам нужно сделать в .add_enemy()
, это установить скорость:
107# Set its speed to a random speed heading left
108enemy.velocity = (random.randint(-20, -5), 0)
109
110# Add it to the enemies list
111self.enemies_list.append(enemy)
112self.all_sprites.append(enemy)
После того, как вы установите произвольную скорость перемещения влево по строке 108, вы добавите нового врага в соответствующие списки. Когда вы позже позвоните sprite.update()
, arcade
, я разберусь с остальным:
В вашем игровом дизайне на Python враги движутся по прямой справа налево. Поскольку ваши враги всегда движутся влево, как только они исчезают с экрана, они больше не возвращаются. Было бы неплохо, если бы вы могли избавиться от вражеского спрайта за кадром, чтобы освободить память и ускорить обновление. К счастью, arcade
вас прикрывает.
Удаление спрайтов
Поскольку ваши враги всегда перемещаются влево, их x-позиции всегда становятся меньше, а y-позиции всегда остаются неизменными. Таким образом, вы можете определить, что враг находится за пределами экрана, когда enemy.right
меньше нуля, что соответствует левому краю окна. Как только вы определите, что враг находится за пределами экрана, вы вызываете enemy.remove_from_sprite_lists()
, чтобы удалить его из всех списков, к которым он принадлежит, и удалить этот объект из памяти:
if enemy.right < 0:
enemy.remove_from_sprite_lists()
Но когда вы выполняете эту проверку? Обычно это происходит сразу после перемещения спрайта. Однако помните, что было сказано ранее о .all_enemies
списке спрайтов:
Вы используете
.enemies_list
для обновления позиций противника и проверки на наличие столкновений.
Это означает, что в SpaceShooter.on_update()
вы вызовете enemies_list.update()
для автоматической обработки перемещения противника, что, по сути, приводит к следующему:
for enemy in enemies_list:
enemy.update()
Было бы неплохо, если бы вы могли добавить проверку за кадром непосредственно к вызову enemy.update()
, и вы можете это сделать! Помните, что arcade
- это объектно-ориентированная библиотека. Это означает, что вы можете создавать свои собственные классы на основе arcade
классов и переопределять методы, которые вы хотите изменить. В этом случае вы создаете новый класс на основе arcade.Sprite
и переопределяете только .update()
:
17class FlyingSprite(arcade.Sprite):
18 """Base class for all flying sprites
19 Flying sprites include enemies and clouds
20 """
21
22 def update(self):
23 """Update the position of the sprite
24 When it moves off screen to the left, remove it
25 """
26
27 # Move the sprite
28 super().update()
29
30 # Remove if off the screen
31 if self.right < 0:
32 self.remove_from_sprite_lists()
Вы определяете FlyingSprite
как все, что будет летать в вашей игре, например, враги и облака. Затем вы переопределяете .update()
, сначала вызывая super().update()
для правильной обработки движения. Затем вы выполняете проверку за кадром.
Поскольку у вас новый класс, вам также нужно будет внести небольшое изменение в .add_enemy()
:
def add_enemy(self, delta_time: float):
"""Adds a new enemy to the screen
Arguments:
delta_time {float} -- How much time as passed since the last call
"""
# First, create the new enemy sprite
enemy = FlyingSprite("images/missile.png", SCALING)
Вместо того, чтобы создавать новый Sprite
, вы создаете новый FlyingSprite
, чтобы воспользоваться преимуществами нового .update()
.
Добавление облаков
Чтобы сделать вашу игру на Python визуально более привлекательной, вы можете добавить облака на небо. Облака летают по небу, как и ваши враги, поэтому вы можете создавать и перемещать их аналогичным образом.
.add_cloud()
выполняется по той же схеме, что и .add_enemy()
, хотя случайная скорость медленнее:
def add_cloud(self, delta_time: float):
"""Adds a new cloud to the screen
Arguments:
delta_time {float} -- How much time has passed since the last call
"""
# First, create the new cloud sprite
cloud = FlyingSprite("images/cloud.png", SCALING)
# Set its position to a random height and off screen right
cloud.left = random.randint(self.width, self.width + 80)
cloud.top = random.randint(10, self.height - 10)
# Set its speed to a random speed heading left
cloud.velocity = (random.randint(-5, -2), 0)
# Add it to the enemies list
self.clouds_list.append(cloud)
self.all_sprites.append(cloud)
Облака движутся медленнее, чем враги, поэтому вы рассчитываете меньшую случайную скорость в строке 129.
Теперь ваша игра на Python выглядит немного более завершенной:
Ваши враги и облака созданы и теперь двигаются сами по себе. Пришло время заставить игрока двигаться также с помощью клавиатуры.
Ввод с клавиатуры
Класс arcade.Window
имеет две функции для обработки ввода с клавиатуры. Ваша игра на Python будет вызывать .on_key_press()
всякий раз, когда нажимается клавиша, и .on_key_release()
всякий раз, когда клавиша отпускается. Обе функции принимают два целочисленных параметра:
symbol
представляет собой фактическую клавишу, которая была нажата или отпущена.modifiers
указывает, какие модификаторы были отключены. К ним относятся клавиши Shift, Ctrl и Alt.
К счастью, вам не нужно знать, какие целые числа обозначают какие клавиши. Модуль arcade.key
содержит все константы клавиатуры, которые вы, возможно, захотите использовать. Традиционно для перемещения игрока с помощью клавиатуры используется один или более из трех различных наборов клавиш:
- Четыре клавиши со стрелками для Вверх, Вниз, Слева и Справа
- Ключи I, J, K и L, который отображает значения Вверх, влево, вниз и вправо
- Для управления левой рукой используются клавиши W, A, S и D, которые также отображаются на "Вверх", "Влево", "Вниз" и "Вправо"
В этой игре вы будете использовать стрелки и I/J/K/L. Всякий раз, когда пользователь нажимает клавишу перемещения, спрайт игрока перемещается в указанном направлении. Когда пользователь отпускает клавишу перемещения, спрайт перестает двигаться в этом направлении. Вы также указываете способ выхода из игры, используя Q, и способ приостановки игры, используя P. Для этого вам необходимо реагировать на нажатия и отпускания клавиш:
- При нажатии клавиши вызывается
.on_key_press()
. В этом методе вы проверяете, какая клавиша была нажата:- Если это Q, то вы просто выходите из игры.
- Если это P, то вы устанавливаете флажок, указывающий на то, что игра приостановлена.
- Если это клавиша перемещения, то вы устанавливаете значение игрока
.change_x
или.change_y
соответственно. - Если это любой другой ключ, то вы игнорируете его.
- Когда клавиша будет отпущена, вызовите
.on_key_release()
. И снова проверьте, какая клавиша была отпущена:- Если это клавиша перемещения, то вы устанавливаете значение игрока
.change_x
или.change_y
равным 0 соответственно. - Если это любой другой ключ, то вы игнорируете его.
- Если это клавиша перемещения, то вы устанавливаете значение игрока
Вот как выглядит код:
134def on_key_press(self, symbol, modifiers):
135 """Handle user keyboard input
136 Q: Quit the game
137 P: Pause/Unpause the game
138 I/J/K/L: Move Up, Left, Down, Right
139 Arrows: Move Up, Left, Down, Right
140
141 Arguments:
142 symbol {int} -- Which key was pressed
143 modifiers {int} -- Which modifiers were pressed
144 """
145 if symbol == arcade.key.Q:
146 # Quit immediately
147 arcade.close_window()
148
149 if symbol == arcade.key.P:
150 self.paused = not self.paused
151
152 if symbol == arcade.key.I or symbol == arcade.key.UP:
153 self.player.change_y = 5
154
155 if symbol == arcade.key.K or symbol == arcade.key.DOWN:
156 self.player.change_y = -5
157
158 if symbol == arcade.key.J or symbol == arcade.key.LEFT:
159 self.player.change_x = -5
160
161 if symbol == arcade.key.L or symbol == arcade.key.RIGHT:
162 self.player.change_x = 5
163
164def on_key_release(self, symbol: int, modifiers: int):
165 """Undo movement vectors when movement keys are released
166
167 Arguments:
168 symbol {int} -- Which key was pressed
169 modifiers {int} -- Which modifiers were pressed
170 """
171 if (
172 symbol == arcade.key.I
173 or symbol == arcade.key.K
174 or symbol == arcade.key.UP
175 or symbol == arcade.key.DOWN
176 ):
177 self.player.change_y = 0
178
179 if (
180 symbol == arcade.key.J
181 or symbol == arcade.key.L
182 or symbol == arcade.key.LEFT
183 or symbol == arcade.key.RIGHT
184 ):
185 self.player.change_x = 0
В .on_key_release()
вы проверяете только те клавиши, которые влияют на перемещение спрайта игрока. Нет необходимости проверять, были ли нажаты клавиши паузы или завершения.
Теперь вы можете перемещаться по экрану и немедленно выходить из игры:
Возможно, вам интересно, как работает функция паузы. Чтобы увидеть это в действии, вам сначала нужно научиться обновлять все ваши игровые объекты на Python.
Обновление игровых объектов
То, что вы установили скорость для всех своих спрайтов, не означает, что они будут двигаться. Чтобы заставить их двигаться, вы должны обновлять их снова и снова в игровом цикле.
Поскольку arcade
управляет игровым циклом Python, он также определяет, когда требуются обновления, вызывая .on_update()
. Вы можете переопределить этот метод, чтобы обеспечить правильное поведение для вашей игры, включая движение в игре и другое поведение. Для этой игры вам нужно сделать несколько вещей, чтобы все правильно обновить:
- Вы проверяете, приостановлена ли игра. Если да, то вы можете просто выйти, чтобы больше никаких обновлений не происходило.
- Вы обновляете все свои спрайты, чтобы заставить их двигаться.
- Вы проверяете, не переместился ли спрайт игрока за пределы экрана. Если это так, то просто верните его обратно на экран.
На этом пока все. Вот как выглядит этот код:
189def on_update(self, delta_time: float):
190 """Update the positions and statuses of all game objects
191 If paused, do nothing
192
193 Arguments:
194 delta_time {float} -- Time since the last update
195 """
196
197 # If paused, don't update anything
198 if self.paused:
199 return
200
201 # Update everything
202 self.all_sprites.update()
203
204 # Keep the player on screen
205 if self.player.top > self.height:
206 self.player.top = self.height
207 if self.player.right > self.width:
208 self.player.right = self.width
209 if self.player.bottom < 0:
210 self.player.bottom = 0
211 if self.player.left < 0:
212 self.player.left = 0
В строке 198 вы проверяете, приостановлена ли игра, и просто возвращаете ее, если да. При этом весь оставшийся код пропускается, поэтому перемещения не будет. Все перемещения спрайтов обрабатываются строкой 202. Эта единственная строка работает по трем причинам:
- Каждый спрайт является членом списка
self.all_sprites
. - Вызов для
self.all_sprites.update()
приводит к вызову.update()
для каждого спрайта в списке. - Каждый спрайт в списке имеет
.velocity
(состоящий из атрибутов.change_x
и.change_y
) и будет обрабатывать свои собственные движение, когда вызывается его.update()
.
Наконец, вы проверяете, находится ли спрайт игрока за пределами экрана в строках с 205 по 212, сравнивая края спрайтов с краями окна. Например, в строках 205 и 206, если self.player.top
находится за пределами верхней части экрана, вы возвращаете self.player.top
в верхнюю часть экрана. Теперь, когда все обновлено, вы можете рисовать все.
Рисунок на окне
Поскольку обновления игровых объектов происходят в .on_update()
, представляется целесообразным, чтобы отрисовка игровых объектов выполнялась методом, называемым .on_draw()
. Поскольку вы организовали все в списки спрайтов, ваш код для этого метода очень короткий:
231def on_draw(self):
232 """Draw all game objects
233 """
234 arcade.start_render()
235 self.all_sprites.draw()
Все отрисовки начинаются с вызова arcade.start_render()
в строке 234. Как и при обновлении, вы можете отрисовать все свои спрайты сразу, просто вызвав self.all_sprites.draw()
в строке 235. Теперь вам осталось поработать над последней частью вашей игры на Python, и это самая последняя часть первоначального проекта:
Когда игрок натыкается на препятствие или пользователь закрывает окно, игра заканчивается.
Это собственно часть игры! Прямо сейчас враги будут пролетать сквозь ваш игровой спрайт, ничего не делая. Давайте посмотрим, как вы можете добавить эту функциональность.
Обнаружение столкновений
Все игры основаны на столкновениях в той или иной форме, даже в некомпьютерных играх. Без реальных или виртуальных столкновений не было бы хоккейных голов, забиваемых с разбега, двойных шестерок в нардах, а в шахматах не было бы способа захватить ферзя противника на конце конской вилки.
Обнаружение столкновений в компьютерных играх требуется, чтобы программист определял, занимают ли два игровых объекта частично одно и то же пространство на экране. Вы используете функцию обнаружения столкновений, чтобы стрелять по врагам, ограничивать передвижение игрока стенами и полом, а также создавать препятствия, которых следует избегать. В зависимости от используемых игровых объектов и желаемого поведения логика обнаружения столкновений может потребовать сложной математической обработки.
Однако вам не обязательно писать свой собственный код обнаружения столкновений с помощью arcade
. Вы можете использовать один из трех различных методов Sprite
для быстрого обнаружения столкновений:
Sprite.collides_with_point((x,y))
возвращаетTrue
, если заданная точка(x,y)
находится в пределах границы текущего спрайта, иFalse
в противном случае.Sprite.collides_with_sprite(Sprite)
возвращаетTrue
, если данный спрайт перекрывается с текущим спрайтом, иFalse
в противном случае.Sprite.collides_with_list(SpriteList)
возвращает список, содержащий все спрайты вSpriteList
, которые перекрываются с текущим спрайтом. Если нет перекрывающихся спрайтов, то список будет пустым, то есть его длина будет равна нулю.
Поскольку вас интересует, столкнулся ли однопользовательский спрайт с каким-либо из вражеских спрайтов, последний метод - это именно то, что вам нужно. Вы вызываете self.player.collides_with_list(self.enemies_list)
и проверяете, содержит ли возвращаемый список какие-либо спрайты. Если это так, то вы заканчиваете игру.
Итак, куда вы сделаете этот звонок? Лучше всего это сделать в .on_update()
, непосредственно перед тем, как вы обновите позиции всего:
189def on_update(self, delta_time: float):
190 """Update the positions and statuses of all game objects
191 If paused, do nothing
192
193 Arguments:
194 delta_time {float} -- Time since the last update
195 """
196
197 # If paused, don't update anything
198 if self.paused:
199 return
200
201 # Did you hit anything? If so, end the game
202 if self.player.collides_with_list(self.enemies_list):
203 arcade.close_window()
204
205 # Update everything
206 self.all_sprites.update()
Строки 202 и 203 проверяют наличие коллизии между player
и любым спрайтом в .enemies_list
. Если возвращаемый список содержит какие-либо спрайты, это указывает на столкновение, и вы можете завершить игру. Итак, зачем вам проверять перед обновлением позиций всего? Запомните последовательность действий в игровом цикле Python:
- Вы обновляете состояния игровых объектов. Вы делаете это в
.on_update()
. - Вы рисуете все игровые объекты на их новых местах. Вы делаете это в
.on_draw()
.
Если вы проверите наличие коллизий после обновления всего в .on_update()
, то при обнаружении коллизии никакие новые позиции отображаться не будут. На самом деле вы проверяете наличие коллизий на основе позиций спрайтов, которые еще не были показаны пользователю. Игроку может показаться, что игра закончилась до того, как произошло реальное столкновение! При первой проверке убедитесь, что то, что видно игроку, совпадает с состоянием игры, которое вы проверяете.
Теперь у вас есть игра на Python, которая выглядит привлекательно и представляет собой сложную задачу! Теперь вы можете добавить несколько дополнительных функций, которые помогут выделить вашу игру на Python.
Дополнительные услуги
Есть еще много возможностей, которые вы можете добавить в свою игру на Python, чтобы она выделялась на общем фоне. В дополнение к возможностям, которые вы не реализовали в игровом дизайне, вы можете иметь в виду и другие. В этом разделе будут рассмотрены две функции, которые придадут вашей игре на Python дополнительный эффект за счет добавления звуковых эффектов и управления скоростью игры.
Звук
Звук - важная составляющая любой компьютерной игры. Без звука ваша игра на Python - от взрывов и вражеских насмешек до фоновой музыки - выглядит немного скучноватой. Изначально arcade
обеспечивает поддержку файлов формата WAV. Если установлена и доступна библиотека ffmpeg, то arcade
также поддерживает Ogg и MP3 форматирование файлов. Вы добавите три различных звуковых эффекта и немного фоновой музыки:
- Первый звуковой эффект воспроизводится по мере продвижения игрока вверх.
- Второй звуковой эффект воспроизводится, когда игрок перемещается вниз.
- Третий звуковой эффект воспроизводится при столкновении.
- Фоновая музыка - это последнее, что вы добавите.
Вы начнете со звуковых эффектов.
Звуковые эффекты
Прежде чем вы сможете воспроизводить любой из этих звуков, вы должны загрузить их. Вы делаете это в .setup()
:
66# Spawn a new enemy every 0.25 seconds
67arcade.schedule(self.add_enemy, 0.25)
68
69# Spawn a new cloud every second
70arcade.schedule(self.add_cloud, 1.0)
71
72# Load your sounds
73# Sound sources: Jon Fincher
74self.collision_sound = arcade.load_sound("sounds/Collision.wav")
75self.move_up_sound = arcade.load_sound("sounds/Rising_putter.wav")
76self.move_down_sound = arcade.load_sound("sounds/Falling_putter.wav")
Как и в случае со спрайтовыми изображениями, рекомендуется размещать все ваши звуки в одной подпапке.
Когда звуки будут загружены, вы сможете воспроизвести их в подходящее время. Для .move_up_sound
и .move_down_sound
это происходит во время .on_key_press()
обработчика:
134def on_key_press(self, symbol, modifiers):
135 """Handle user keyboard input
136 Q: Quit the game
137 P: Pause the game
138 I/J/K/L: Move Up, Left, Down, Right
139 Arrows: Move Up, Left, Down, Right
140
141 Arguments:
142 symbol {int} -- Which key was pressed
143 modifiers {int} -- Which modifiers were pressed
144 """
145 if symbol == arcade.key.Q:
146 # Quit immediately
147 arcade.close_window()
148
149 if symbol == arcade.key.P:
150 self.paused = not self.paused
151
152 if symbol == arcade.key.I or symbol == arcade.key.UP:
153 self.player.change_y = 5
154 arcade.play_sound(self.move_up_sound)
155
156 if symbol == arcade.key.K or symbol == arcade.key.DOWN:
157 self.player.change_y = -5
158 arcade.play_sound(self.move_down_sound)
Теперь всякий раз, когда игрок перемещается вверх или вниз, в вашей игре на Python будет воспроизводиться звук.
Звук столкновения будет воспроизводиться всякий раз, когда .on_update()
обнаружит столкновение:
def on_update(self, delta_time: float):
"""Update the positions and statuses of all game objects
If paused, do nothing
Arguments:
delta_time {float} -- Time since the last update
"""
# If paused, don't update anything
if self.paused:
return
# Did you hit anything? If so, end the game
if len(self.player.collides_with_list(self.enemies_list)) > 0:
arcade.play_sound(self.collision_sound)
arcade.close_window()
# Update everything
self.all_sprites.update()
Непосредственно перед закрытием окна будет воспроизведен звук столкновения.
Фоновая музыка
Добавление фоновой музыки выполняется по той же схеме, что и добавление звуковых эффектов. Разница лишь в том, когда она начинает воспроизводиться. Что касается фоновой музыки, то вы обычно запускаете ее в начале уровня, поэтому загрузите и включите звук в .setup()
:
66# Spawn a new enemy every 0.25 seconds
67arcade.schedule(self.add_enemy, 0.25)
68
69# Spawn a new cloud every second
70arcade.schedule(self.add_cloud, 1.0)
71
72# Load your background music
73# Sound source: http://ccmixter.org/files/Apoxode/59262
74# License: https://creativecommons.org/licenses/by/3.0/
75self.background_music = arcade.load_sound(
76 "sounds/Apoxode_-_Electric_1.wav"
77)
78
79# Load your sounds
80# Sound sources: Jon Fincher
81self.collision_sound = arcade.load_sound("sounds/Collision.wav")
82self.move_up_sound = arcade.load_sound("sounds/Rising_putter.wav")
83self.move_down_sound = arcade.load_sound("sounds/Falling_putter.wav")
84
85# Start the background music
86arcade.play_sound(self.background_music)
Теперь у вас есть не только звуковые эффекты, но и отличная фоновая музыка!
Ограничения по звуку
Существуют некоторые ограничения на то, что arcade
в настоящее время может делать со звуком:
- Нет регулировки громкости для любых звуков.
- Невозможно повторить звук, например, зацикливание фоновой музыки.
- Невозможно определить, воспроизводится ли звук в данный момент, прежде чем пытаться остановить его.
- Без
ffmpeg
вы ограничены звуками в формате WAV, которые могут быть большими.
Несмотря на эти ограничения, стоит приложить усилия, чтобы добавить звук в вашу arcade
игру на Python.
Скорость игры на Python
Скорость любой игры определяется ее частотой кадров, которая представляет собой частоту обновления графики на экране. Более высокая частота кадров обычно приводит к более плавному игровому процессу, в то время как более низкая частота кадров дает вам больше времени для выполнения сложных вычислений.
Частота кадров в arcade
игре на Python регулируется игровым циклом в arcade.run()
. Игровой цикл Python вызывает .on_update()
и .on_draw()
примерно 60 раз в секунду. Таким образом, частота кадров в игре составляет 60 кадров в секунду или 60 кадров в секунду.
Обратите внимание, что в приведенном выше описании указано, что частота кадров составляет примерно 60 кадров в секунду. Точность этой частоты не гарантируется. Оно может увеличиваться или уменьшаться в зависимости от многих факторов, таких как нагрузка на компьютер или более длительное, чем обычно, время обновления. Как программист игр на Python, вы хотите убедиться, что ваша игра на Python работает одинаково, независимо от того, работает ли она со скоростью 60 кадров в секунду, 30 кадров в секунду или с любой другой скоростью. Итак, как вы это делаете?
Перемещение по времени
Представьте себе объект, движущийся в пространстве со скоростью 60 километров в минуту. Вы можете рассчитать, какое расстояние объект пролетит за любой промежуток времени, умножив это время на скорость объекта:
Объект перемещается на 120 километров за 2 минуты и на 30 километров за полминуты.
Вы можете использовать этот же расчет для перемещения ваших спрайтов с постоянной скоростью независимо от частоты кадров. Если вы укажете скорость спрайта в пикселях в секунду, то сможете подсчитать, на сколько пикселей он перемещается за каждый кадр, если знаете, сколько времени прошло с момента появления последнего кадра. Откуда вы это знаете?
Напомним, что .on_update()
принимает единственный параметр, delta_time
. Это количество времени в секундах, прошедшее с момента последнего вызова .on_update()
. Для игры, работающей со скоростью 60 кадров в секунду, delta_time
будет составлять 1/60 секунды, или примерно 0,0167 секунды. Если вы умножите прошедшее время на количество перемещений спрайта, то убедитесь, что перемещение спрайта основано на прошедшем времени, а не на частоте кадров.
Обновление перемещения спрайта
Есть только одна проблема — ни Sprite.on_update()
, ни SpriteList.on_update()
не принимают параметр delta_time
. Это означает, что нет способа передать его вашим спрайтам для автоматической обработки. Следовательно, чтобы реализовать эту функцию, вам необходимо обновить позиции ваших спрайтов вручную. Замените вызов self.all_sprites.update()
на .on_update()
следующим кодом:
def on_update(self, delta_time: float):
"""Update the positions and statuses of all game objects
If paused, do nothing
Arguments:
delta_time {float} -- Time since the last update
"""
# If paused, don't update anything
if self.paused:
return
# Did you hit anything? If so, end the game
if len(self.player.collides_with_list(self.enemies_list)) > 0:
arcade.play_sound(self.collision_sound)
arcade.close_window()
# Update everything
for sprite in self.all_sprites:
sprite.center_x = int(
sprite.center_x + sprite.change_x * delta_time
)
sprite.center_y = int(
sprite.center_y + sprite.change_y * delta_time
)
В этом новом коде вы изменяете положение каждого спрайта вручную, умножая .change_x
и .change_y
на delta_time
. Это гарантирует, что спрайт перемещается на постоянное расстояние каждую секунду, а не на постоянное расстояние в каждом кадре, что может сгладить игровой процесс.
Обновление параметров спрайта
Конечно, это также означает, что вам следует пересмотреть и скорректировать начальное положение и скорость всех ваших спрайтов. Вспомните, какое положение и .velocity
задаются вашим вражеским спрайтам при их создании:
93def add_enemy(self, delta_time: float):
94 """Adds a new enemy to the screen
95
96 Arguments:
97 delta_time {float} -- How much time as passed since the last call
98 """
99
100 # First, create the new enemy sprite
101 enemy = FlyingSprite("images/missile.png", SCALING)
102
103 # Set its position to a random height and off screen right
104 enemy.left = random.randint(self.width, self.width + 80)
105 enemy.top = random.randint(10, self.height - 10)
106
107 # Set its speed to a random speed heading left
108 enemy.velocity = (random.randint(-20, -5), 0)
Благодаря новым расчетам движения, основанным на времени, ваши враги теперь будут перемещаться с максимальной скоростью 20 пикселей в секунду. Это означает, что в окне шириной 800 пикселей самому быстрому врагу потребуется сорок секунд, чтобы пересечь экран. Далее, если враг появится в восьмидесяти пикселях справа от окна, то самому быстрому потребуется целых четыре секунды, чтобы просто появиться!
Настройка положения и скорости - это часть того, чтобы сделать вашу игру на Python интересной и воспроизводимой. Начните с настройки каждого параметра в десять раз, а затем отрегулируйте его. Такая же переоценка и корректировка должны быть произведены с облаками, а также со скоростью передвижения игрока.
Настройки и усовершенствования
При разработке игры на Python вы не добавили несколько функций. Чтобы дополнить этот список, вот несколько дополнительных улучшений и хитростей, которые вы, возможно, заметили во время игрового процесса и тестирования на Python:
- Когда игра приостановлена, враги и облака по-прежнему генерируются с помощью запланированных функций. Это означает, что, когда игра не приостановлена, вас поджидает огромная волна игроков. Как вы можете предотвратить это?
- Как упоминалось выше, из-за некоторых ограничений звукового движка
arcade
фоновая музыка не повторяется. Как вы решаете эту проблему? - Когда игрок сталкивается с противником, игра внезапно заканчивается без воспроизведения звука столкновения. Как сохранить игру открытой в течение секунды или двух, прежде чем окно закроется?
Возможно, вы могли бы добавить и другие улучшения. Попробуйте применить некоторые из них в качестве упражнения и поделитесь своими результатами в комментариях!
Примечание к источникам
Возможно, вы заметили комментарий при загрузке фоновой музыки с указанием источника музыки и ссылкой на лицензию Creative Commons. Это было сделано потому, что этого требует создатель этого звука. В лицензионных требованиях указано, что для использования звука должны быть указаны как надлежащие авторские права, так и ссылка на лицензию.
Вот несколько источников информации о музыке, звуке и искусстве, в которых вы можете найти полезный контент:
- OpenGameArt.org: звуки, звуковые эффекты, спрайты и другие иллюстрации
- Kenney.nl: звуки, звуковые эффекты, спрайты и другие иллюстрации
- Геймерское искусство в формате 2D: спрайты и другие иллюстрации
- CC-микшер: звуки и звуковые эффекты
- Бесплатный звук: звуки и звуковые эффекты
Создавая свои игры и используя загруженный контент, такой как рисунки, музыка или код из других источников, пожалуйста, убедитесь, что вы соблюдаете условия лицензирования этих источников.
Заключение
Компьютерные игры - отличное введение в программирование, а библиотека arcade
- отличный первый шаг. Разработанная как современный фреймворк на Python для создания игр, вы можете создавать захватывающие игры на Python с великолепной графикой и звуком.
На протяжении всего этого урока вы учились тому, как:
- Установите библиотеку
arcade
- Рисуйте элементы на экране
- Работа с
arcade
игровым циклом Python - Управление графическими элементами на экране
- Обработка пользовательского ввода
- Воспроизведение звуковых эффектов и музыки
- Опишите, чем программирование игр на Python в
arcade
отличается отpygame
Я надеюсь, что вы дадите arcade
попробовать. Если да, то, пожалуйста, оставьте комментарий ниже, и удачи в работе с Python! Вы можете скачать все материалы, использованные в этом руководстве, по ссылке ниже:
Загрузите ресурсы: Нажмите здесь, чтобы загрузить ресурсы, которые вы будете использовать для создания аркадной игры в этом руководстве.
Back to Top