Полноценный 2D-платформер на Python в 2023? Мой опыт

Моя цель - предложение широкого ассортимента товаров и услуг на постоянно высоком качестве обслуживания по самым выгодным ценам.

Говорят, что на Python легко и просто создавать платформеры. Правда ли?

Предисловие

Все мы были когда-то детьми. И те, кто вырос в 90-ые, наверняка играли в приставку Денди (в США она называлась NES - Nintendo Entertainment System). Среди всех игр была одна игра, которая мне особенно запомнилась, так как была не похожа на все остальные. Это игра The Addams Family (1992 год, студия Ocean). В игре была какая-то своя атмосфера. И мне захотелось создать что-то похожее.

Придумываем сюжет и геймплей

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

Рисуем ассеты

Перед тем как приступить к созданию ассетов (разных картинок, которые потом можно будет анимировать), надо разобраться в каком разрешении будет работать игра. У всех разные мониторы с разным разрешением. И не у всех даже FullHD. Поэтому выбираем 720p - то есть разрешение 1280х720 пикселей. Для такого разрешения органично будут смотреться плитки земли размером 64х64 пикселя. Берем любой векторный графический редактор и начинаем рисовать.

Рисуем ассеты поместья
Рисуем ассеты поместья

Рисовал как мог, вспоминая как у всех ребят в школе по рисованию было «5», и только у меня одного «4». Вы могли заметить, что это все статические объекты, которые не имеют анимации. Ну а как же с анимированными объектами? Все просто, анимированные объекты - это те же отдельные картинки, у которых изменяется положение некоторых пикселей. Вот пример анимации на примере главного героя игры:

Анимация главного героя
Анимация главного героя

Собственно программирование

Инструмент для создания игр мы будем выбирать на основании того языка программирования, который более-менее знаем. В моем случае, это Python. Выбираем какую-нибудь современную версию языка - я выбрал Python 3.11.4. Для создания игр на Python существует библиотека Pygame. Причем это не графический движок типа Unity. Здесь нет графического интерфейса, а есть только набор разных классов, в которых есть свои атрибуты и методы. Эта библиотека служит для осуществления манипуляции графическими объектами на основе событий (events).

Заполняем словарики

Игру начинаем даже не с файла main.py,  а с файла settings.py, куда будут прописаны основные параметры и настройки игры. Помимо названия игры, длины и ширины окна игры, мы должны прописать доступы к ассетам. В связи с тем, что данных много, а в Python есть такой тип данных как словарь (dict), в основе которого лежит хеш-таблица, мы выбираем именно словарь и заполняем. Фрагмент такого словаря:

12: {
        'style': 'enemy',
        'type': 'tile',
        'menu': 'enemy',
        'menu_surf': 'images/menu/bug.png',
        'preview': 'images/preview/bug.png',
        'graphics': 'images/enemies/cementry/bug'
    },

С чего начинается родина - с main.py

Наконец-то поработаем с main.py. Конечно, будем использовать нашу любимую концепцию ООП. Есть такая штука как принципы SOLID, которым следует придерживаться при разработке программы. Некоторые из них я собираюсь нарушить, но вот один я никак нарушить не могу - буковка “S” - Single Resposibility Principle. Суть его в том, что каждый класс должен выполнять строго обозначенную функцию и быть ограниченным своей задачей. Не надо создавать классы, которые делают все сразу. Поэтому main.py будет класс Main, в котором есть главный цикл игры - бесконечный цикл с условием While, но все события будут обрабатываться в других отдельных классах, а в Main мы будем создавать экземпляры этих других классов.

Режим редакторы игры

Как думаете, что объединяет такие игры как Heroes of Might and Magic 3, The Elder Scrolls III: Morrowind и Max Payne. Их объединяет, что на диске с ними шел встроенный редактор уровней. Это мощнейший инструмент в разработке игры. Беда в том, что в Pygame ничего подобного нет, а значит мы его сами создадим. Здесь лучше найти какой-нибудь туториал. Я лично нашел на YouTube видео немецкого программиста Christian Koch “Creating a Mario Maker style game in Python” (канал ClearCode). На основе этого видео и создаем редактор уровней. Но нам надо как-нибудь сохранять те произведения искусства, которые мы создали. И здесь у нас есть выбор: либо сохранять как текстовый формат передачи данных (например, JSON), или же сохранять в бинарном виде, используя библиотеку pickle. Я решил, что для уровней у нас будут бинарные файлы, а для сохранений в процессе игры у нас будет JSON.

