Как написать простенькую игру

Это статья для новичков в геймдеве. Для тех, кто хочет сделать игру, но не знает с чего начать.

Я постараюсь, по шагам, объяснить весь процесс от желания до релиза. Погнали!

Кто я такой?

Я гейм-дизайнер с 10-летним стажем. Работал в многих компаниях, например в Playgendary. Делал разное: и казуалки для мобилок, и танковый шутер для PC.

Теперь я инди-разработчик. Живу за счёт продажи своих игр. Выпустили 4 игры для PC и Консолей. Сейчас разрабатываю игру They Are Here: Alien Abduction Horror — хоррор от 1-го лица, про похищение пришельцами.

They Are Here: Alien Abduction Horror

Шаг 1. Запасись энтузиазмом

Энтузиазм — это топливо, которое ты сжигаешь при разработке. Оно позволит тебе делать игру после работы, когда устал, когда хочется отдохнуть.

Как пополнять запас энтузиазма? Смотри документалки, читай истории успеха разработчиков. Это мотивирует!

Смотри по сторонам: на другие игры, фильмы, кино, на новые технологии. Желание изучить что-то новое или сделать что-то похожее — это то, что нужно.

Шаг 2. Собери команду или сделай всё сам!

Одному — проще. Проще придумать идею и принимать решения. Не надо спорить и описывать задачи. Сделать игру одному — возможно. Я например сделал 4 игры один.

С командой — лучше. Лучше получается качество. Твои решения критикуются, и результат улучшается. Можно распределить обязанности и сделать игру быстрее. Последнюю игру я делаю в команде со своей женой. Она отвечает за историю, критикует мои решения, помогает с артом, ищет стримеров.

Короче — есть команда, круто! Нет команды — делай всё сам, это не трудно.

Типичный инди-разработчик

Шаг 3. Сформулируй цель разработки

Очень важно понять — для чего тебе всё это?

Ну например:

1. Трудоустройство в геймдев компанию.

Продукт — портфолио. Приоритет — качество исполнения.

Вопросы: На какую должность хотим устроиться? В какую компанию(и)? Какими играми занимается компания(и)? Чему нужно научиться?

2. Научиться делать игры, освоить навык.

Продукт — опытный образец. Приоритет- новые знания.

Вопросы: Какой навык освоить? Как сделать какую-то конкретную штуку?

3. Рассказать о чём то важном.

Продукт — манифест. Приоритет — донести идею до масс.

Вопросы: Поймут ли мою идею? Как сделать продукт более массовым?

4. Сделать игру о которой мечтал.

Продукт — мечта. Приоритет — воплотить своё видение.

Вопросы: Что я хочу видеть? Чем можно пренебречь? Как закончить проект?

5. Построить свой бизнес.

Продукт — актив. Приоритет — получить доход.

Вопросы: Какие игры лучше продаются? Сколько времени займет разработка? Как сократить это время?

Цель может быть не одна. Цели могут меняться от игры к игре.

Короче — ты должен ответить на вопрос — зачем я делаю эту игру?

А рально, зачем?

Шаг 4. Вспомни, что ты умеешь или любишь

Например, я и моя жена — фанаты фильмов ужасов про пришельцев. Типа «Знаки», «Мрачные небеса», «Секретные материалы». Поэтому нам проще работать над идеями и сценарием для They Are Here

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

Тян одобряет отталкиваться от умений и увлечений

Короче — твои умения и увлечения — это твои преимущества. Учитывай их при выборе платформы, движка, жанра игры. А пока, просто подумай над этим.

Шаг 5. Выбери платформу

Если просто, то есть 2 пути: Мобилки или ПК + Консоли.

Исходя из целей и умений нужно будет выбрать что-то одно. Это разные платформы, с разными играми, аудиторией и монетизацией.

Путь 1. Мобики

Аудитория:

  • Массовая аудитория. Дети, пенсионеры, скучающие продавщицы. Это не геймеры. Всё должно быть очень понятно и просто.
  • Играют по 1 — 5 минут. В перерывах, в очередях, на работе. Чтобы «убить время».
  • Ценится простая яркая графика.
  • Упор на простой, но залипательный кор-геймплей.

Плюсы:

  • Некоторые жанры (головоломки, аркады) — наиболее просты в разработке. Можно сделать небольшой прототип (1-5 уровней) и показать его работодателю, например.
  • Не требуется красивая или сложная графика. Главное — чтобы было понятно.
  • Простой геймплей и гейм-дизайн.
  • Будет плюсом, если сам привык к мобильным девайсам и играм.

Минусы:

  • Очень. Высокая. конкуренция. Игр миллионы и почти все они — бесплатные. Игроки приходят только с рекламы. Нет рекламы — нет игроков. Нет денег.
  • Монетизация. Нужно встраивать рекламу или внутри-игровые покупки в игру. Знать куда и как. Тестировать чтобы всё это работало.
  • Аналитика. Нужно понимать что такое LTV. Почему он должен быть > чем CPI. Встраивать аналитику в игру.
  • Будь готов делать по 20 прототипов или улучшать продукт, пока LTV не станет > CPI.
  • Заработать денег небольшой команде, можно только с издателем. Я лично не знаю других путей.

Короче — мобилки, это огромный супер-маркет. На полке лежит то, что окупает рекламу. Это конкуренция рекламных бюджетов. Если хочешь заработать на мобилках, то советую делать гипер-казуалки и работать с издателем.

Если пофиг на доход — классная, лёгкая платформа.

Если решишься, узнай подробнее про:

  • Гипер-казуальные игры (всё по теме гейм-дизайна и производства).
  • Как найти издателя гипер-казуальных игр.
  • Казуальная графика.
  • Low-poly графика.
  • Казуальные игроки (сложность казуальных игр и туториалы).
  • Аналитика мобильных игр (CPI, LTV, Retention).
  • Монетизация мобильных игр.
  • Оптимизация мобильных игр.
  • Google Play и App Store. Регистрация аккаунта разработчика. Правила и рекомендации. SEO.
  • Рекламные медиаторы и сети (Iron Source, AdMob и т.п.).
  • Сервисы рыночной аналитики мобильных игр (Sensor Tower, App Annie).

Путь 2. ПК + Консоли

Аудитория:

  • Хардкорные геймеры.
  • Играют по несколько часов. Дома. Чтобы погрузиться в игру.
  • Ценится реалистичная или стильная графика.
  • Упор на интересную историю или глубокий геймплей.

Плюсы:

  • Меньше конкуренция, чем на мобилках. Особенно на консолях.
  • Легче получить игроков и отзывы.
  • Можно хорошо заработать портировав игру на консоли, с помощью издателя.
  • Не надо возится с аналитикой и монетизацией.
  • С детства понятная платформа (ПК / Консоль) и аудитория (Геймеры).
  • Аудитория любит авторские, творческие, интересные игры.
  • Будет плюсом, если сам играешь на компе или приставке.

Минусы:

  • Плохо заходят простенькие игры (головоломки, аркады). Геймеры хотят получить опыт, вжиться в роль. Залипнуть надолго. Игра не должна выглядеть как что-то на пару минут.
  • Игры дольше в производстве. Но можно хитрить — делать маленькие игры, которые выглядят как большие, а также использовать готовые ассеты.
  • Нужно поработать над интересной идеей. Найти отличительные черты (USP), которые выделят проект.
  • Нужно продумать интересную историю или геймплей.
  • Более сложный геймдизайн.
  • Большая требовательность к качеству графики.

Короче — ПК, а особенно Консоли это элитный бутик. На полке лежит то, что пользуется спросом. Это конкуренция качества. Если хочешь заработать, то сделай интересную игру, и обязательно портируй её на консоли (через издателя). Подумай как сэкономить на производстве!

