- PVSM.RU - https://www.pvsm.ru -
Всем привет!
Мы продолжаем делится с вами интересными найденными вещами про питончик. Сегодня вот решили разобраться с 2D играми. Это, конечно, немного попроще, чем то, что проходят у нас на курсе «Разработчик Python» [1], но не менее интересно это уж точно.
Поехали.
Python — выдающийся язык для начинающих изучать программирование. Он также идеально подходит тем, кто хочет “просто взять и сделать”, а не тратить кучу времени на шаблонный код. Arcade [2] — библиотека Python для создания 2D игр, с низким порогом вхождения, но очень функциональная в опытных руках. В этом статье я объясню, как начать использовать Python и Arcade для программирования игр.
Я начал разрабатывать на Arcade после преподавания азов библиотеки PyGame [3]студентам. Я очно преподавал PyGames в течение почти 10 лет, а также разработал ProgramArcadeGames.com [4] для обучения онлайн. PyGames отличная, но в какой-то момент я понял, что устал тратить время на оправдание багов, которые никогда не фиксятся [5].
Меня беспокоило преподавание таких вещей, как событийный цикл [6], которым уже почти не пользовались. И был целый раздел [7], в котором я объяснял, почему y-координаты повернуты в противоположном направлении. PyGames обновлялась редко и базировалась на старой библиотеке SDL 1 [8], а не чем-то более современном вроде OpenGL [9]. На светлое будущее я не рассчитывал.
В моих мечтах была простая и мощная библиотека, которая бы использовала новые фичи Python 3, например, декораторы и тайп-хинтинг. Ей оказалась Arcade. Посмотрим, как начать ее использовать.
Установка
Arcade, как и многие другие пакеты, доступна на PyPi [10], а значит, можно установить Arcade при помощи команды pip (или pipenv [11]). Если Python уже установлен, скорее всего можно просто открыть командную строку Windows и написать:
pip install arcade
А в Linux и MacOS:
pip3 install arcade
Для более детализированной инструкции по установке, почитайте документацию [12]по установке Arcade.
Простой рисунок
Вы можете открыть окно и нарисовать простой рисунок всего несколькими строчками кода. В качестве примера, нарисуем смайлик, как на картинке ниже:
Скрипт ниже показывает, как это сделать, используя команды [13]рисования Arcade. Заметьте, что вам не обязательно знать, как использовать классы или определять функции. Программирование с быстрым визуальным фидбеком — хороший старт для тех, кто только учится.
import arcade
# Задать константы для размеров экрана
SCREEN_WIDTH = 600
SCREEN_HEIGHT = 600
# Открыть окно. Задать заголовок и размеры окна (ширина и высота)
arcade.open_window(SCREEN_WIDTH, SCREEN_HEIGHT, "Drawing Example")
# Задать белый цвет фона.
# Для просмотра списка названий цветов прочитайте:
# http://arcade.academy/arcade.color.html
# Цвета также можно задавать в (красный, зеленый, синий) и
# (красный, зеленый, синий, альфа) формате.
arcade.set_background_color(arcade.color.WHITE)
# Начать процесс рендера. Это нужно сделать до команд рисования
arcade.start_render()
# Нарисовать лицо
x = 300
y = 300
radius = 200
arcade.draw_circle_filled(x, y, radius, arcade.color.YELLOW)
# Нарисовать правый глаз
x = 370
y = 350
radius = 20
arcade.draw_circle_filled(x, y, radius, arcade.color.BLACK)
# Нарисовать левый глаз
x = 230
y = 350
radius = 20
arcade.draw_circle_filled(x, y, radius, arcade.color.BLACK)
# Нарисовать улыбку
x = 300
y = 280
width = 120
height = 100
start_angle = 190
end_angle = 350
arcade.draw_arc_outline(x, y, width, height, arcade.color.BLACK, start_angle,
end_angle, 10)
# Завершить рисование и показать результат
arcade.finish_render()
# Держать окно открытым до тех пор, пока пользователь не нажмет кнопку “закрыть”
arcade.run()
Использование функций
Конечно, писать код в глобальном контексте — не лучший способ. К счастью, использование функций поможет улучшить ваш код. Ниже приведен пример того, как нарисовать елку в заданных координатах (x, y), используя функцию:
def draw_pine_tree(x, y):
""" Эта функция рисует елку в указанном месте"""
# Нарисовать треугольник поверх ствола.
# Необходимы три x, y точки для рисования треугольника.
arcade.draw_triangle_filled(x + 40, y, # Point 1
x, y - 100, # Point 2
x + 80, y - 100, # Point 3
arcade.color.DARK_GREEN)
# Нарисовать ствол
arcade.draw_lrtb_rectangle_filled(x + 30, x + 50, y - 100, y - 140,
arcade.color.DARK_BROWN)
Для полного примера, посмотрите рисунок с функциями [14].
Более опытные программисты знают, что современные программы сначала загружают графическую информацию на видеокарту, а затем просят ее отрисовать batch-файлом. Arcade это поддерживае [15]т. Индивидуальная отрисовка 10000 прямоугольников занимает 0.8 секунды. Отрисовка того же количества батником займет менее 0.001 секунды.
Класс Window
Большие программы обычно базируются на классе Window [16]или используют декораторы [17]. Это позволяет программисту писать код, контролирующий отрисовку, обновление и обработку входных данных пользователя. Ниже приведен шаблон для программы с Window-основой.
import arcade
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600
class MyGame(arcade.Window):
""" Главный класс приложения. """
def __init__(self, width, height):
super().__init__(width, height)
arcade.set_background_color(arcade.color.AMAZON)
def setup(self):
# Настроить игру здесь
pass
def on_draw(self):
""" Отрендерить этот экран. """
arcade.start_render()
# Здесь код рисунка
def update(self, delta_time):
""" Здесь вся игровая логика и логика перемещения."""
pass
def main():
game = MyGame(SCREEN_WIDTH, SCREEN_HEIGHT)
game.setup()
arcade.run()
if __name__ == "__main__":
main()
В классе Window есть несколько методов, которые ваши программы могут переопределять для обеспечения функциональности. Вот список тех, что используются чаще всего:
Спрайты
Спрайты [18] — простой способ создания 2D bitmap объектов в Arcade. В нем есть методы, позволяющие с легкостью рисовать, перемещать и анимировать спрайты. Также можно использовать спрайты для отслеживания коллизий между объектами.
Создание спрайта
Создать инстанс Sprite [19]класса Arcade очень легко. Программисту необходимо только название файла изображения, на котором будет основываться спрайт, и, опционально, число раз для увеличения или уменьшения изображения. Например:
SPRITE_SCALING_COIN = 0.2
coin = arcade.Sprite("coin_01.png", SPRITE_SCALING_COIN)
Этот код создает спрайт, используя изображение coin_01.png. Картинка уменьшится на 20% по сравнении с шириной и высотой оригинала.
Список спрайтов
Спрайты обычно организуются в списки. Они помогают упростить их управление. Спрайты в списке будут использовать OpenGl для групповой batch-отрисовки. Нижеприведенный код настраивает игру, где есть игрок и множество монет, которые игрок должен собрать. Мы используем два списка — один для игрока и один для монеток.
def setup(self):
""" Настроить игру и инициализировать переменные. """
# Создать список спрайтов
self.player_list = arcade.SpriteList()
self.coin_list = arcade.SpriteList()
# Счет
self.score = 0
# Задать игрока и
# Его изображение из kenney.nl
self.player_sprite = arcade.Sprite("images/character.png",
SPRITE_SCALING_PLAYER)
self.player_sprite.center_x = 50 # Стартовая позиция
self.player_sprite.center_y = 50
self.player_list.append(self.player_sprite)
# Создать монетки
for i in range(COIN_COUNT):
# Создать инстанс монеток
# и их изображение из kenney.nl
coin = arcade.Sprite("images/coin_01.png", SPRITE_SCALING_COIN)
# Задать положение монеток
coin.center_x = random.randrange(SCREEN_WIDTH)
coin.center_y = random.randrange(SCREEN_HEIGHT)
# Добавить монетку к списку
self.coin_list.append(coin)
Мы с легкостью можем отрисовать все монетки в списке монеток:
def on_draw(self):
""" Нарисовать все """
arcade.start_render()
self.coin_list.draw()
self.player_list.draw()
Отслеживание коллизий спрайтов
Функция check_for_collision_with_list позволяет увидеть, если спрайт наталкивается на другой спрайт из списка. Используем ее, чтобы увидеть все монетки, с которыми пересекается спрайт игрока. Применив простой for- цикл, можно избавиться от монетки в игре и увеличить счет.
def update(self, delta_time):
# Сгенерировать список всех спрайтов монеток, которые пересекаются с игроком.
coins_hit_list = arcade.check_for_collision_with_list(self.player_sprite,
self.coin_list)
# Пройтись циклом через все пересекаемые спрайты, удаляя их и увеличивая счет.
for coin in coins_hit_list:
coin.kill()
self.score += 1
С полным примером можно ознакомиться в collect_coins.py [20].
Игровая физика
Во многих играх есть физика в том или ином виде. Самые простое, например, что top-down игры не позволяют игроку проходить сквозь стены. Платформеры добавляют сложности с гравитацией и движущимися платформами. Некоторые игры используют полноценные физические 2D движки с массами, трением, пружинами и тд.
Top-down игры
Для простых игр с видом сверху программе на Arcade необходим список стен (или чего-то подобного), через которые игрок не сможет проходить. Обычно я называю это wall_list. Затем создается физический движок в установочном коде класса Window:
self.physics_engine = arcade.PhysicsEngineSimple(self.player_sprite, self.wall_list)
player_sprite получает вектор движения с двумя атрибутами change_x и change_y. Просто пример использования — перемещение игрока с помощью клавиатуры.
MOVEMENT_SPEED = 5
def on_key_press(self, key, modifiers):
"""Вызывается при нажатии пользователем клавиши"""
if key == arcade.key.UP:
self.player_sprite.change_y = MOVEMENT_SPEED
elif key == arcade.key.DOWN:
self.player_sprite.change_y = -MOVEMENT_SPEED
elif key == arcade.key.LEFT:
self.player_sprite.change_x = -MOVEMENT_SPEED
elif key == arcade.key.RIGHT:
self.player_sprite.change_x = MOVEMENT_SPEED
def on_key_release(self, key, modifiers):
"""Вызывается, когда пользователь отпускает клавишу"""
if key == arcade.key.UP or key == arcade.key.DOWN:
self.player_sprite.change_y = 0
elif key == arcade.key.LEFT or key == arcade.key.RIGHT:
self.player_sprite.change_x = 0
Несмотря на то что этот код задает скорость игрока, он его не перемещает. Метод update в классе Window вызывает physics_engine.update(), что заставит игрока двигаться, но не через стены.
def update(self, delta_time):
""" Передвижение и игровая логика """
self.physics_engine.update()
Пример полностью можно посмотреть в sprite_move_walls.py [21].
Платформеры
Переход к платформеру с видом сбоку достаточно прост. Программисту необходимо переключить физический движок на PhysicsEnginePlatformer и добавить гравитационную константу.
self.physics_engine = arcade.PhysicsEnginePlatformer(self.player_sprite,
self.wall_list,
gravity_constant=GRAVITY)
Для добавления тайлов и блоков, из которых будет состоять уровень, можно использовать программу вроде Tiled [22].
Пример доступен в sprite_tiled_map.py. [23]
Учитесь на примере
Учиться на примере — один из лучших методов. В библиотеке Arcade есть большой список образцов программ [24], на которые можно ориентироваться при создании игры. Эти примеры раскрывают концепты игр, о которых спрашивали мои онлайн и оффлайн студенты в течение нескольких лет.
Запускать демки при установленной Arcade совсем не сложно. В начале программы каждого примера есть комментарий с командой, которую нужно ввести в командную строку для запуска этого примера. Например:
python -m arcade.examples.sprite_moving_platforms
THE END
Как всегда ждём ваши комментарии и вопросы, которые можно оставить тут или зайти к Стасу [25]на день открытых дверей [26].
Автор: MaxRokatansky
Источник [27]
Сайт-источник PVSM.RU: https://www.pvsm.ru
Путь до страницы источника: https://www.pvsm.ru/python/288762
Ссылки в тексте:
[1] «Разработчик Python»: https://otus.pw/dNOU/
[2] Arcade: http://arcade.academy/
[3] PyGame : https://www.pygame.org/
[4] ProgramArcadeGames.com: http://programarcadegames.com/
[5] которые никогда не фиксятся: https://stackoverflow.com/questions/10148479/artifacts-when-drawing-primitives-with-pygame
[6] событийный цикл: https://www.pygame.org/docs/tut/tom_games2.html
[7] целый раздел: http://programarcadegames.com/index.php?chapter=introduction_to_graphics&lang=en#section_5_1
[8] SDL 1: https://www.libsdl.org/download-1.2.php
[9] OpenGL: https://opensource.com/article/18/4/opengl-bindings-bash
[10] PyPi: https://pypi.python.org/pypi
[11] pipenv: https://opensource.com/article/18/2/why-python-devs-should-use-pipenv
[12] документацию : http://arcade.academy/installation.html
[13] команды : http://arcade.academy/quick_index.html#drawing-module
[14] рисунок с функциями: http://arcade.academy/examples/drawing_with_functions.html
[15] Arcade это поддерживае: http://arcade.academy/examples/shape_list_demo.html
[16] Window : http://arcade.academy/arcade.html#arcade.application.Window
[17] декораторы: http://arcade.academy/examples/decorator_drawing_example.html#decorator-drawing-example
[18] Спрайты : https://ru.wikipedia.org/wiki/%D0%A1%D0%BF%D1%80%D0%B0%D0%B9%D1%82_(%D0%BA%D0%BE%D0%BC%D0%BF%D1%8C%D1%8E%D1%82%D0%B5%D1%80%D0%BD%D0%B0%D1%8F_%D0%B3%D1%80%D0%B0%D1%84%D0%B8%D0%BA%D0%B0)
[19] Sprite : http://arcade.academy/arcade.html#arcade.sprite.Sprite
[20] collect_coins.py: http://arcade.academy/examples/sprite_collect_coins.html
[21] sprite_move_walls.py: http://arcade.academy/examples/sprite_move_walls.html
[22] Tiled: http://www.mapeditor.org/
[23] sprite_tiled_map.py.: http://arcade.academy/examples/sprite_tiled_map.html
[24] образцов программ: http://arcade.academy/examples/index.html
[25] Стасу : https://otus.pw/rr2n/
[26] день открытых дверей: https://otus.pw/fGCp/
[27] Источник: https://habr.com/post/419761/?utm_campaign=419761
Нажмите здесь для печати.