Сохраняем нарисованный уровень как бинарный файл
Сохраняем нарисованный уровень как бинарный файл

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

Коллизии и анимации спрайтов

Спрайт в Pygame -  это графическое изображение, которое представляет собой одну единицу анимации. Главное здесь - это коллизии и анимации. С коллизиями все просто - у классов Pygame есть встроенные методы для работы с коллизиями, например, collidepoint. Для анимаций в соответствующем классе мы создадим свой метод и используем тернарный оператор:

def animate(self, dt):
        self.frame_index += ANIMATION_SPEED * dt
        self.frame_index = 0 if self.frame_index >= len(
            self.animation_frames) else self.frame_index
        self.image = self.animation_frames[int(self.frame_index)]

Мы просто перебираем картинки в списке, и вызываем их одну за другой с помощью переменной self.frame_index. Тернарый оператор применяется, чтобы из бежать ошибки IndexError: list index out of range.

Обратите внимание на константу ANIMATION_SPEED. Дело в том, что у нас разлочен FPS в игре и скорость анимации никак не зависит от FPS.

Главное меню игры

Не помню какой обзорщик из YouTube 10-ых годов говорил, что главное меню - это как вешалка в театре. Для меня очень удобным было меню из игры The Elder Scrolls V: Skyrim - ничего лишнего. Нечто похожее и мы сделаем с учетом, что я не умею рисовать и игру мы делаем на Pygame. В главном меню мы должны сказать игроку как управлять персонажем в игре и создать возможности поменять язык, перейти в полноэкранный режим, уменьшить или увеличить громкость музыки и звуков, и перейти в режим редактора.

Музыкальная пауза

Если для звуков полно бесплатных ресурсов, где можно скачать free sounds, то музыку я решил сам написать для игры. Все рождается из импровизации. Записываем все на листочек, а потом ноты перебиваем в любой музыкальный midi-редактор, который поддерживает нотный стан.

Вот пример трека Garden из моей игры:

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

Итоги

Самое главное, что я понял, создание игры - это хорошая возможность прокачать ваши hard skills. Процесс создания игры заставляет вас решать множество задач. Библиотека Pygame - это один из самых лучших способов понять концепцию ООП в Python. Я, когда неправильно прописал условия для звуков и музыки, понял, как именно загружаются в память компьютера экземпляры классов, как в них инициализируются атрибуты и как работают методы. Также вы повторите весь базовый синтаксис Python - работу со всеми типами данных, включая файлы, и со стандартными библиотеками типа math, random, configparser, json и pickle.

Полный код игры доступен на моем GitHub

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

И что же получилось на выходе

Источник: https://habr.com/ru/articles/766162/


Интересные статьи

Интересные статьи

В данной статье я опишу причины, процесс и результат переноса почтовых сервисов на собственный сервер. Также расскажу про свои костыли и поделюсь ими. Если вдруг у тебя тоже много доменов с полуархивн...
Привет, дорогой читатель, в этой статье я хотел бы поделиться опытом работы с базой данных посредством ORM Dapper на .NET Core, а также рассказать полезные лайфхаки, которые нам помогают удобно исполь...
Как и CSS Grid, Flex Box довольно сложен, потому что состоит из двух составляющих: контейнера и элементов внутри него.Когда я начал изучать Flex, я хотел увидеть все, на ...
В конце прошлого года я поучаствовал в хакатоне "Лидеры цифровой трансформации" при поддержке Правительства Москвы. Мы решали задачу от Департамента культуры - рекомендат...
Многие задачи в области Computer Science, которые на первый взгляд кажутся новыми или уникальными, на самом деле уходят корнями в классические алгоритмы, методы кодирования и принципы разработки...