Если решишься, узнай подробнее про:

  • Геймдизайн компьютерных игр.
  • Нарратив, сторителлинг.
  • Как питчить игры.
  • Фичи игры / USP.
  • Что такое вертикальный срез.
  • Steam. Регистрация аккаунта разработчика. Оформление страницы. Тэги. Правила и рекомендации.
  • Маркетинг и продвижение инди-игр на Steam (рекомендую http://howtomarketagame.com/) Как сделать крутой постер, трейлер, скриншоты, ГИФки.
  • Портирование игр на консоли.
  • Издатели игр на консолях.
  • Конкурсы и фестивали инди-игр.
  • Работа с инфлюенсерами (ютуберами, стримерами).
  • Реалистичная графика.
  • Стилизованная графика.
  • Сервисы аналитики тэгов и жанров (SteamDB, Steamspy, SteamCharts, Game Data Crunch).
  • Сервисы рассылки ключей (Keymailer, Woovit)

Шаг 6. Узнай про геймдизайн и производство игр

Интересуйся тем Как делают игры (классный подкаст в твои наушники)

Рекомендую погуглить про:

  • Игровые механики, жанры и сеттинги.
  • Геймдизайн. Есть книга Джесси Шелла, она хорошая, но большая. Можешь гуглить про конкретный жанр.
  • Кор-геймплей и Мета-геймплей.
  • Левел-дизайн. Лучше гуглить про отдельный жанр.
  • Пользовательский интерфейс (UI) в играх.
  • Ассеты и маркетплейсы.

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

Шаг 7. Выбери движок и глянь уроки

Движок — это программа, в которой собирается игра. Это большой кухонный комбайн, в котором есть всё. Там программируется логика, собираются уровни, выставляется освещение, настраивается анимация, создаются материалы, вставляются звуки и т.п.

Про выбор движка написано много статей — погугли.

Если ты один, и не знаешь языков программирования, рекомендую Unreal Engine 4.

  • Там есть Blueprints — это визуальное программирование. Это проще чем писать код.
  • Красивый рендер «из коробки».
  • Есть большой маркетплейс с гововыми ассетами
  • Это популярный коммерчесский движок, на котором сделано очень много игр.
  • Можно сделать игру под все платформы. Можно встроить рекламу, инапы, аналитику.
  • Много уровков. Рекомендую Unreal Engine Rus
  • Классный интерфейс.
  • Куча встроенных функций.
  • Бесплатный до ляма баксов дохода.
Unreal Engine 4 Blueprints

Перед началом работы над игрой, сделай пару очень простых подделок «в стол».

Сделай змейку, пинг-понг и т.п. Пофиг на качество, пофиг на геймдизайн. Главное — попрактиковаться «на кошках», пощупать функции движка.

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

Короче — почитай про выбор движка. Потрать время на его изучие.

Шаг 8. Выбери жанр

Жанр — это твоя ниша. Жанр — это очень важно. Есть жанры, в которые никто не играет. А для некоторых нужно изучить много дополнительного материала.

Лучше выбрать жанр который:

  • Популярен на платформе. Игры этого жанра часто покупают или скачивают. Используй сайты для аналитики жанров.
  • Не слишком сложен в производстве. мморпг — не твой выбор.
  • Нравится тебе или команде. Ты разбираешься в нём или много играл в детстве.
Продажи игр в разных жанрах

Как только ты определилися с жанром — гугли всё по производству игр в этом жанре. Геймдизайн, графика, уровни, звуки. На что сделать акцент?

Поиграй в лучшие игры в этом жанре. Посмотри видео об этом жанре.

Короче — выбери жанр и узнай про него всё что можешь!

Шаг 9. Придумай идею, концепцию, USP

Идея — ядро твоей игры. Зерно, из которого вырастет проект.

Какая идея хорошая?

  • Понятная. Должна быть понятна каждому. Например, твоей маме.
  • Интересная. Уже хочется поиграть в это! Люди любят риск и новый опыт, который хотят, но не могут пережить в реальной жизни. Например GTA — это симулятор крутого парня, которым все хотят быть, но не могут.
  • Популярная. Это не артхаус, не что-то странное или специфичное. Идея обращается к понятным образам из жизни или массовой культуры.
  • Выделяющаяся. Такого раньше не было. Или было, но давно. Или в другом жанре. Или в другом стиле. Или плохо сделано.

Что поможет тебе в выборе идеи?

  • Каталог игр на твоей платформе. Смотри что популярно. Думай как это изменить, подать под другим углом. Хмм…игра про постройку железной дороги в топе. А что если, мы играем за машиниста?
  • Сайты-сервисы с аналитикой тэгов и жанров на платформе. Можно отследить популярность жанра, количество игр в нем. Можно скрестить отдельные тэги между собой.
  • Массовая культура. Фильмы, книги, комиксы, короткометражки, гифки, картинки из интернета.

Скорее всего у тебя будет рождаться много идей. Записывай их. Дай полежать. А потом выбери ту, что не даёт тебе покоя и кажется лучшей.

Когда родил идею

Про питч

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

На основе Питча, описываем концепт игры. Более развернутое описание игры на одну страничку. За кого мы играем? В чем цель? Что можно делать? Какие эмоции вызываем?

Про USP

Продумай ключевые фичи — USP, которые будут продавать твой проект. Они вытекают из твоей идеи.

Например, идея Панка — издевательство над массовой культурой и модой.

Ключевые фичи (USP) Панка: вызывающее поведение, агрессивная музыка и странные прически.

Зацени мои USP, чувак!

Показывай свои USP везде — в трейлере, скриншотах, постере, описании игры. Говори про них общении с прессой и издателями.Тычь ими в лицо!

Например, у They Are Here — это пришельцы, кукурузные поля как фильме Знаки, и НЛО.

Кароче — почитай про идею, концепцию, питч, USP игры. Сформулируй чёткое видение твоего проекта и доноси это видение до всех. Без него — всё развалится и поплывет.

Шаг 10. Составь список ассетов и задач

Ассеты — это кирпичики, из которых состоят игры.

Составь список того, что нужно сделать. Хотя-бы крупными мазками. Сделать уровнь, найти музыку, вставить персонажа. А еще надо 20 видов мечей.

Оцени время, а потом умножь его на 2. Даже если тебе кажется это глупым. Умножь его в 2 раза!

Если видишь, что проект большой — отрезай всё ненужное. Ненужное — всё, что не показывает идею. Или редко появляется на экране.

Например, если идея игры — ультра-насилие, то можно не делать 20 видов мечей, а лучше проработать физику расчленения тела.

Прикинь, что для мобильных гипер-казуалок нужно сделать минимум 30 минут геймплея. А для ПК и Консолей, лучше сделать игру на 2 часа. Если можешь больше — круто!

Настоятельно рекомендую!

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

Шаг 11. Организуй процесс

Записывай, всё что надо сделать. Каждую мелочь. Иначе — забудешь.

Ставь задачи. Себе и команде. Рекомендую Trello (проще) или Asana (функциональнее).

Cобирай инфу по проекту в одном месте. Можно юзать доски типа “Miro” или вики типа Notion.

Если ты один, или у вас небольшая команда, не парься над большой и красивой документацией. Лучше покажи пример, начерти схему, объясни на пальцах ЧЁ НАДО сделать.

Референс — лучшее описание задачи для художника! Например, я сказал жене — хочу обложку как у Слендера, но с пришельцем. Этого — достаточно!

Собирай и храни нужную инфу. Ссылки на классные статьи. Контакты возможных партнёров. Скриншоты багов. И т.п.

Шаг 12. Сделай демку

Демо-версия / Вертикальный срез / MVP — очень близкие по смыслу понятия. Это маленький кусочек игры финального качества.

Маленькая, но качественная демка

Демо-версия решает множество задач:

  • Поможет записать видео, скриншоты, гифки
  • Покажет окупаемость мобильной игры
  • Поможет устроиться на работу
  • Ускорит набор вишлсистов в Steam
  • Получит отзывы от игроков и стримеров
  • Можно участвовать в фестивалях и конкурсах
  • Только с ней можно найти издателя.

Короче — сделай демонстрационную версию игры. Это твоя визитная карточка. Показывай её всем. Говори — я сделаю так-же, только больше.

Шаг 13. Фигачь! Прорывайся к релизу!

Не буду вдаваться в подробности о релизе. Всё зависит от игры и платформы.

Лучше дам рекомендации как дожить до релиза:

  • Не меняй идею на ходу. Сильно. По чуть-чуть можно.
  • Не начинай другие проекты. Не распыляйся. Делай, что запланировал.
  • Составь график работы. Работай над игрой постоянно. Хотя бы по 3 дня в неделю, по 2 часа в день. Больше — быстрее!
  • Надоела разработка? Поиграй в похожие игры. Посмотри похожие фильмы. Найди, что было бы круто сделать.
  • Всё равно надоела? Мечтай о релизе. Представь как это будет здорово и вечно!
  • Показывай свою работу — пиши посты, пости гифки, давай поиграть стримерам. Твоя цель — получить позитивную обратную связь. Ну или отрицательную.
  • Узнавай что-то новое про производство игр. Слушай подкасты, смотри доклады. Это мотивирует, помогает в производстве.
Будь как этот парень

Спасибо, что дочитал!

Эта статья — вводная. Тебе много предстоит узнать и загуглить на каждом шаге.

Короче — ты можешь сделать это! Реально!

Главное — желание!

Что вы делаете, когда вы играете в какую-то игру и несколько раз не можете пройти одно и то же место? Можно просто найти уже готовое прохождение. Это, конечно, здорово, но что, если вы застряли в разработке игры? Какой гайд прочитать? Так пусть наша статья станет вашим пошаговым руководством к разработке вашей первой игры, если вы все еще не начали ее писать. Если уже начали, то вам все равно не помешает прочитать наши советы — быть может, увидите что-нибудь новое.

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

01

Это была самая первая игра, причем запрограммированная для калькулятора TI-83 Plus. Позднее она была переписана автором на Java во время обучения в старших классах. Примечательно, что игра так и не была закончена.

Ко всеобщему сожалению, не доводить игры до логического конца — одна из самых распространенных проблем начинающих разработчиков. Соответственно, возникает вопрос: как повысить свою продуктивность и все-таки закончить начатый проект? Ответ прост: прочтите наше «прохождение» разработки игры.

Основные этапы

Если вы разрабатываете игру сами (а начинающие программисты обычно пишут как раз в одиночку), то процесс написания можно разделить на 4 основных этапа (или уровня, как и в играх):

  • планирование;
  • прототипирование;
  • программирование;
  • релиз.

Каждый следующий уровень в видеоигре сложнее, чем предыдущий. Здесь все также: каждый следующий этап имеет свои трудности и проблемы, с которыми вы неизбежно встретитесь. Это пошаговое руководство поможет вам не остановиться ни на одном этапе разработки игры. Мы приведем различные цитаты и мнения профессионалов, целиком прошедшие тот путь, который мы только начинаем.

В играх каждый уровень имеет свои проблемные места, а в конце — еще и босса. Так будет и у нас. Мы остановимся на них более подробно и, как и в любом прохождении, мы покажем, как пройти эти места и двинуться дальше.

Уровень 1: Планирование

Помните, сделав 90% игры, вы думаете, что потратили 90% своего времени. А доделывая оставшиеся 10%, вы тратите еще столько же «оставшегося» 90% времени. Составляйте план, учитывая это. — Ян Шрейбер

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

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

02

Как уже говорилось выше — уделяйте внимание деталям. Записали новую фичу для реализации? Отметьте рядом, как она будет работать, как будет влиять на игрока и непосредственно на игровой процесс. И помните, секрет успешной разработки — решать существующие проблемы, пока они не накопились.

Разработка игры есть компромисс. Качественная игра должна уметь делать не все подряд, а только ограниченный набор хорошо работающих функций. — Патрик Вайет

Именно поэтому важно спланировать все, иначе на этапе разработки (уровень 3) вы захотите добавить в игру больше возможностей и начнете реализовывать все подряд, что категорически неправильно. Ваш проект рискует быть чрезмерно большим, отчего вам сложнее будет его контролировать, а вскоре вы вовсе бросите его в дальний ящик в надежде, что возьметесь за него позже. Если вы играли в серию игр Halo, представьте себе, как было бы трудно играть в нее, если бы вы столкнулись с парочкой охотников сразу после начала игры. Вы попросту будете умирать снова и снова, пока вам не надоест эта череда смертей. В разработке игры все аналогично.

Основная проблема первого этапа — притупить свое желание кодить и начать планировать. Написать код вы всегда сможете, для этого у вас будет целый этап. Спланируйте как можно больше аспектов вашей игры.

А боссом этого уровня являются вопросы. Просмотрите на все свои заметки и убедитесь в том, что у вас нет каких-либо непонятных пунктов: ни в используемых инструментах, ни в алгоритмах и прочем. Если же у вас действительно все вопросы решены, то вы смело можете считать, что уровень «Планирование» закончен. Но если остались непонятные аспекты — решите их, прежде чем переходить дальше.

Разумеется, у вас могут возникнуть такие вопросы, которые касаются, например, баланса игры. В таких случаях вы также готовы переходить дальше, поскольку эту проблему необходимо будет решить на втором и третьем этапах разработки игры.

Уровень 2: Прототипирование

Дизайн это процесс, а не результат. — Кристофер Симмонс

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

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

Если вы получаете удовольствие от какой-либо игры, то вы захотите поиграть в нее снова, независимо от того, сколько очков или денег вы там набрали. — Стэн Яроцки

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

Вы помните секретные телепорты в игре Super Mario Bros? Игрок мог найти хорошо спрятанные трубы, прыгнув в которые можно было пропустить несколько уровней. Так и здесь. Правда, мы не полностью пропускаем прототипирование, а совмещаем его с планированием.

03

Хотим заметить, что первые два этапа взаимозаменяемы. Быть может, вы хотите проверить основную механику вашей игры, прежде чем потратите кучу времени на детали? А может, вы хотите попробовать какую-то возможность в вашей игре? Это основные причины, почему есть смысл в том, чтобы поменять порядок первых двух этапов.

Хорошая игра — это поток интересных задач, решаемых игроком. — Брюс Шелли

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

А боссом этого уровня является полнота. Вы должны собрать воедино все наработки первого и второго этапа и понять, что же у вас должно получиться в итоге. Если вы будете иметь хорошее представление о вашем конечном проекте, то проблем при написании кода у вас точно не возникнет. А следовательно, повысятся шансы закончить игру.

Уровень 3: Программирование

Третий уровень — наиболее сложный уровень для начинающих программистов. Дойдя до него, многие забрасывают свой проект. Но бояться здесь ничего не надо! Первые два этапа пройдены и вы уже на полпути к окончанию разработки.

Чтобы начать этот этап, вам стоит определиться с целевой платформой вашей игры. Будет эта игра для консолей, а, может быть, мобильная или вовсе браузерная? Определившись с платформой, выберите необходимый инструментарий и язык программирования.

На самом деле эти два шага можно выполнить в обратном порядке. Имея какую-либо среду разработки (или язык программирования), вы можете проанализировать ее возможности и решить, что вы сможете написать.

Вы очень сильно облегчите себе жизнь, если воспользуетесь бесплатными библиотеками и ресурсами. Не пытайтесь изобретать велосипед: используйте то, что находится в свободном доступе. Это поможет вам приберечь немного сил для того, чтобы закончить проект.

«Я не умею рисовать» — используй клипарт. «Я не умею создавать звуки» — ищи MIDI файлы. «Я не умею программировать» — никого это не волнует, не программируй! — Роб

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

Но вы не должны унывать! Лучшее решение этих проблем — отвлечься от проекта на несколько дней. Вы очистите ваш ум и позволите новым идеям посетить его. Также неоднократно замечено, что «утро вечера мудренее». Застряли? Не знаете как решить проблему? Ложитесь спать, а на завтрашнее утро вы, возможно, сразу поймете причину ваших неудач. Не работайте до изнеможения и не изнуряйте себя: работа над проектом должна быть в удовольствие.

Если вы пытаетесь и не можете решить действительно сложную проблему — остановитесь. Решите более простую проблему, которая выполняет те же действия, что и сложная. — Даниель Кук

Ну а боссом этого уровня является сама игра. Да, игра, которую вы и пишете. Она не должна быть идеальной, но она должна быть полноценной. Такой, в которую бы люди могли и хотели играть.

Уровень 4: Релиз

Никогда не сдавайся. — Элис Тейлор

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

Главная проблема этого этапа — критика. Всегда найдутся те, кому попросту не понравится ваша игра. Это нормально. Не стоить из-за таких людей опускать руки. Ориентируйтесь лучше на тех, кто играет в ваше приложение и предлагает вам добавить в нее новые возможности.

Начиная создавать игру, не смотрите на результаты других. Создайте то, что хотите вы. — Роб

А финальным боссом всего нашего путешествия будет являться ваша гордость. Вы сделали полноценную игру от начала и до конца! На самом деле, не все могут похвастаться этим.

Каждый разработчик когда-нибудь напишет «плохую» игру. Если вы еще не написали — напишете. Все мы напишем. — Бренда Ромеро

И помните, дорога к успеху вымощена многократными неудачами. Никогда не сдавайтесь!

Вывод

Разработка первой игры — захватывающее занятие, выполняя которое мы получаем бесценный опыт. И все же, многие разработчики не могут довести свой проект до конца, хотя так категорически нельзя поступать. Следуя нашим четырем «уровням» разработки игры, вы увеличите свои шансы довести ваш проект до логического завершения.

А теперь соберитесь и напишите свою игру!

Перевод статьи «Making Your First Game: A Walkthrough for Game Developers»

Голубев Никита, коммерческий автор и переводчик, специально для блога Нетологии перевёл статью разработчика игр Анжелы Хе о том, как без навыков программирования создать свою первую игру.

Всего 2 года назад я была 17-летней школьницей и ничего не знала о программировании. Это не помешало мне начать учиться и через несколько месяцев выпустить свою первую игру в Steam. Сегодня у меня более 10 игр для ПК, интернета и мобильных устройств и свыше 1,9 млн игроков.

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

Всему, что я знаю, я научилась сама, а теперь научу вас.

Чтобы сделать игру, нужно пройти 6 этапов:

  • Концепция
  • Графика
  • Программирование
  • Звук
  • Подготовка к публикации
  • Публикация

В статье для каждого этапа я выделю:
— Советы, которые я вынесла из своего и чужого опыта.
— Инструменты, которые я считаю наиболее полезными.

image

Концепция

Совет

У вас есть классная идея. Но как оформить её на бумаге?

У каждого свой путь. Одни составляют дизайн-документы по 60 страниц, другие напишут лист неразборчивых заметок. Не знаю, как удобнее для вас, но обязательно зафиксируйте следующее:

  • Фишки. Что делает вашу идею крутой? Это самый главный вопрос. Как только вы сможете уловить и зафиксировать это, остальные этапы покажутся легче. Ваша игра поднимает острые темы? Станет новой классикой? Или будет отличаться от всего, что было раньше?
  • Механика. Что делает игрок и зачем? Это ваш игровой процесс. Он может быть простым, как поочерёдное нажатие клавиш Q, W, O, P в игре QWOP, или сложным, как комбинации в Dwarf Fortress.
  • Легенда. Благодаря чему игроки запомнят вашу игру? С какими эмоциями они будут её покидать? У каждой игры есть история. Если стория неочевидна, игрок сам создаст её. История бывает разная: возрастание чисел в игре 2048, восхождение империй в Civilization или безмолвные взаимодействия в Monument Valley. Подумайте, какая легенда будет стоять за вашей игрой.
  • Настроение. Какое впечатление производит игра? Какие визуальные эффекты и музыка будут этому способствовать? Важно первое впечатление, которое сможет зацепить игрока и затем заставить его снова возвращаться к игре. Возможно, вам захочется ретро-эффекта с пиксельной графикой и 8-битной музыкой или современного вида с плоской геометрией — подумайте об этом.
  • Участвуйте в хакатонах. Вам и другим участникам нужно будет сделать игру за отведённое время. Как минимум вы вдохновитесь и встретите единомышленников. Попробуйте Ludum Dare, один из самых больших геймджемов.
  • Создайте список идей. Записывайте каждую новую мысль. В моменты ступора всегда можно заглянуть в список и найти что-то интересное. Так выглядит мой личный Google Doc идей и заметок.

Когда приходит вдохновение, бросайте всё и пишите. В следующий раз, когда мысль уйдёт, не понадобится высасывать идеи из пальца.

Инструменты

Ведение заметок:

  • Заметки на Mac OS.
  • Google Документы.
  • Трелло.

Командная работа:

  • Google Диск.
  • GitHub. Требуется git и Unity .gitignore.
  • Unity Collab. Самый простой инструмент, но с ограничениями в бесплатной версии.

Я делаю игры на Unity. Дальше речь пойдёт о нём, но не бойтесь использовать другой движок.

Вдохновение:

  • Книга Джесси Шелл «Искусство геймдизайна».
  • Сайт для разработчиков игр Gamasutra.

Графика

Совет

Если вы не умеете программировать, сначала прочтите раздел «Программирование». Вряд ли вы хотите потратить время на графику и выкинуть её потому, что под неё не написать код.

Даже если вы не умеете рисовать, игру можно сделать красивой, используя три визуальных принципа: цвет, форма и объём.

Thomas Was Alone — простая и прекрасная игра

Интерфейс

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


Неудачный и удачный шрифт

2D-анимация

Анимацию можно реализовать двумя способами:

  • Покадровая анимация. Когда вы отрисовываете каждый кадр. Для этого используйте таблицы спрайтов и Sprite Packer в Unity.
  • Скелетная анимация. Отрисовывается каждая подвижная конечность, затем анимируется её позиция и повороты. Это быстрее, легче и тратит меньше оперативной памяти. Для 2D-анимации на Unity используйте пивоты (точки привязки) или плагин Anima 2D.

Что ещё может пригодиться

Советы, которые применимы не только к игровой графике, но и к другим программам:

  • Объекты-тайлы используются для создания плитки и требуют меньше места на жёстком диске.

Без тайлов и с тайлом

  • 9-slice объекты с немасштабируемыми границами и масштабируемым центром позволяют увеличивать изображения без заполнения памяти.

Пятно расширяется, но углы остаются прежними

  • Делайте разрешение каждого объекта таким, чтобы оно делилось на 4 или было степенью числа 2.
  • В Photoshop вы можете сохранить каждый слой в отдельный файл через Файл > Экспорт > Быстрый экспорт в [формат изображения].

Инструменты

Создание интерфейса:

  • Photoshop.
  • Sketch.

Принципы создания интерфейса:

  • Google Material Design.
  • Apple’s UI Do’s and Don’ts.

Создание 2D объектов:

  • Photoshop.
  • Gimp.
  • Paint Tool SAI — для графики в стиле аниме.

Создание 3D объектов:

  • Blender — мощное ПО со сложным обучением.
  • Maya — для анимации.
  • Max — для отрисовки.

Бесплатные игровые ассеты:

  • Behance — шрифты, иконки и прочее.
  • KennyNL — высококачественные объекты, готовые к использованию в играх.
  • Open Game Dev Art — огромная библиотека графики, созданной другими пользователями.

Вдохновление:

  • Dribbble — закрытое сообщество дизайнеров.
  • Behance — сообщество дизайнеров, к которому может присоединиться любой желающий.
  • itch.io — сообщество создателей инди-игр.

Программирование

Совет

Выберите игровой движок, среду разработки и начинайте погружаться в код.

Представленных ниже знаний достаточно для начала. Все примеры написаны на C++, одном из языков программирования в Unity3D. (Примечание переводчика: на самом деле в Unity используется C#, который похож на C++).

  1. Типы данных и переменные. В основе кода лежат данные, которые хранятся в переменных. Можно объявить переменную так:
    int i = 0;

    int — тип данных, i — имя переменной, = 0 — значение переменной.

    Часто используемые типы данных:
    int и long — для целых чисел,
    float и double — для чисел с плавающей точкой,
    string — строчные данные.

  2. Условия. С помощью оператора if можно создать условия для выполнения кода:
    if (true){ // истина всегда истинна!
        doThings(); // я внутри выражения, и я выполняюсь!
    }

    Используя оператор else, можно расширить условие и отобразить что делать, если условие не соответствует истине:

    int i = 1;
    if (i == 0){ 
       doThings(); 
    }
    else if (i == 1){
       doOtherThings(); // теперь запускаюсь я!
    }

  3. Циклы for/while. While-циклы повторяют части кода, пока условие остаётся истинным. Как только условие перестаёт быть истинным, цикл обрывается.
    while (someBool == true){ // условие
       doThings(); // Буду выполняться, пока условие истинно
    }

    For-циклы похожи на while-циклы. Для while мы пишем так:

    int i = 0;
    while (i < condition){ 
        doThings();
        i++; // счётчик, по которому цикл продолжается
    }

    Равнозначный for-цикл будет таким:

    for (int i = 0; i < condition; i++){
        doThings();
    }
    

  4. Структуры данных. У нас есть данные, с которыми можно взаимодействовать. К тому же их можно хранить в особой структуре — массиве, списке, очереди, стеке или наборе.
    Простой примера массива:

    /*
    Допустим, у нас есть числа от 0 до 9. Будем хранить их в массиве!
    */
    int[] arr = new int[10]; 
    /*
    Скобки [] нужны для объявления массива. Мы присваиваем массив из 10 элементов переменной arr. Теперь он выглядит так:
    arr = [ 0 0 0 0 0 0 0 0 0 0 ]
    */
    for (int i=0; i<10; i++){
        arr[i]=i; // Мы присваиваем позиции i значение i.
    //Заметили, что счёт начинается с нуля?  
    }
    /*
    После цикла наш массив будет выглядеть так:
    arr = [ 0 1 2 3 4 5 6 7 8 9 ]
    */
    

  5. Функции и исключения. Функция — это короткая строчка кода, заменяющая огромное количество строчек кода. Например, выведем функцию EatBread(), которая содержит следующее:
    void EatBread(){ //<---это функция 
       breadAte=true;
       printf("Я ОЩУЩАЮ УГЛЕВОДЫ, ОНИ БЕГУТ ВНУТРИ МЕНЯ");
    }

Тогда при выводе функции выполняются два выражения внутри неё.

Если в коде что-то идёт не так, на помощь приходят исключения. Они как бы говорят: «Так, погоди, здесь ты сделал что-то нелогичное. Перепроверь ещё раз».

О чём ещё надо знать:

  1. Язык. На каком языке вы будете программировать? Чаще всего игры пишут на C++, JavaScript или C#. Языки отличаются синтаксисом и областью применения.
  2. API (Application Programming Interface). Как только вы ознакомились с базой, приступайте к изучению программного интерфейса приложения для конкретного игрового движка. Они представляют собой набор полезных инструментов, упакованных в простые классы и функции. API сильно упрощает жизнь программиста.
  3. Посмотрите примеры проектов на выбранном игровом движке. Можно найти много бесплатных примеров игр на движках Unreal и Unity. Это позволит увидеть итог и весь процесс работы целиком, а также почерпнуть идеи для своей будущей игры.

Немного вдохновения. Знаю, программирование поначалу пугает. Всё кажется бессмысленным, вы постоянно спотыкаетесь и перед лицом постоянных ошибок хотите сдаться, но это не значит, что программирование не для вас.

Код — это вызов самому себе. И ничего не понимать поначалу — нормально.

Как и любому навыку, программированию нужно обучаться. И, возможно, это окажется довольно интересно.

Другие немаловажные основы программирования:

  • Объектно-ориентированное программирование. Делает код более естественным.
  • Соглашение об именовании. Называйте классы, методы и переменные так, чтобы вам и другим программистам была понятна их цель. Например, назовите функцию атаки ближнего боя,
    meleeAttack ()

    а не

    mA()

    или

    protecbutalsoattac()

  • Декомпозиция. Сделайте из повторяющегося кода функцию и вызывайте её вместо копирования повторяющихся строк.
  • Шаблон проектирования Singleton («Одиночка»). Шаблон программирования, который позволяет данным храниться в одном месте.
  • Избегание статических переменных. Помимо использования синглтонов, я избегала статических переменных — они живут только на время игры, медленные и могут вести себя непредсказуемо.
  • Шаблон проектирования Observer («Наблюдатель»). Позволяет объекту узнавать о состоянии других объектов, не теряя компьютерного времени на проверку.

Вещи, свойственные Unity:

  • Сопрограммы. Позволяют начать выполнять действие, продолжать в течение нужного времени и затем прекратить. Я использую их для визуальных эффектов взрывов, резких движений.
  • Класс ScriptableObject. Он хранит данные с меньшими затратами, чем базовый класс MonoBehaviour.

Инструменты

Игровые движки:

  • Свой движок на C/C++. Низкий порог входа. (Примечание переводчика: на самом деле, создание своего движка требует больших усилий и глубокого знания принципов программирования).
  • Unity. Поддерживает 2D/3D. Требует знаний JavaScript/C#. Средний порог входа. Разработка для нескольких платформ.
  • Unreal. Поддерживает 2D/3D. Требует знаний C++. Средний порог входа. Разработка для нескольких платформ.
  • pixi.js. Только 2D. Требует знаний JavaScript. Средний порог входа. Разработка для браузера.
  • GameMaker Studio. Поддерживает 2D/3D. Требует знаний специального языка движка GML (Game Maker Language). Для новичков. Разработка для нескольких платформ.
  • Corona. Только 2D. Требует знаний Lua (похож на JavaScript). Для новичков. Разработка для нескольких платформ.

Среды разработки:

  • Visual Studio Code (для MacOS) — не зависает, имеет встроенную справочную информацию и удобные «горячие» клавиши.
  • Visual Studio (для Windows).
  • MonoDevelop — устанавливается с Unity, иногда подвисает.

Бесплатные ассеты Unity:

В Unity Asset Store, bitbucket и GitHub очень много бесплатных ассетов. В своих проектах я использую минимум по два. Они упрощают жизнь, но далеко не идеальны. Заметили ошибку — исправляйте и говорите разработчику о ней.

  • TextMeshPro.
  • LeanTween.
  • Fungus.
  • Corgi Engine.
  • Dialogue System.
  • Post Processing Stack.
  • Keijiro Takahashi — работает над Unity, доступные проекты визуальных эффектов с открытым исходным кодом.

Немаловажный, даже главный источник решения проблем с кодом — Гугл!

Звук

Совет

Аудио способно создавать настроение и погружать в игру, но для него нужна память.

Для начала решите: вы хотите звук? Если да, будет ли в игре музыка, звуковые эффекты, озвучка или повествование.

В любом случае потребуется запись и сведение таким образом, чтобы звук подходил под настроение игры. Например, Bastion использует органические и инструментальные звуки, хорошо вписывающиеся в мир игры. Crypt of the Necrodancer включил в себя смесь электронных ритмов и восьмибитного рока, чтобы передать темп и яркость игры.

Погружение решает. Если звуки не совпадают с настроением игры, игроку будет сложно погрузиться в ваш мир.

Инструменты

Приложения для работы с аудио:

  • Logic Pro (только для MacOS). Цена 200 $.
  • FL Studio. Цена 99–899 $. Есть бесплатная демоверсия.
  • Reaper. Цена 60–225 $.
  • Audacity. Бесплатная программа. Имеет мало возможностей, но полезен для чистки аудио.

Создание ретро-эффектов:

  • Chiptone.
  • Bfxr.
  • Leshy SFMaker.
  • as3sfxr.

Бесплатные звуки:

  • Soundcloud. Здесь можно найти бесконечно много звуков и музыки под лицензией Creative Commons. Начните с этого плейлиста. Использовать можно бесплатно, но не забудьте указать авторство.
  • Incompetech.
  • Bensound.

Подготовка к публикации

Совет

Существует небольшая вероятность — на 99,99 процентов, что в игре есть ошибки. А это значит, что самое время заняться баг-тестом.

Как тестировать игру на баги?

  1. Дайте другим поиграть в игру. Желательно вместе с вами, на случай, если они столкнутся с ошибкой и не смогут понять или объяснить её.
  2. Проверьте игру на разных платформах. В редакторе может не быть проблем, но работает ли она там, где её будут запускать? Будьте особенно внимательны с Linux и Android.

Итак, баг найден. Что теперь?

  1. Проверьте консоль на исключения. Если нашли исключение, найдите файл и строку, где сработало исключение. Если оно звучит по-марсиански, поищите решение в сети, и подумайте, почему именно в этой строке срабатывает исключение.
  2. Напишите в консоль. Попробуйте вывести логи (системные файлы) в предполагаемых местах ошибки. Введите разные переменные и сверьте полученные значения с ожидаемыми. При несовпадении — исправляйте.
  3. Проверьте логи. Системные записи вашего проекта дадут больше информации, чем консоль. Прочтите строки, где сработало исключение. Гуглите всё, что не знаете.
  4. Поспите. Всё починится с утра. Это просто плохой сон :)

Типичные ошибки

  • NullReferenceException.
    var.doThing(); //throws NullReferenceException: Object reference not set to an instance of an object

    В чём дело: функция выполняется с несуществующей (null) переменной.
    Быстрое решение: проверьте, является ли переменная null.

    if(var != null)
        {
            var.doThing(); // выполняем функцию безопасно!
        }
    

  • SyntaxErrorException.
    В чём дело: ошибки в синтаксисе.
    Быстрое решение: в сообщении указано, какой символ выдал ошибку. Найдите и исправьте его.

    Примечание: Проверьте, какие кавычки вы используете.
    » //правильные кавычки;
    » //ненужные кавычки, они принесут вам немало ошибок.

  • Розовый или чёрный экран.
    Возможная проблема: не обработался шейдер.
    Возможные причины: вы используете 3D-шейдеры в 2D-игре или шейдеры, которые не поддерживаются операционной системой. Убедитесь, что вы используете мобильные шейдеры для мобильных игр.

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

Советы по оптимизации

  • Установите нужную частоту кадров. Для визуальной новеллы хватит 20 кадров в секунду, а вот для шутера нужны 60. Низкая частота кадров тратит меньше времени на отрисовку.
  • Анимация / система частиц / выборочная обработка. Объекты, невидимые для камеры игрока, не обрабатываются. Персонажи анимируются, частицы обновляются, 3D-модели обрабатываются только в поле зрения игрока.
  • Сжатие текстур и звуков. Для сжатия текстур используйте Crunch. Потоковая музыка и распаковка звуковых эффектов перегружают игру. Попробуйте снизить качество аудио. Сжатие может заметно снизить качество объектов.
  • Не позволяйте Raycast касаться лишних объектов. Raycast похожи на маленькие лучи, выстреливающие из ваших пальцев или мыши, когда вы касаетесь экрана или кликаете. Найдите объекты, которые не должны реагировать на действия игрока и удалите их из вычислений Raycast.
  • Используйте объектный пул. Частое создание и удаление большого количества объектов снижает производительность. Вместо этого, объедините их в список, очередь или другую структуру. Например, пули должны объединяться в один массив.
  • Оптимизируйте шейдеры. Задайте материал для каждого визуализатора. Игре не придётся создавать новые материалы в начале игры, что сэкономит ресурсы. Пусть визуализатор включает только то, что функционально необходимо.
  • Используйте AssetBundles (дословно «комплекты активов») вместо старой системы Resources в Unity. AssetBundles экспортирует ваши файлы из Unity и помещает в один файл, экономя оперативную память.

Инструменты (только для Unity)

Скрипты:

  • Optimizing scripts in Unity games.

Графика:

  • A guide to optimizing Unity UI;
  • Art Asset best practice guide.

Память:

  • Reducing the file size of your build.
  • Memory.

Оптимизация под платформы:

  • Practical guide to optimization for mobiles;
  • WebGL performance considerations;
  • Memory Considerations when targeting WebGL;
  • Olly’s seven stages of optimizations for mobile VR.

Публикация

Совет

Самое время показать всему миру своё творение.

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

Вы не узнаете, станет ли игра хитом, пока не опубликуете её.

  1. Описание

    Сделайте скриншоты страниц «Об игре» и создайте описания для каждой платформы, на которых планируете выпустить игру.

  2. Нетворкинг

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

    Отправьте описание игры в прессу за неделю до выхода — дайте людям время написать о ней. Может случиться, что о ней не станут писать, но помните: журналисты любят красивые истории о разработчиках, уникальную или противоречивую идею и медиа-кит.

    Где взять адреса?

    • Найдите в сети контакты авторов, которые вам нравятся: почта, страница в LinkedIn, Твиттер.
    • Найдите почту издания в разделе «О нас» или внизу страницы.

    Не пишите в игровые издания, которые не освещают ваш жанр или целевую игровую платформу.

  3. Стримеры и видеоблогеры

    Они снимут по игре видео, если:

    • Игра станет популярна на платформах.
    • Вы напишете напрямую. Не говорите о себе, кратко, красиво и убедительно расскажите про игру. Используйте гифки и скриншоты для привлечения внимания.

    Обычно адреса блогеров указаны на странице. Если нет, попробуйте найти контакты в интернете.

    Письмо видеоблогеру Markiplier, чей канал насчитывает более 21 миллиона подписчиков

    Видео по игре от Markiplier

  4. Социальные сети

    Это прекрасный инструмент для продвижения: Agar.io обрела популярность на 4chan, Butterfly Soup подскочила в загрузках после внимания в Твиттере.

    Как лучше: публиковаться через издателя или самому. Хотите пойти по пути Hotline Miami, выпущенной Devolver Digital, или перенять опыт Farmville и Doki Doki Literature Club?

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

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

    Количество установок игры растёт

    Я предпочитаю публиковать игры самостоятельно. Мне нравится учиться, и я верю, что по-настоящему хорошая игра будет успешна вне зависимости от продвижения.

  5. Жмите на кнопку «Опубликовать»!

    Получилось! Теперь расслабьтесь, возьмите что-нибудь вкусное и отдохните. Вы работали не покладая рук и заслужили это.

    Не бойтесь, если игра не получила ожидаемого внимания — это нормально. У моей первой игры всего 255 загрузок в Steam.

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

Инструменты

Сервис presskit() помогает разработчикам оформить описание игры для прессы.

Платформы для публикации:

  • Steam (PC) — 100 $ за публикацию.
  • Origin (PC).
  • GOG (PC) — бесплатная публикация после разрешения.
  • Mac App Store (MacOS) — 100 $ в год, требуется учётная запись разработчика Apple.
  • itch.io (PC / Web) — бесплатная публикация.
  • Game Jolt (PC/Web) — бесплатная публикация.
  • Armor Games — бесплатная публикация.
  • Kongregate (Web) — бесплатная публикация.
  • Newgrounds (Web) — бесплатная публикация.
  • GitHub (Web) — бесплатная публикация на сайте, заканчивающемся на «___.github.io».
  • Amazon (Web/Mobile) — бесплатная публикация.
  • Google Play (Mobile) — 25 $ за публикацию.
  • iOS App Store (Mobile) — требуется учётная запись разработчика Apple.

Журналы об играх:

  • DTF (на русском).
  • Канобу (на русском).
  • IndieGames.
  • Siliconera.
  • FreeGamesPlanet.
  • PCGamer.
  • Kotaku.
  • Rock Paper Shotgun.
  • Polygon.
  • Giant Bomb.
  • EuroGamer.

Фестивали:

  • Independent Games Festival (IGF). Приём заявок до 1 октября.
  • Indiecade. Международный фестиваль инди-игр. Приём заявок до мая–июня.
  • Swedish Game Awards. Игровая премия Швеции. Приём заявок до июня.
  • South by Southwest Festival (SXSW). Приём заявок до декабря.
  • The Game Awards. Приём заявок до ноября.

Игровые конференции:

  • DevGAMM — проводится в Москве.
  • Game Developer’s Conference (GDC).
  • Penny Arcade Expo (PAX).
  • Electronic Entertainment Expo (E3).
  • Tokyo Game Show.

Заключение

Нет простого пути создания игры. Есть только ваши решительность и усилия.

За каждым Half-Life, Minecraft и Uncharted лежат океаны крови, пота и слез.
Кен Левин, создатель Bioshock

Вы будете допускать ошибки, чувствовать себя в тупике и плакать. Это нормально — значит, вы растёте над собой.

От редакции

  • Онлайн-курс «Геймдизайн с нуля: станьте профессионалом игровой индустрии»
  • Онлайн-курс «Создание продукта: аналитика, разработка, продвижение»
  • Онлайн-профессия «Python-разработчик»
  • Онлайн-профессия «Ruby on Rails разработчик»
  • Онлайн-курс «PR в digital: стратегия, репутация, инструменты»
  • Онлайн-курс «Дизайн мобильных приложений: интерфейсы, архитектура, визуальная концепция»

#статьи

  • 15 июл 2022

  • 0

Учимся программировать через разработку игр. Сегодня напишем знакомую всем «Змейку» — вспомним правила игры и реализуем их на Python.

Иллюстрация: Оля Ежак для Skillbox Media

Антон Яценко

Изучает Python, его библиотеки и занимается анализом данных. Любит путешествовать в горах.

Pygame — популярная библиотека для создания игр под различные устройства на Windows, macOS, Linux или Android. Она помогает разработчику не только описать геймплей, но и работать с клавиатурой, мышью, акселерометром, звуком и видео.

Первая версия Pygame была представлена Питом Шиннерсом в октябре 2000 года. За 22 года вокруг библиотеки сложилось большое комьюнити, а о работе с ней написано несколько десятков книг. Последняя стабильная версия на июль 2022 года — 2.1.2.

Давайте разберёмся в том, как устроена Pygame, и напишем свою первую игру — классическую «Змейку» на Python, которую студенты часто берут для курсовой работы по программированию.

Pygame — не самостоятельная библиотека. На самом деле это обёртка для библиотеки SDL, Simple DirectMedia Layer. Именно SDL позволяет задействовать любые внешние устройства — например, мышь или клавиатуру. А Pygame делает работу с ними удобной для Python-разработчика.

Установить Pygame просто. Для этого воспользуемся терминалом или командной строкой и командой pip:

pip install pygame

Если во время установки возникают ошибки, то можно воспользоваться официальной документацией. В ней описаны особенности установки на различные системы, а также пути решения распространённых проблем.

Библиотека Pygame состоит из конструкций на языке Python и включает в себя несколько модулей. Модули позволяют получить доступ к определённому устройству и содержат методы для работы с ним. Например, модуль display позволяет работать с экраном, а joystick — считывать движения с джойстика.

После того как вы импортировали Pygame, необходимо инициировать библиотеку с помощью команды pygame.int(). Это поможет нам использовать любые методы любых функций, включённых в библиотеку модулей. Без инициализации код может потерять кросс-платформенность и не запускаться в другой системе.

Помимо модулей, Pygame включает несколько классов Python, которые работают с концепциями, не зависящими от аппаратного обеспечения. Одна из таких концепций — Surface. Surface, можно сказать, определяет прямоугольную область, на которой можно рисовать. Если переносить на практику, то этот класс позволяет создать игровое поле. Он широко используется при работе с Pygame, и мы тоже поработаем с ним при создании «Змейки».

В Pygame вся информация выводится на игровое поле, которому в коде соответствует класс display. Игровое поле может быть полноэкранным или занимать часть экрана. Display создаётся с помощью функции .set_mode(), которая возвращает Surface, представляющий видимую часть окна. Именно эту область вы будете передавать в функции рисования, такие как pygame.draw.circle(), а содержимое этого Surface будет выводиться на дисплей при вызове pygame.display.flip(). Звучит сложно, но на практике будет проще. Оба класса мы будем использовать при создании «Змейки».

Работать с изображениями в Pygame можно двумя способами: создавать их с нуля на экране или использовать изображения с диска. И тот и другой тип можно перезаписывать, загружать и сохранять в различных форматах — например, в PNG и JPG.

Изображения — не самостоятельные компоненты: они загружаются в объекты Surface, которые можно изменять и выводить на дисплеи различными способами.

Выше мы писали, что объекты Surface представлены прямоугольниками, подобно многим другим объектам в Pygame, в том числе изображениям и окнам. Прямоугольники используются настолько активно, что существует даже специальный класс Rect, предназначенный для работы только с ними. Объекты Rect используются для различных задач: создания фигур игрока и врагов, управления взаимодействиями между ними и так далее.

Перед тем как начать писать код, необходимо подумать о том, какие правила мы должны учитывать при создании игры. Давайте составим для «Змейки» базовые правила, которые влияют на геймплей:

  • цель игры — набрать как можно больше очков за счёт увеличения длины змейки:
  • при поглощении специального объекта на игровом экране длина змейки увеличивается на один блок;
  • игрок начинает движение с левой стороны экрана;
  • игрок может двигаться влево, вправо, вверх или вниз;
  • игрок не может двигаться за пределы экрана, при столкновении с границами игра заканчивается;
  • игра заканчивается, когда змейка врезается сама в себя;
  • ещё игра заканчивается, когда пользователь закрывает окно.

Несмотря на то что «Змейка» — простая игра, нам предстоит написать довольно много кода. Мы разбили этапы создания игры на последовательные шаги, каждый из которых реализует отдельную часть геймплея.


Запускаем Python

Писать код на Python лучше всего в специальном редакторе. Есть несколько вариантов:

  • Воспользоваться специализированными IDE: IntelliJ IDEA или Visual Studio Code. Мы рекомендуем именно этот способ — например, весь код для этой статьи мы писали в Visual Studio Code.
  • Использовать терминал на macOS или Linux или воспользоваться командной строкой в Windows. Для этого предварительно потребуется установить Python в систему. Мы подробно писали об этом в отдельном материале.

После установки и запуска Python загружаем библиотеку Pygame:

pip install pygame

Теперь у нас всё готово к работе над игрой. Для дальнейшего написания кода необходимо создать один пустой Python-файл.


Создаём игровое поле

Чтобы создать окно с игрой с помощью Pygame, необходимо использовать функцию display.set_mode() и передать в неё желаемый размер окна в пикселях. Также необходимо использовать методы init() и quit() для инициализации библиотеки в начале кода и её деинициализации в конце кода.

Метод update() используется для обновления содержимого экрана. Существует ещё метод flip(), который работает аналогично update(). Разница в том, что метод update() обновляет только внесённые изменения, а метод flip() перерисовывает экран целиком. Но если в метод update() не передавать никакие параметры, то также обновится весь экран.

import pygame
 
pygame.init()
dis=pygame.display.set_mode((500,400))  #Задаём размер игрового поля.
 
pygame.display.update()
 
pygame.quit()
quit()

Если сейчас запустить этот код, то экран игры сразу же закроется. Это связано с тем, что код сразу переходит к следующей строчке pygame.quit(), отключающей библиотеку и наше игровое поле. Чтобы избежать этого, необходимо воспользоваться циклом while — он не позволит игровому экрану закрыться:

import pygame
 
pygame.init()
 
dis=pygame.display.set_mode((500,400))
pygame.display.update()
pygame.display.set_caption('Змейка от Skillbox') #Добавляем название игры.
 
game_over=False #Создаём переменную, которая поможет нам контролировать 
статус игры — завершена она или нет. Изначально присваиваем значение False,
 то есть игра продолжается.
 
while not game_over:
   for event in pygame.event.get():
       print(event)  #Выводить в терминал все произошедшие события.
 
pygame.quit()
quit()

Кроме этого, мы добавили в код ещё две сущности: название игры и функцию для отслеживания игровых событий. Чтобы у окна с игрой появилось название, мы используем pygame.display.set_caption(») (название пишем в кавычках). А функция event.get() возвращает в терминал все события, которые происходят с игрой.

Запустим код и посмотрим, что получилось:

Скриншот: Pygame / Skillbox Media

Теперь игровое окно не закрывается само по себе. Однако и закрыть его мы тоже не сможем — если нажать на кнопку «Выход», ничего не произойдёт. Исправляем это с помощью кода: добавляем событие QUIT, закрывающее окно.

import pygame
 
pygame.init()
 
dis=pygame.display.set_mode((500, 400))
pygame.display.update()
pygame.display.set_caption('Змейка от Skillbox')
 
game_over=False
while not game_over:
   for event in pygame.event.get():
       if event.type==pygame.QUIT:
           game_over=True
 
pygame.quit()
quit()

Теперь кнопка выхода работает как надо. Если нажать на неё, то окно с игрой закроется.


Создаём змейку

Для начала инициализируем переменные, которые задают цвет. Мы будем использовать их, чтобы присвоить цвет экрану, самой змейке и еде. В Pygame используется стандартная RGB-схема, то есть любой цвет представляет собой комбинацию красного, зелёного и синего цветов, интенсивность которых мы можем менять.

Наша змейка — прямоугольник, поэтому мы воспользуемся функцией создания прямоугольников draw.rect(). Она позволяет задать размер и цвет прямоугольника.

import pygame
 
pygame.init()
 
dis=pygame.display.set_mode((500, 400))
pygame.display.update()
pygame.display.set_caption('Змейка от Skillbox')
 
game_over=False
while not game_over:
   for event in pygame.event.get():
       if event.type==pygame.QUIT:
           game_over=True
 
pygame.quit()
quit()

Запустим код и посмотрим на результат.

Скриншот: Pygame / Skillbox Media

Всё получилось. Ближе к центру экрана появился синий квадрат, который и будет нашей змейкой.


Описываем движения змейки

Управлять перемещением змейки можно с помощью специального класса Pygame KEYDOWN. Класс позволяет использовать четыре стандартных события, получая их с клавиавтуры: K_UP, K_DOWN, K_LEFT и K_RIGHT — они соответствуют движениям змейки вверх, вниз, влево и вправо. Срабатывание любого события из класса KEYDOWN приводит к изменению положения змейки. Зададим шаг этого движения в 10 пикселей.

Кроме того, мы должны создать две переменные для хранения значений координат первой клетки нашей змейки по осям x и y. Назовём их x1_change и y1_change.

import pygame
 
pygame.init()
 
white = (255, 255, 255)
black = (0, 0, 0)
red = (255, 0, 0)
 
dis = pygame.display.set_mode((800, 600))
pygame.display.set_caption('Змейка от Skillbox')
 
game_over = False
x1 = 300 #Указываем начальное значение положения змейки по оси х.
y1 = 300 #Указываем начальное значение положения змейки по оси y.
x1_change = 0 #Создаём переменную, которой в цикле while будут
присваиваться значения изменения положения змейки по оси х.
y1_change = 0 #создаём переменную, которой в цикле while будут
присваиваться значения изменения положения змейки по оси y.
clock = pygame.time.Clock()
 
while not game_over:
   for event in pygame.event.get():
       if event.type == pygame.QUIT:
           game_over = True
       if event.type == pygame.KEYDOWN: #Добавляем считывание направления
движений с клавиатуры.
           if event.key == pygame.K_LEFT:
               x1_change = -10 #Указываем шаг изменения положения змейки
в 10 пикселей.
               y1_change = 0
           elif event.key == pygame.K_RIGHT:
               x1_change = 10
               y1_change = 0
           elif event.key == pygame.K_UP:
               y1_change = -10
               x1_change = 0
           elif event.key == pygame.K_DOWN:
               y1_change = 10
               x1_change = 0
   x1 += x1_change #Записываем новое значение положения змейки по оси х.
   y1 += y1_change #Записываем новое значение положения змейки по оси y.
   dis.fill(white)
   
   pygame.draw.rect(dis, black, [x1, y1, 10, 10])
   pygame.display.update()
   clock.tick(30)
 
pygame.quit()
quit()

Теперь змейка двигается по игровому полю:

Скриншот: Pygame / Skillbox Media

Учитываем препятствия — границы игрового поля

Если змейка попадает на границу экрана, то игрок терпит поражение, а игра заканчивается. Чтобы закодить это правило, можно воспользоваться оператором if, который определяет координаты x и y для змейки и анализирует, выходят ли они за границы игрового поля. Добавим необходимый код.

import pygame
import time
 
pygame.init()
 
white = (255, 255, 255)
black = (0, 0, 0)
red = (255, 0, 0)
 
dis_width = 800 #Зададим размер игрового поля через две переменные.
dis_height = 600
dis = pygame.display.set_mode((dis_width, dis_width))
pygame.display.set_caption('Змейка от Skillbox')
 
game_over = False
x1 = dis_width/2 #Стартовое положение змейки по осям рассчитывается
через переменные, указывающие размер игрового экрана.
y1 = dis_height/2
snake_block=10 #Укажем в переменной стандартную величину сдвига
положения змейки при нажатии на клавиши.
x1_change = 0
y1_change = 0
 
clock = pygame.time.Clock()
snake_speed=15 #Ограничим скорость движения змейки.
font_style = pygame.font.SysFont(None, 50)
 
def message(msg,color): #Создадим функцию, которая будет показывать
нам сообщения на игровом экране.
   mesg = font_style.render(msg, True, color)
   dis.blit(mesg, [dis_width/2, dis_height/2])
 
while not game_over:
   for event in pygame.event.get():
       if event.type == pygame.QUIT:
           game_over = True
       if event.type == pygame.KEYDOWN:
           if event.key == pygame.K_LEFT:
               x1_change = -snake_block
               y1_change = 0
           elif event.key == pygame.K_RIGHT:
               x1_change = snake_block
               y1_change = 0
           elif event.key == pygame.K_UP:
               y1_change = -snake_block
               x1_change = 0
           elif event.key == pygame.K_DOWN:
               y1_change = snake_block
               x1_change = 0
   
  if x1 >= dis_width or x1 < 0 or y1 >= dis_height or y1 < 0:
       game_over = True #Явно укажем, что если координаты змейки
выходят за рамки игрового поля, то игра должна закончиться.
   x1 += x1_change
   y1 += y1_change
   dis.fill(white)
   
   pygame.draw.rect(dis, black, [x1, y1, snake_block, snake_block])
   pygame.display.update()
   clock.tick(snake_speed)
 
message("Вы проиграли :(",red) #Сообщение, которое появляется при
проигрыше. В нашем случае — при выходе змейки за пределы игрового поля.
 
pygame.display.update()
time.sleep(2)
pygame.quit()
 
quit()

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

Скриншот: Pygame / Skillbox Media

Добавляем еду для змейки

Теперь добавим «еду». Используем библиотеку random, чтобы она появлялась в случайном месте на игровом поле. Когда наша змейка будет проходить через еду, то её длина будет увеличиваться. Это мы добавим на следующем шаге. Кроме того, дадим возможность игроку выйти из игры или начать игру заново после проигрыша.

import pygame
import time
import random
 
pygame.init()
white = (255, 255, 255)
black = (0, 0, 0)
red = (255, 0, 0)
blue = (0, 0, 255)
dis_width = 800
dis_height = 600
dis = pygame.display.set_mode((dis_width, dis_height))
pygame.display.set_caption('Змейка от Skillbox')
clock = pygame.time.Clock()
snake_block = 10
snake_speed = 15
font_style = pygame.font.SysFont(None, 30)
 
def message(msg, color):
   mesg = font_style.render(msg, True, color)
   dis.blit(mesg, [dis_width/10, dis_height/3])
 
def gameLoop(): #Описываем всю игровую логику в одной функции.
   game_over = False
   game_close = False
   x1 = dis_width / 2
   y1 = dis_height / 2
   x1_change = 0
   y1_change = 0
   foodx = round(random.randrange(0, dis_width - snake_block) / 10.0) * 10.0 
#Создаём переменную, которая будет указывать расположение еды по оси х.
   foody = round(random.randrange(0, dis_width - snake_block) / 10.0) * 10.0 
#Создаём переменную, которая будет указывать расположение еды по оси y.
   while not game_over:
       while game_close == True:
           dis.fill(white)
           message("Вы проиграли! Нажмите Q для выхода 
или C для повторной игры", red)
           pygame.display.update()
           for event in pygame.event.get():
               if event.type == pygame.KEYDOWN:
                   if event.key == pygame.K_q:
                       game_over = True
                       game_close = False
                   if event.key == pygame.K_c:
                       gameLoop()
       for event in pygame.event.get():
           if event.type == pygame.QUIT:
               game_over = True
           if event.type == pygame.KEYDOWN:
               if event.key == pygame.K_LEFT:
                   x1_change = -snake_block
                   y1_change = 0
               elif event.key == pygame.K_RIGHT:
                   x1_change = snake_block
                   y1_change = 0
               elif event.key == pygame.K_UP:
                   y1_change = -snake_block
                   x1_change = 0
               elif event.key == pygame.K_DOWN:
                   y1_change = snake_block
                   x1_change = 0
       if x1 >= dis_width or x1 < 0 or y1 >= dis_height or y1 < 0:
           game_close = True
       x1 += x1_change
       y1 += y1_change
       dis.fill(white)
       pygame.draw.rect(dis, blue, [foodx, foody, snake_block, snake_block])
       pygame.draw.rect(dis, black, [x1, y1, snake_block, snake_block])
       pygame.display.update()
   
   pygame.quit()
   quit()
 
gameLoop()

Теперь при запуске игры кроме самой змейки будет показана еда. В нашем случае — в виде чёрного квадрата.

Скриншот: Pygame / Skillbox Media

А если выполнить условие для завершения игры, то появится сообщение с предложением выйти из игры или начать её заново:

Скриншот: Pygame / Skillbox Media

Увеличиваем длину змейки

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

import pygame
import time
import random
 
pygame.init()
 
white = (255, 255, 255)
yellow = (255, 255, 102)
black = (0, 0, 0)
red = (213, 50, 80)
green = (0, 255, 0)
blue = (50, 153, 213)
 
dis_width = 800
dis_height = 600
dis = pygame.display.set_mode((dis_width, dis_height))
pygame.display.set_caption('Змейка от Skillbox')
clock = pygame.time.Clock()
snake_block = 10
snake_speed = 15
font_style = pygame.font.SysFont("bahnschrift", 25) #Укажем название
 шрифта и его размер для системных сообщений, например, при завершении игры.
score_font = pygame.font.SysFont("comicsansms", 35) #Укажем шрифт и 
его размер для отображения счёта. Это мы реализуем очень скоро.
 
def our_snake(snake_block, snake_list):
   for x in snake_list:
       pygame.draw.rect(dis, black, [x[0], x[1], snake_block, snake_block])
 
def message(msg, color):
   mesg = font_style.render(msg, True, color)
   dis.blit(mesg, [dis_width / 6, dis_height / 3])
 
 
def gameLoop():
   game_over = False
   game_close = False
   x1 = dis_width / 2
   y1 = dis_height / 2
   x1_change = 0
   y1_change = 0
   snake_List = [] #Создаём список, в котором будем хранить 
показатель текущей длины змейки.
   Length_of_snake = 1 
   foodx = round(random.randrange(0, dis_width - snake_block) / 10.0) * 10.0
   foody = round(random.randrange(0, dis_height - snake_block) / 10.0) * 10.0
   while not game_over:
       while game_close == True:
           dis.fill(blue)
           message("Вы проиграли! Нажмите Q для выхода 
или C для повторной игры", red)
           pygame.display.update()
           for event in pygame.event.get():
               if event.type == pygame.KEYDOWN:
                   if event.key == pygame.K_q:
                       game_over = True
                       game_close = False
                   if event.key == pygame.K_c:
                       gameLoop()
       for event in pygame.event.get():
           if event.type == pygame.QUIT:
               game_over = True
           if event.type == pygame.KEYDOWN:
               if event.key == pygame.K_LEFT:
                   x1_change = -snake_block
                   y1_change = 0
               elif event.key == pygame.K_RIGHT:
                   x1_change = snake_block
                   y1_change = 0
               elif event.key == pygame.K_UP:
                   y1_change = -snake_block
                   x1_change = 0
               elif event.key == pygame.K_DOWN:
                   y1_change = snake_block
                   x1_change = 0
       if x1 >= dis_width or x1 < 0 or y1 >= dis_height or y1 < 0:
           game_close = True
       x1 += x1_change
       y1 += y1_change
       dis.fill(blue)
       pygame.draw.rect(dis, green, [foodx, foody, snake_block, snake_block])
       snake_Head = [] #Создаём список, в котором будет храниться 
показатель длины змейки при движениях.
       snake_Head.append(x1) #Добавляем значения в список при 
изменении по оси х.
       snake_Head.append(y1) #Добавляем значения в список при 
изменении по оси y.
       snake_List.append(snake_Head)
       if len(snake_List) > Length_of_snake:
           del snake_List[0] #Удаляем первый элемент в списке 
длины змейки, чтобы она не увеличивалась сама по себе при движениях.
       for x in snake_List[:-1]:
           if x == snake_Head:
               game_close = True
       our_snake(snake_block, snake_List)
       pygame.display.update()
       if x1 == foodx and y1 == foody: #Указываем, что в случаях, 
если координаты головы змейки совпадают с координатами еды, еда появляется 
в новом месте, а длина змейки увеличивается на одну клетку.
           foodx = round(random.randrange(0, dis_width - snake_block) / 10.0) * 10.0
           foody = round(random.randrange(0, dis_height - snake_block) / 10.0) * 10.0
           Length_of_snake += 1
       clock.tick(snake_speed)
   pygame.quit()
   quit()
 
gameLoop()

Дополнительно мы изменили цвет игрового поля и змейки, увеличив их контрастность.

Скриншот: Pygame / Skillbox Media

Добавляем отображение счёта

Добавим отображение счёта текущей игры. Для этого создадим функцию Your_score. Она будет отображать длину змейки, вычитая из неё 1 (ведь 1 — это начальный размер змейки, и это не является достижением игрока).

def Your_score(score):
   value = score_font.render("Ваш счёт: " + str(score), True, yellow)
   dis.blit(value, [0, 0])

И отдельно пропишем правило определения длины змейки, вычитая из текущей длины змейки единицу.

Your_score(Length_of_snake - 1)

Теперь на игровом поле будет отображаться текущий счёт:

Скриншот: Pygame / Skillbox Media

Можно считать, что наша работа над «Змейкой» закончена. Мы полностью реализовали геймплей, который запланировали на старте работы.

Наш код полностью и без комментариев:

import pygame
import time
import random
pygame.init()
white = (255, 255, 255)
yellow = (255, 255, 102)
black = (0, 0, 0)
red = (213, 50, 80)
green = (0, 255, 0)
blue = (50, 153, 213)
dis_width = 800
dis_height = 600
dis = pygame.display.set_mode((dis_width, dis_height))
pygame.display.set_caption('Змейка от Skillbox')
clock = pygame.time.Clock()
snake_block = 10
snake_speed = 15
font_style = pygame.font.SysFont("bahnschrift", 25)
score_font = pygame.font.SysFont("comicsansms", 35)
 
def Your_score(score):
   value = score_font.render("Ваш счёт: " + str(score), True, yellow)
   dis.blit(value, [0, 0])
 
def our_snake(snake_block, snake_list):
   for x in snake_list:
       pygame.draw.rect(dis, black, [x[0], x[1], snake_block, snake_block])
 
def message(msg, color):
   mesg = font_style.render(msg, True, color)
   dis.blit(mesg, [dis_width / 6, dis_height / 3])
 
def gameLoop():
   game_over = False
   game_close = False
   x1 = dis_width / 2
   y1 = dis_height / 2
   x1_change = 0
   y1_change = 0
   snake_List = []
   Length_of_snake = 1
   foodx = round(random.randrange(0, dis_width - snake_block) / 10.0) * 10.0
   foody = round(random.randrange(0, dis_height - snake_block) / 10.0) * 10.0
   while not game_over:
       while game_close == True:
           dis.fill(blue)
           message("Вы проиграли! Нажмите Q для выхода или C для повторной игры", red)
           Your_score(Length_of_snake - 1)
           pygame.display.update()
           for event in pygame.event.get():
               if event.type == pygame.KEYDOWN:
                   if event.key == pygame.K_q:
                       game_over = True
                       game_close = False
                   if event.key == pygame.K_c:
                       gameLoop()
       for event in pygame.event.get():
           if event.type == pygame.QUIT:
               game_over = True
           if event.type == pygame.KEYDOWN:
               if event.key == pygame.K_LEFT:
                   x1_change = -snake_block
                   y1_change = 0
               elif event.key == pygame.K_RIGHT:
                   x1_change = snake_block
                   y1_change = 0
               elif event.key == pygame.K_UP:
                   y1_change = -snake_block
                   x1_change = 0
               elif event.key == pygame.K_DOWN:
                   y1_change = snake_block
                   x1_change = 0
       if x1 >= dis_width or x1 < 0 or y1 >= dis_height or y1 < 0:
           game_close = True
       x1 += x1_change
       y1 += y1_change
       dis.fill(blue)
       pygame.draw.rect(dis, green, [foodx, foody, snake_block, snake_block])
       snake_Head = []
       snake_Head.append(x1)
       snake_Head.append(y1)
       snake_List.append(snake_Head)
       if len(snake_List) > Length_of_snake:
           del snake_List[0]
       for x in snake_List[:-1]:
           if x == snake_Head:
               game_close = True
       our_snake(snake_block, snake_List)
       Your_score(Length_of_snake - 1)
       pygame.display.update()
       if x1 == foodx and y1 == foody:
           foodx = round(random.randrange(0, dis_width - snake_block) / 10.0) * 10.0
           foody = round(random.randrange(0, dis_height - snake_block) / 10.0) * 10.0
           Length_of_snake += 1
       clock.tick(snake_speed)
   pygame.quit()
   quit()
gameLoop()

Узнать об особенностях работы с Pygame и возможностях библиотеки можно в официальной документации. Углубиться в разработку и попробовать другие игры можно благодаря специализированным книгам:

  • «Учим Python, делая крутые игры» Эла Свейгарта;
  • «Beginning Game Development with Python and Pygame: From Novice to Professional» Уилла Макгугана;
  • «Program Arcade Games: With Python and Pygame» Пола Винсента Крэйвена.

Учись бесплатно:
вебинары по программированию, маркетингу и дизайну.

Участвовать

Прежде чем мы начнём программировать что-то полезное на Python, давайте закодим что-нибудь интересное. Например, свою игру, где нужно не дать шарику упасть, типа Арканоида. Вы, скорее всего, играли в детстве во что-то подобное, поэтому освоиться будет просто.

Логика игры

Есть игровое поле — простой прямоугольник с твёрдыми границами. Когда шарик касается стенки или потолка, он отскакивает в другую сторону. Если он упадёт на пол — вы проиграли. Чтобы этого не случилось, внизу вдоль пола летает платформа, а вы ей управляете с помощью стрелок. Ваша задача — подставлять платформу под шарик как можно дольше. За каждое удачное спасение шарика вы получаете одно очко.

Алгоритм

Чтобы реализовать такую логику игры, нужно предусмотреть такие сценарии поведения:

  • игра начинается;
  • шарик начинает двигаться;
  • если нажаты стрелки влево или вправо — двигаем платформу;
  • если шарик коснулся стенок, потолка или платформы — делаем отскок;
  • если шарик коснулся платформы — увеличиваем счёт на единицу;
  • если шарик упал на пол — выводим сообщение и заканчиваем игру.

Хитрость в том, что всё это происходит параллельно и независимо друг от друга. То есть пока шарик летает, мы вполне можем двигать платформу, а можем и оставить её на месте. И когда шарик отскакивает от стен, это тоже не мешает другим объектам двигаться и взаимодействовать между собой.

Получается, что нам нужно определить три класса — платформу, сам шарик и счёт, и определить, как они реагируют на действия друг друга. Поле нам самим определять не нужно — для этого есть уже готовая библиотека. А потом в этих классах мы пропишем методы — они как раз и будут отвечать за поведение наших объектов.

Весь кайф в том, что мы всё это задаём один раз, а потом объекты сами разбираются, как им реагировать друг на друга и что делать в разных ситуациях. Мы не прописываем жёстко весь алгоритм, а задаём правила игры — а для этого классы подходят просто идеально.

По коням, пишем на Python

Для этого проекта вам потребуется установить и запустить среду Python. Как это сделать — читайте в нашей статье.

Начало программы

Чтобы у нас появилась графика в игре, используем библиотеку Tkinter. Она входит в набор стандартных библиотек Python и позволяет рисовать простейшие объекты — линии, прямоугольники, круги и красить их в разные цвета. Такой простой Paint, только для Python.

Чтобы создать окно, где будет видна графика, используют класс Tk(). Он просто делает окно, но без содержимого. Чтобы появилось содержимое, создают холст — видимую часть окна. Именно на нём мы будем рисовать нашу игру. За холст отвечает класс Canvas(), поэтому нам нужно будет создать свой объект из этого класса и дальше уже работать с этим объектом.

Если мы принудительно не ограничим скорость платформы, то она будет перемещаться мгновенно, ведь компьютер считает очень быстро и моментально передвинет её к другому краю. Поэтому мы будем искусственно ограничивать время движения, а для этого нам понадобится модуль Time — он тоже стандартный.

Последнее, что нам глобально нужно, — задавать случайным образом начальное положение шарика и платформы, чтобы было интереснее играть. За это отвечает модуль Random — он помогает генерировать случайные числа и перемешивать данные.

Запишем всё это в виде кода на Python:

# подключаем графическую библиотеку
from tkinter import *
# подключаем модули, которые отвечают за время и случайные числа
import time
import random
# создаём новый объект — окно с игровым полем. В нашем случае переменная окна называется tk, и мы его сделали из класса Tk() — он есть в графической библиотеке 
tk = Tk()
# делаем заголовок окна — Games с помощью свойства объекта title
tk.title('Game')
# запрещаем менять размеры окна, для этого используем свойство resizable 
tk.resizable(0, 0)
# помещаем наше игровое окно выше остальных окон на компьютере, чтобы другие окна не могли его заслонить
tk.wm_attributes('-topmost', 1)
# создаём новый холст — 400 на 500 пикселей, где и будем рисовать игру
canvas = Canvas(tk, width=500, height=400, highlightthickness=0)
# говорим холсту, что у каждого видимого элемента будут свои отдельные координаты 
canvas.pack()
# обновляем окно с холстом
tk.update()

Мы подключили все нужные библиотеки, сделали и настроили игровое поле. Теперь займёмся классами.

Шарик

Сначала проговорим словами, что нам нужно от шарика. Он должен уметь:

  • задавать своё начальное положение и направление движение;
  • понимать, когда он коснулся платформы;
  • рисовать сам себя и понимать, когда нужно отрисовать себя в новом положении (например, после отскока от стены).

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

# Описываем класс Ball, который будет отвечать за шарик 
class Ball:
    # конструктор — он вызывается в момент создания нового объекта на основе этого класса
    def __init__(self, canvas, paddle, score, color):
        # задаём параметры объекта, которые нам передают в скобках в момент создания
        self.canvas = canvas
        self.paddle = paddle
        self.score = score
        # цвет нужен был для того, чтобы мы им закрасили весь шарик
        # здесь появляется новое свойство id, в котором хранится внутреннее название шарика
        # а ещё командой create_oval мы создаём круг радиусом 15 пикселей и закрашиваем нужным цветом
        self.id = canvas.create_oval(10,10, 25, 25, fill=color)
        # помещаем шарик в точку с координатами 245,100
        self.canvas.move(self.id, 245, 100)
        # задаём список возможных направлений для старта
        starts = [-2, -1, 1, 2]
        # перемешиваем его 
        random.shuffle(starts)
        # выбираем первый из перемешанного — это будет вектор движения шарика
        self.x = starts[0]
        # в самом начале он всегда падает вниз, поэтому уменьшаем значение по оси y
        self.y = -2
        # шарик узнаёт свою высоту и ширину
        self.canvas_height = self.canvas.winfo_height()
        self.canvas_width = self.canvas.winfo_width()
        # свойство, которое отвечает за то, достиг шарик дна или нет. Пока не достиг, значение будет False
        self.hit_bottom = False
    # обрабатываем касание платформы, для этого получаем 4 координаты шарика в переменной pos (левая верхняя и правая нижняя точки)
    def hit_paddle(self, pos):
        # получаем кординаты платформы через объект paddle (платформа)
        paddle_pos = self.canvas.coords(self.paddle.id)
        # если координаты касания совпадают с координатами платформы
        if pos[2] >= paddle_pos[0] and pos[0] <= paddle_pos[2]:
            if pos[3] >= paddle_pos[1] and pos[3] <= paddle_pos[3]:
                # увеличиваем счёт (обработчик этого события будет описан ниже)
                self.score.hit()
                # возвращаем метку о том, что мы успешно коснулись
                return True
        # возвращаем False — касания не было
        return False
    # обрабатываем отрисовку шарика
    def draw(self):
        # передвигаем шарик на заданные координаты x и y
        self.canvas.move(self.id, self.x, self.y)
        # запоминаем новые координаты шарика
        pos = self.canvas.coords(self.id)
        # если шарик падает сверху  
        if pos[1] <= 0:
            # задаём падение на следующем шаге = 2
            self.y = 2
        # если шарик правым нижним углом коснулся дна
        if pos[3] >= self.canvas_height:
            # помечаем это в отдельной переменной
            self.hit_bottom = True
            # выводим сообщение и количество очков
            canvas.create_text(250, 120, text='Вы проиграли', font=('Courier', 30), fill='red')
        # если было касание платформы
        if self.hit_paddle(pos) == True:
            # отправляем шарик наверх
            self.y = -2
        # если коснулись левой стенки
        if pos[0] <= 0:
            # движемся вправо
            self.x = 2
        # если коснулись правой стенки
        if pos[2] >= self.canvas_width:
            # движемся влево
            self.x = -2

Платформа

Сделаем то же самое для платформы — сначала опишем её поведение словами, а потом переведём в код. Итак, вот что должна уметь платформа:

  • двигаться влево или вправо в зависимости от нажатой стрелки;
  • понимать, когда игра началась и можно двигаться.

А вот как это будет в виде кода:

#  Описываем класс Paddle, который отвечает за платформы
class Paddle:
    # конструктор
    def __init__(self, canvas, color):
        # canvas означает, что платформа будет нарисована на нашем изначальном холсте
        self.canvas = canvas
        # создаём прямоугольную платформу 10 на 100 пикселей, закрашиваем выбранным цветом и получаем её внутреннее имя 
        self.id = canvas.create_rectangle(0, 0, 100, 10, fill=color)
        # задаём список возможных стартовых положений платформы
        start_1 = [40, 60, 90, 120, 150, 180, 200]
        # перемешиваем их
        random.shuffle(start_1)
        # выбираем первое из перемешанных
        self.starting_point_x = start_1[0]
        # перемещаем платформу в стартовое положение
        self.canvas.move(self.id, self.starting_point_x, 300)
        # пока платформа никуда не движется, поэтому изменений по оси х нет
        self.x = 0
        # платформа узнаёт свою ширину
        self.canvas_width = self.canvas.winfo_width()
        # задаём обработчик нажатий
        # если нажата стрелка вправо — выполняется метод turn_right()
        self.canvas.bind_all('<KeyPress-Right>', self.turn_right)
        # если стрелка влево — turn_left()
        self.canvas.bind_all('<KeyPress-Left>', self.turn_left)
        # пока игра не началась, поэтому ждём
        self.started = False
        # как только игрок нажмёт Enter — всё стартует
        self.canvas.bind_all('<KeyPress-Return>', self.start_game)
    # движемся вправо 
    def turn_right(self, event):
        # будем смещаться правее на 2 пикселя по оси х
        self.x = 2
    # движемся влево
    def turn_left(self, event):
        # будем смещаться левее на 2 пикселя по оси х
        self.x = -2
    # игра начинается
    def start_game(self, event):
        # меняем значение переменной, которая отвечает за старт
        self.started = True
    # метод, который отвечает за движение платформы
    def draw(self):
        # сдвигаем нашу платформу на заданное количество пикселей
        self.canvas.move(self.id, self.x, 0)
        # получаем координаты холста
        pos = self.canvas.coords(self.id)
        # если мы упёрлись в левую границу 
        if pos[0] <= 0:
            # останавливаемся
            self.x = 0
        # если упёрлись в правую границу 
        elif pos[2] >= self.canvas_width:
            # останавливаемся
            self.x = 0

Счёт

Можно было не выделять счёт в отдельный класс и каждый раз обрабатывать вручную. Но здесь реально проще сделать класс, задать нужные методы, чтобы они сами потом разобрались, что и когда делать.

От счёта нам нужно только одно (кроме конструктора) — чтобы он правильно реагировал на касание платформы, увеличивал число очков и выводил их на экран:

#  Описываем класс Score, который отвечает за отображение счетов
class Score:
    # конструктор
    def __init__(self, canvas, color):
        # в самом начале счёт равен нулю
        self.score = 0
        # будем использовать наш холст
        self.canvas = canvas
        # создаём надпись, которая показывает текущий счёт, делаем его нужно цвета и запоминаем внутреннее имя этой надписи
        self.id = canvas.create_text(450, 10, text=self.score, font=('Courier', 15), fill=color)
    # обрабатываем касание платформы
    def hit(self):
        # увеличиваем счёт на единицу
        self.score += 1
        # пишем новое значение счёта 
        self.canvas.itemconfig(self.id, text=self.score)
        

Игра

У нас всё готово для того, чтобы написать саму игру. Мы уже провели необходимую подготовку всех элементов, и нам остаётся только создать конкретные объекты шарика, платформы и счёта и сказать им, в каком порядке мы будем что делать.

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

Посмотрите, как лаконично выглядит код непосредственно самой игры:

# создаём объект — зелёный счёт 
score = Score(canvas, 'green')
# создаём объект — белую платформу
paddle = Paddle(canvas, 'White')
# создаём объект — красный шарик 
ball = Ball(canvas, paddle, score, 'red')
# пока шарик не коснулся дна 
while not ball.hit_bottom:
    # если игра началась и платформа может двигаться
    if paddle.started == True:
        # двигаем шарик
        ball.draw()
        # двигаем платформу
        paddle.draw()
    # обновляем наше игровое поле, чтобы всё, что нужно, закончило рисоваться
    tk.update_idletasks()
    # обновляем игровое поле, и смотрим за тем, чтобы всё, что должно было быть сделано — было сделано
    tk.update()
    # замираем на одну сотую секунды, чтобы движение элементов выглядело плавно
    time.sleep(0.01)
# если программа дошла досюда, значит, шарик коснулся дна. Ждём 3 секунды, пока игрок прочитает финальную надпись, и завершаем игру
time.sleep(3)
# подключаем графическую библиотеку
from tkinter import *
# подключаем модули, которые отвечают за время и случайные числа
import time
import random
# создаём новый объект — окно с игровым полем. В нашем случае переменная окна называется tk, и мы его сделали из класса Tk() — он есть в графической библиотеке 
tk = Tk()
# делаем заголовок окна — Games с помощью свойства объекта title
tk.title('Game')
# запрещаем менять размеры окна, для этого используем свойство resizable 
tk.resizable(0, 0)
# помещаем наше игровое окно выше остальных окон на компьютере, чтобы другие окна не могли его заслонить. Попробуйте 🙂
tk.wm_attributes('-topmost', 1)
# создаём новый холст — 400 на 500 пикселей, где и будем рисовать игру
canvas = Canvas(tk, width=500, height=400, highlightthickness=0)
# говорим холсту, что у каждого видимого элемента будут свои отдельные координаты 
canvas.pack()
# обновляем окно с холстом
tk.update()
# Описываем класс Ball, который будет отвечать за шарик 
class Ball:
    # конструктор — он вызывается в момент создания нового объекта на основе этого класса
    def __init__(self, canvas, paddle, score, color):
        # задаём параметры объекта, которые нам передают в скобках в момент создания
        self.canvas = canvas
        self.paddle = paddle
        self.score = score
        # цвет нужен был для того, чтобы мы им закрасили весь шарик
        # здесь появляется новое свойство id, в котором хранится внутреннее название шарика
        # а ещё командой create_oval мы создаём круг радиусом 15 пикселей и закрашиваем нужным цветом
        self.id = canvas.create_oval(10,10, 25, 25, fill=color)
        # помещаем шарик в точку с координатами 245,100
        self.canvas.move(self.id, 245, 100)
        # задаём список возможных направлений для старта
        starts = [-2, -1, 1, 2]
        # перемешиваем его 
        random.shuffle(starts)
        # выбираем первый из перемешанного — это будет вектор движения шарика
        self.x = starts[0]
        # в самом начале он всегда падает вниз, поэтому уменьшаем значение по оси y
        self.y = -2
        # шарик узнаёт свою высоту и ширину
        self.canvas_height = self.canvas.winfo_height()
        self.canvas_width = self.canvas.winfo_width()
        # свойство, которое отвечает за то, достиг шарик дна или нет. Пока не достиг, значение будет False
        self.hit_bottom = False
    # обрабатываем касание платформы, для этого получаем 4 координаты шарика в переменной pos (левая верхняя и правая нижняя точки)
    def hit_paddle(self, pos):
        # получаем кординаты платформы через объект paddle (платформа)
        paddle_pos = self.canvas.coords(self.paddle.id)
        # если координаты касания совпадают с координатами платформы
        if pos[2] >= paddle_pos[0] and pos[0] <= paddle_pos[2]:
            if pos[3] >= paddle_pos[1] and pos[3] <= paddle_pos[3]:
                # увеличиваем счёт (обработчик этого события будет описан ниже)
                self.score.hit()
                # возвращаем метку о том, что мы успешно коснулись
                return True
        # возвращаем False — касания не было
        return False
    # метод, который отвечает за движение шарика
    def draw(self):
        # передвигаем шарик на заданный вектор x и y
        self.canvas.move(self.id, self.x, self.y)
        # запоминаем новые координаты шарика
        pos = self.canvas.coords(self.id)
        # если шарик падает сверху  
        if pos[1] <= 0:
            # задаём падение на следующем шаге = 2
            self.y = 2
        # если шарик правым нижним углом коснулся дна
        if pos[3] >= self.canvas_height:
            # помечаем это в отдельной переменной
            self.hit_bottom = True
            # выводим сообщение и количество очков
            canvas.create_text(250, 120, text='Вы проиграли', font=('Courier', 30), fill='red')
        # если было касание платформы
        if self.hit_paddle(pos) == True:
            # отправляем шарик наверх
            self.y = -2
        # если коснулись левой стенки
        if pos[0] <= 0:
            # движемся вправо
            self.x = 2
        # если коснулись правой стенки
        if pos[2] >= self.canvas_width:
            # движемся влево
            self.x = -2
#  Описываем класс Paddle, который отвечает за платформы
class Paddle:
    # конструктор
    def __init__(self, canvas, color):
        # canvas означает, что платформа будет нарисована на нашем изначальном холсте
        self.canvas = canvas
        # создаём прямоугольную платформу 10 на 100 пикселей, закрашиваем выбранным цветом и получаем её внутреннее имя 
        self.id = canvas.create_rectangle(0, 0, 100, 10, fill=color)
        # задаём список возможных стартовых положений платформы
        start_1 = [40, 60, 90, 120, 150, 180, 200]
        # перемешиваем их
        random.shuffle(start_1)
        # выбираем первое из перемешанных
        self.starting_point_x = start_1[0]
        # перемещаем платформу в стартовое положение
        self.canvas.move(self.id, self.starting_point_x, 300)
        # пока платформа никуда не движется, поэтому изменений по оси х нет
        self.x = 0
        # платформа узнаёт свою ширину
        self.canvas_width = self.canvas.winfo_width()
        # задаём обработчик нажатий
        # если нажата стрелка вправо — выполняется метод turn_right()
        self.canvas.bind_all('<KeyPress-Right>', self.turn_right)
        # если стрелка влево — turn_left()
        self.canvas.bind_all('<KeyPress-Left>', self.turn_left)
        # пока платформа не двигается, поэтому ждём
        self.started = False
        # как только игрок нажмёт Enter — всё стартует
        self.canvas.bind_all('<KeyPress-Return>', self.start_game)
    # движемся вправо 
    def turn_right(self, event):
        # будем смещаться правее на 2 пикселя по оси х
        self.x = 2
    # движемся влево
    def turn_left(self, event):
        # будем смещаться левее на 2 пикселя по оси х
        self.x = -2
    # игра начинается
    def start_game(self, event):
        # меняем значение переменной, которая отвечает за старт движения платформы
        self.started = True
    # метод, который отвечает за движение платформы
    def draw(self):
        # сдвигаем нашу платформу на заданное количество пикселей
        self.canvas.move(self.id, self.x, 0)
        # получаем координаты холста
        pos = self.canvas.coords(self.id)
        # если мы упёрлись в левую границу 
        if pos[0] <= 0:
            # останавливаемся
            self.x = 0
        # если упёрлись в правую границу 
        elif pos[2] >= self.canvas_width:
            # останавливаемся
            self.x = 0
#  Описываем класс Score, который отвечает за отображение счетов
class Score:
    # конструктор
    def __init__(self, canvas, color):
        # в самом начале счёт равен нулю
        self.score = 0
        # будем использовать наш холст
        self.canvas = canvas
        # создаём надпись, которая показывает текущий счёт, делаем его нужно цвета и запоминаем внутреннее имя этой надписи
        self.id = canvas.create_text(450, 10, text=self.score, font=('Courier', 15), fill=color)
    # обрабатываем касание платформы
    def hit(self):
        # увеличиваем счёт на единицу
        self.score += 1
        # пишем новое значение счёта 
        self.canvas.itemconfig(self.id, text=self.score)
# создаём объект — зелёный счёт 
score = Score(canvas, 'green')
# создаём объект — белую платформу
paddle = Paddle(canvas, 'White')
# создаём объект — красный шарик 
ball = Ball(canvas, paddle, score, 'red')
# пока шарик не коснулся дна 
while not ball.hit_bottom:
    # если игра началась и платформа может двигаться
    if paddle.started == True:
        # двигаем шарик
        ball.draw()
        # двигаем платформу
        paddle.draw()
    # обновляем наше игровое поле, чтобы всё, что нужно, закончило рисоваться
    tk.update_idletasks()
    # обновляем игровое поле и смотрим за тем, чтобы всё, что должно было быть сделано — было сделано
    tk.update()
    # замираем на одну сотую секунды, чтобы движение элементов выглядело плавно
    time.sleep(0.01)
# если программа дошла досюда, значит, шарик коснулся дна. Ждём 3 секунды, пока игрок прочитает финальную надпись, и завершаем игру
time.sleep(3)

Пишем игру на Python

Что дальше

На основе этого кода вы можете сделать свою модификацию игры:

  • добавить второй шарик;
  • раскрасить элементы в другой цвет;
  • поменять размеры шарика; поменять скорость платформы;
  • сделать всё это сразу;
  • поменять логику программы на свою.

Для работы проектов iXBT.com нужны файлы cookie и сервисы аналитики.
Продолжая посещать сайты проектов вы соглашаетесь с нашей
Политикой в отношении файлов cookie

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

— Я придумал игру, создай мне её.
— А почему ты сам её не создашь?
— Я не умею.

И я задумался, а так ли сложно что-то создать с нынешним количеством уроков и тем по созданию игр в интернете?

С чего начать?

Для начала нам нужна идея, что за игру мы будем создавать, благо у меня была идея брата. Рассмотрим её поближе.

  1. Это РПГ в средневековом стиле (банально, не правда ли? =) )
  2. Она должна быть 3D, а не 2D (тут, кстати, довольно интересно, потому как в основном весь интернет пестрит роликами с 2D играми)
  3. Вид камеры от третьго лица
  4. Характеристики изменяются сами с повышением уровня, с упором на используемое оружие.
  5. Лимит уровней — 30
  6. Предметы привязаны к уровню персонажа (персонаж четвертого уровня не сможет использовать предмет пятого уровня) 
  7. Движок, на котором всё будет работать (в моём случае это Unity: по работе с ним самое большое количество уроков на мой взгляд)

Думаю, что данный план вполне подойдёт для создания шедевра ААА класса =).

Начнём создавать шедевр

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

Идём в интернет и спрашиваем «как нам начать использовать Unity?».

Запускаем Unity Hub.

Выбираем NEW и далее 3D проект, пишем название и местоположение проекта.

И открывается сама программа.

И тут, наверное, знатоки начнут кидаться картошкой со словами «Зачем столько воды? Все и так это знают» НО! Материал предназначен в первую очередь для тех, кто ничего не умеет, а не для гуру геймдева =).

Дальше снова идём в интернет либо проходим туториал в самой программе, чтобы научиться основам работы с движком. Для того, чтобы воспользоваться туториалом в программе, нужно в окне Unity Hub нажать на строчку Learn и выбрать любой из проектов. Я советую пройти все уроки и посмотреть несколько роликов по созданию игр.

Как создать модели для игры?
  1. Научиться моделированию (сложно, долго, но интересно)
  2. Купить готовый пак моделей (быстро и просто, но за деньги)

Я выбрал второй вариант. Отправляемся в AssetStore. Если у вас не активировалась ваша учетная запись, повторно входим в личный кабинет. И начинаем искать подходящие паки. Я нашел то, что нужно, примерно за 3 минуты по поиску knight. В паке, помимо моделей самих персонажей, были модели окружения. Купил за 10 долларов, нажал Import, поставил все галочки, и пропала проблема, неумения моделировать. 1/4 игры готово.

Сцена

Дальше начинается самое нудное. Нужно собрать рабочую зону (scene, сцену, кому как привычнее называть).

Я привык сначала прописывать персонажей, анимацию, и прочую ненужную (очень нужную) ерунду в начале работы, а уже после того как основные механики готовы, я собираю уровень (локацию, игровую зону). Для начала давайте в сцену поставим кусок земли, на которой будет стоять наш персонаж, и начнём работать с анимацией.

Поскольку мы с вами в этом деле новички, снова лезем в интернет и смотрим, как нам поставить поверхность в игровую зону. Выбираем GameObject -> 3D Object -> Cube, после масштабируем его до простой площадки.

Далее добавляем персонажа (рыцаря, демона, ниндзю, тяночку, или кто вам больше по душе). Персонажа берем из папки Prefabs: мы уже знаем (вспоминаем, чему нас научили во вкладке Learn), что туда сохраняют полностью готовые объекты, персонажей и так далее.

И вот он, наш герой, который будет покорять всех и вся.

Анимация

Помните в рейде «Цитадель Ночи» в World of Warcraft был босс Алуриэль? Когда она произносила заклинания, то кричала «Аннигиляция, репликация, детонация, АНИМАЦИЯ!!!». Нам необходимо с криком «Анимация!» наброситься на интернет и понять, как её сделать.

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

  1. Идём на сайт www.mixamo.com
  2. Регистрируемся
  3. Получаем огромное количество анимации на все случаи жизни

Что нужно в первую очередь? По мне — так научиться ходить и бегать. Возьмём анимацию ходьбы и бега.

  • В поисковике анимации набираем walking, выбираем понравившуюся анимацию, и ставим галочку In Place
  • Далее нам нужно подгрузить FBX модель от купленного пака для того, чтобы анимация не баговала (иногда такой модели может не быть в паке, но сейчас 99% разработчиков дают модель при покупке любого пака бесплатно либо она может лежать на официальном сайте). Тыкаем на upload character и загружаем модель FBX со смешным названием Mixamo_Guy_Naked.fbx.
  • Видим, что наш FBX заменил стандартную модель миксамо, и при желании можно кастомизировать анимацию, но этого делать мы, конечно же, не будем. Меня всё устраивает. Я жмякаю кнопку Download, выбираю Frames per Second 60 — анимация ходьбы готова.
  • Проделываем туже процедуру с анимацией бега (и другими, в зависимости от того, сколько вы их хотите добавить в данный момент)

Теперь создаём папку Animation в Unity и добавляем туда нашу анимацию. Начинаем настройку.

  • Выбираем анимацию, в inspector переходим на вкладку Rig, в строке Animation Type выбираем Humanoid и тыкаем Apply.
  • Заходим во вкладку Configure, если выползет окно, нажимаем save. В первую очередь нажимаем на вкладку Head, и в строке Jaw вместо Eyebrows ставим none (на вопрос «Почему?» скажу, что у нас просто нет бровей). Далее выбираем Left Hand и в строку Little Proximal, Little Intermediate, Little Distal ставим none, далее Middle Proximal — Finger_01, Middle Intermediate — Finger_02, Middle Distal — Finger_03. Мы делаем это, потому что у нашей FBX модели есть только указательный палец, а остальные три идут как один.
  • Проделываем всё то же самое с Right Hand, пальцы там будут иметь названия Finger_011, Finger_021, Finger_031, Apply, Done.
  • Повторяем всё выше написанное с каждой новой анимацией.
  • В Inspector анимации переходим во вкладку Animation. В строке Clips выбираем mixamo.com, меняем название над Source Take на Walking, выставляем галочки напротив Loop Time, Bake into Pose(Y,XZ), Apply. С анимацией Running проделываем то же самое, НО! Не забываем поменять название на Running.
  • Создаём Animator Controller, тыкаем правой кнопкой, в диалоговом окне выбираем Create -> Animator Controller
  • Заходим в Animator Controller, тыкаем правой кнопкой Create State -> Empty, выбираем появившийся бочонок New State, Смотрим в inspector и в строке Motion выбираем анимацию ходьбы walking, добавляем второй бочонок и в нём выбираем анимацию Running. И тут я понимаю, что у меня нет анимации бездействия (стоять на месте), быстро бегу в миксамо, выбираю анимацию бездействия Idle и добавляю её в проект =)
  • Сейчас необходимо правильно объединить анимацию. Бочонок Idle должен быть первым, чтобы персонаж без действий проигрывал анимацию Idle. Тыкнем по бочонку правой кнопкой и выберем Set as Layer Default State. Как видим, он теперь стал желтый и идёт сразу после Entry. Теперь подключаем анимацию Walking и Running, используем Make Transition и протягиваем стрелочки от бочонков друг к другу.
  • И лайфхак: чтобы не было задержек между переходами анимации, заходим в настройки транзисторов (белых стрелочек) и убираем галочки Has Exit Time, жмякаем на Setting и выставляем Transition Duration(s), Transition Offset на 0.
  • Смотрим в параметры Animator — туда где написано List is Empty, нажимаем на плюсик, добавляем Bool и переименовываем его в Idle, создаем второй Bool и называем его Running.
  • Выбираем транзистор, который идёт от Idle к Running, справа в строке Conditions нажимаем плюс и добавляем Idle = false, на обратном транзисторе Idle = true. С транзисторами Idle — Walking проделываем ту же процедуру. С транзисторами Running — Walking проделываем аналогичную процедуру, но в этот раз используем параметр Running.

Вот мы и победили нашу анимацию! УРА! Теперь нам нужно подключить её к нашему персонажу. Вперед, к финишной прямой!

Выбираем персонажа, inspector, окно Animator, и в строке Controller нажимаем на кругляшок. Появится выбор, где мы и увидим нашу Animation, выбираем её и нажимаем на кнопку Play в Unity. Если вы всё сделали правильно, то сейчас должны наблюдать как ваш персонаж стоит, и у него проигрывается анимация Idle. То есть, он стоит и немного покачивается.

 С анимацией разобрались, пора включать снова человека, который ничего не умеет =)

Скрипт W A S D

Анимация у нас есть, теперь нужно заставить нашего персонажа двигаться. Покопавшись в интернете, я узнал, что можно просто добавить компонент Character Controller. Так и сделаем — тыкнем Add Component, в поиск вбиваем Character Controller и добавляем его, в строке Center выставляем Y=1 (нужно, чтобы «яйцо» покрывало всего персонажа. Если у вас получилось меньше или больше, то просто настройте его вручную).

И снова прочесав гигантской расческой интернет, я всё же нашел скрипт, который у меня заработал. Значит, пора его добавить в Unity. Жмякаем правой кнопкой, Create -> C# Script. Назовём его Move. Добавим туда такой код:

Тут код

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(CharacterController))]

public class Move: MonoBehaviour
{

public float speed = 3.0F;
public float rotateSpeed = 3.0F;
void Update()
{
float horizontal = Input.GetAxis(«Horizontal»);
float vertical = Input.GetAxis(«Vertical»);

CharacterController controller = GetComponent<CharacterController>();
transform.Rotate(0, horizontal * rotateSpeed, 0);
Vector3 forward = transform.TransformDirection(Vector3.forward);
float curSpeed = speed * vertical;
controller.SimpleMove(forward * curSpeed);

if (controller.velocity == Vector3.zero)
{
GetComponent<Animator>().SetBool(«Idle», true);
}
if (controller.velocity != Vector3.zero)
{
GetComponent<Animator>().SetBool(«Idle», false);
}
}
}

Тут я немного поясню скрипт.

Верхние четыре строчки — это подключение библиотек, public class — название скрипта. Если у Вас скрипт называется Moving или что-то в этом роде, то поменяйте название. Учтите, к регистру скрипт тоже придирчив.

public float speed = 3.0F; public float rotateSpeed = 3.0F; — это скорость персонажа, настраивается по желанию. Далее идёт подключение управления Character Controller и, соответственно, анимации.

Перетаскиваем скрипт в Inspector персонажа и проверяем. It’s ALIVE!!!!!

Но есть нюанс: поворачивается наш персонаж слишком быстро и не подключена анимация бега. Скорость поворота лечится просто — выставляем в строке Rotate Speed 0.5, и наш персонаж больше не использует чит-крутилку из CS GO. Теперь сделаем, чтобы наш персонаж все-таки побежал. Снова интернет, хотя, по мне, тут можно и логически додумать, как всё провернуть, но всё же я нашел строчку кода, чтобы всё заработало. Добавляем в наш код такую строчку

Нажмите, чтобы развернуть

if (Input.GetButtonDown(«Fire3»))
GetComponent<Animator>().SetBool(«Running», true);
else if (Input.GetButtonUp(«Fire3»))
GetComponent<Animator>().SetBool(«Running», false);

Если у Вас возникли вопросы, что такое Fire3, то ответ прост: это LShift, а проверить это можно, зайдя File->Build Setting->Player Setting->Input Manager. Эту информацию также не составило труда найти в интернете.

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

Нажмите, чтобы развернуть

if (Input.GetKey(KeyCode.LeftShift))
{
speed = 6.0f;
}
else
{
speed = 3.0f;
}

В итоге весь скрипт у нас получился такого вида

Нажмите, чтобы рассмотреть весь скрипт

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

[RequireComponent(typeof(CharacterController))]

public class Move: MonoBehaviour
{

public float speed = 3.0F;
public float rotateSpeed = 3.0F;
void Update()
{
float horizontal = Input.GetAxis(«Horizontal»);
float vertical = Input.GetAxis(«Vertical»);

CharacterController controller = GetComponent<CharacterController>();
transform.Rotate(0, horizontal * rotateSpeed, 0);
Vector3 forward = transform.TransformDirection(Vector3.forward);
float curSpeed = speed * vertical;
controller.SimpleMove(forward * curSpeed);

if (Input.GetKey(KeyCode.LeftShift))
{
speed = 6.0f;
}
else
{
speed = 3.0f;
}

if (controller.velocity == Vector3.zero)
{
GetComponent<Animator>().SetBool(«Idle», true);
}
if (controller.velocity != Vector3.zero)
{
GetComponent<Animator>().SetBool(«Idle», false);
}
if (Input.GetButtonDown(«Fire3»))
GetComponent<Animator>().SetBool(«Running», true);
else if (Input.GetButtonUp(«Fire3»))
GetComponent<Animator>().SetBool(«Running», false);
}

}

Всё проверили, всё работает, осталось только прикрепить камеру к персонажу. Без заморочек просто перетаскиваем Main Camera в нашего персонажа, далее её настраиваем как нам удобно, проверяем и празднуем ПОБЕДУ!

Заключение

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

Я считаю, что не имея никаких знаний и денег, а только немного терпения, можно самому создать свою игру. Если вас смущает покупка пака из Asset Store, то всегда можно найти бесплатные паки. Я порылся в интернете и нашел как минимум 6 ресурсов, которые их предоставляют. Советую помимо интернета начать изучение какого-либо направления гейм дева.

Все описанное в этой статье было собрано без специальных знаний с помощью интернета.

Писать игры – тайное желание миллионов геймеров. У каждого своя цель: рассказать историю, стать известным, донести идею или просто создать хороший и интересный продукт. Как делать игры, если вы ничего не умеете? Рассказываем, как начать, что понадобится, с какими сложностями придется столкнуться и каких ошибок избегать.

Спойлер: научиться можно всему. Но придется приложить усилия.

Игры – это не легко. Перед тем как сделать свою игру, вы потратите много часов на обучение, неоднократно столкнетесь со сложностями, но и это не означает, что ваш проект «взлетит». Большинство «первых проб пера» оказывается неудачным и не доходит до релиза. Причина – создатели переоценили силы, возможности, время и навыки. Но шанс есть.

Разработка игр в фактах. Вот несколько фактов, которые говорят сами за себя.

  • Известную инди-игру Stardew Valley полностью сделал один человек, Эрик Барон. На разработку ушло 5 лет. Он не ходил на работу – на жизнь зарабатывала его девушка.
  • Для разработки крупных проектов вроде Mass Effect нужны сотни работников и миллионы долларов. Сотрудникам, бывает, приходится работать сверхурочно. Создание игры все равно занимает несколько лет.
  • Во время работы над Red Dead Redemption 2 сотрудники Rockstar порой работали по 100 часов в неделю.
  • В средней игре от нескольких сотен тысяч до нескольких миллионов строк кода. Например, в «Ведьмак 3» без дополнений – 1,136 млн.

Как менялась внешность главы игровой студии CD Projekt Red за годы разработки игр

Зачем тогда это все? Делать свои игры очень интересно. Разработчик или геймдизайнер может задать новые стандарты для геймдева – так было с Hollow Knight или Minecraft, получить благодарность от игроков и удовольствие от процесса.

Читайте также: Кто такой разработчик игр?

Создавать карты для готовых игр. Процесс занимает меньше времени, чем создание полноценной игры. Но он помогает сориентироваться и понять, хотите ли вы заниматься разработкой.

Можно делать карты для Far Cry 4, Counter Strike или других «боевых» игр, экспериментировать с головоломками вроде Portal 2 или с симуляторами, например Trainz Railroad Simulator 2004.

Чаще всего карты создают с помощью специального редактора в самой игре. В нем можно расставлять предметы, задавать им свойства и пр.

Примерный алгоритм действий:

  • скачать редактор;
  • продумать, какую карту хотите создать;
  • расставить предметы;
  • спланировать освещение;
  • задать логику и взаимодействия;
  • протестировать карту, чтобы понять, можно ли с ней играть;
  • выкладывать, если вас все устраивает.

Написать игру на конструкторе. Если вам не интересны чужие проекты, и вы хотите сразу попробовать что-то свое, можно создать игру на специальном движке:

  • GameMaker Studio. Простой и популярный вариант. Его используют не только новички, но и опытные инди-разработчики. На нем написано много инди-игр, включая широко известную Undertale;
  • RPG Maker. Японский движок, на котором создают двумерные пиксельные игры. Он сложнее GameMaker, но у него больше функций. Множество пиксельных инди-проектов, например, Ib, написано именно на нем;
  • Instead или RenPy. Движки подойдут, если вам интересна не механика, а история. Они позволяют создавать текстовые квесты и визуальные новеллы. Но для работы придется немного уметь программировать.

Если знания и опыт в IT есть, можно начать создавать свои 2D- и 3D-игры на Unity или Unreal Engine. Это два основных движка. Писать на них относительно просто, сложнее оптимизировать игры. Помните, что в инди часто играют на относительно слабых устройствах, например на ноутбуках или старых компьютерах.

Unity. Движок появился в 2005 году для устройств на iOS, но быстро распространился на другие платформы. Для создателей Unity – основной продукт, и это важно, потому что влияет на всю экосистему.

  • Основная идея – сделать процесс разработки для инди-девелоперов простым и понятным.
  • Экосистема включает дополнительные продукты, в том числе платные, с курсами, сертификатами и другими видами поддержки.
  • На Unity можно писать игры под разные платформы, в том числе мобильные.
  • Слабое место Unity – оптимизация игр, а также сложности с подключением внешних библиотек и менее «красивый» внешний вид сцены по умолчанию.
  • Разработка ведется на языке C#. Можно писать на визуальном языке Bolt.

Читайте также: Как создать игру на Unity

Unreal Engine. UE появился раньше, в 1998 году. Движок создала компания Epic Games. Ее основная деятельность – разработка игр с его помощью. Название произошло от первой игры, созданной на движке, – Unreal.

  • Основная идея Unreal Engine – эффективность разработки и «выжимание» максимума из возможностей компьютера.
  • Движок рассчитан на создание крупных 3D-проектов. Поддержка 2D-игр тоже есть, но не такая мощная, как в Unity. То же самое касается мобильной разработки. UE – это в первую очередь компьютеры и консоли.
  • Разработка ведется на C++. Он сложнее, но быстрее в освоении, чем C#. Также есть внутренний визуальный язык Blueprints, который легко освоить.
  • Слабые места – высокая требовательность движка к компетенции разработчика и к «железу». Unreal Engine нужно много аппаратных ресурсов.

Что выбрать. Unreal Engine и Unity бесплатные, но если игра «взлетит», нужно заплатить разработчику движка. В лицензии Unity указано, что когда доход от игры превысит 100 тыс долларов, нужно купить платную подписку. Unreal Engine требует роялти в размере 5% с игр, которые приносят больше 3 тыс долларов ежеквартально.

  • Unity можно выбрать, если вы хотите работать с 2D или мобильными проектами, а также важна модульность и гибкость движка. У него более широкое сообщество, больше туториалов, поэтому ниже порог входа.
  • Unreal Engine подойдет, если вы хотите сконцентрироваться на 3D-разработке для ПК, сразу «делать красиво» и эффективно. Но будет нужно более мощное «железо». Порог входа выше, хотя в последние годы разница стирается.

Скачать движок. Это можно сделать бесплатно на сайте проекта. Установка простая: следуйте инструкциям, как в случае с любой программой. О том, как скачать и установить Unity, мы рассказали в статье.

Начать тренироваться. Сначала сделайте что-то простое: не нужно сразу браться за сложный проект. Начните с азов и постепенно усложняйте задачу.

Сделать тестовую игру. Ваша цель – создать и довести проект до конца. Если вы бросите на середине, то не сможете пройти все этапы разработки и упустите важные нюансы.

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

Действовать дальше. После создания первой игры вы поймете, как и куда дальше развиваться, что нужно знать. Чтобы улучшить навыки, можно участвовать в джемах – это мероприятия вроде хакатонов, где за ограниченное время нужно создать готовый проект. Игры с джемов редко становятся популярны, хотя есть исключения, например Hollow Knight. Мероприятия дают бесценный опыт и возможность узнать новое.

Читайте также: NFT-галерея, шутер в пустыне и космический платформер: кейсы студентов курса по разработке игр

Зацикленность на технологиях. Ваша главная задача – разрабатывать игры, а не изучать все технологии сразу. Поэтому не нужно выбирать редкие движки. На них тяжело учиться, а перебор может занять слишком много времени. Тем более для новичков разницы мало. Исключение – если вы энтузиаст, которому важно в первую очередь работать с технологиями, а не создавать игры.

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

Ориентированность только на деньги. Не нужно сразу гнаться за коммерческим успехом. Учитесь создавать хорошие игры, творить и придумывать что-то интересное – это важнее и принесет больше пользы. Делайте игры, которые вам нравятся, а не то, что популярно и приносит прибыль. Это не значит, что о доходе не нужно думать. Просто на старте это не главное, и вы должны быть готовы к тому, что получать деньги за создание игр начнете не сразу.

Необъективность. Посмотреть на результат со стороны очень сложно, поэтому разработчики часто необъективны по отношению к созданным играм. Но, чем раньше вы научитесь быть честным с собой, тем быстрее вы будете учиться. Это увеличивает шанс создать по-настоящему хорошую игру. Обращайте внимание на критику со стороны и исправляйте ошибки. Но учитесь отличать полезную критику от простого желания вас задеть.

Если вы мечтаете создавать игры – не бойтесь и начните: практика – лучший способ научиться.

Понравилась статья? Поделить с друзьями:
  • Как написать простейший парсер
  • Как написать простейший калькулятор на питоне
  • Как написать прокуратуру жалобу на дпс
  • Как написать простейший калькулятор на python
  • Как написать проклятие на человека