С этой первой статьи я бы хотел начать своё увлекательное повествование о создании игры своими руками. Все Вы помните из детства (это больше обращено к детям, которые росли в 90-ые) столь увлекательные игры на приставке Dendy или Sega. Например всемирно известный Mario, со всеми своими красочными мирами, а энергичный боевик Contra, уничтожающий всё на своём пути, а чего только стоят "Танчики", музыку с которого мы напевали чуть ли не всё своё детство, и так далее. Но эта статья сейчас не об этом, а о том, как это выглядит изнутри, что там под капотом и как оно работает. Нет, мы не будем заниматься играми конкретно под приставки, со своим сложным ассемблером, мы поговорим о web-браузерных играх, написанных на прекраснейшем, по моему мнению, фреймворке Phaser 3. Но немного предыстории.
Я с юношества мечтал научиться создавать подобные игры, или хотя бы примитивные. Меня интересовала, как будущего программиста (хотя я об этом ещё не подозревал), техническая сторона вопроса. Вообще программированием я стал увлекаться примерно с лет 14-15, когда впервые увидел 80286 у своей мамы на работе, я часто тогда после школы "торчал" у мамы на работе, так и маме спокойней, что я под наблюдением, и мне не надо "одному" переться 14 километров со школы домой, к тому же, по счастливой случайности я учился практически "под боком" с локомотивным депо, где и работала некогда моя мама.
После того как я зажёгся компьютерами, мне захотелось узнать каким образом рисуется графика на экране монитора, как эту графику оживлять, и как это можно управлять героем игры, просто нажимая на клавиши, всё это вкупе поражало моё детское воображение. Но непосредственно программированию я стал обучаться примерно в классе 9-ом, когда мой очень хороший друг детства Jeff (это его никнейм тех времен) отвёл в Станцию Юных Техников (СЮТ) и познакомил с великолепным педагогом, которого я до сих пор вспоминаю с теплом и нотками ностальгии, где я постигал ZX-Spectrum со своим Basic-ом.
Но пожалуй достаточно автобиографии, давайте же наконец перейдём к сути вопроса. Итак, каким же образом создать свою собственную игру? Но прежде чем мы будем погружаться в строки кода, я бы хотел немного ввести Вас теоретически, что из себя представляет игра.
Неважно какого жанра 2D игра (платформер это или что-то вроде RPG), как Вы наверное заметили, любая из них состоит из неких элементов (блоков если хотите), которые составляют как мозайка игровой мир, который вы видите на мониторе (или на телевизоре, если играли в приставку). Каждый блок, это элемент графики, который составляет предметы в игре, персонажей, врагов, дома, дороги и так далее. Всё рисуется этими маленькими графическими кирпичиками и в целом составляют красочный игровой мир. Такой кирпичик или плитка называется на английском Tile, а карта которая строится из таких элементов Tilemap. Но не спешите подумать, что художник рисует уровень игры, а программист "тупо" вставляет цельную картинку как есть в игру и дело в шляпе. Всё немного сложнее, и я решил написать серию статей с подробным описанием каждого шага этого длительного и кропотливого процесса, как создание игры с нуля. Что подразумевается "с нуля" Вы наверное догадались - просто имеется ввиду, что я буду рассказывать не только как запрограммировать логику игры, как оживить спрайты (в какой-нибудь статье мы подробно разберём, что такое спрайты), а также введу Вас в курс каким образом самому создать Tilemap и каким образом её вставить в свою игру, более того, забегая вперёд приятно Вас удивлю - мы также рассмотрим как быстро и просто создать препятствия для персонажа и других участников игры, без особого труда сделать опасные преграды, столкнувшись с которыми главный герой погибает (в нашем примере , который мы будем разбирать - это будут шипы или вода, в которой управляемый персонаж тонет).
Я решил сразу идти в Ва-банк. В русскоязычном секторе довольно скудная информация про Phaser, лишь несколько статей на хабре и переведённое руководство на Mozilla Developer Network, не более того. И то, в этом руководстве разбирается примитивная игра вроде арканоида. Конечно она обучает основам программирования игр с помощью Phaser, но я считаю, она не обучит Вас сразу перейти на "высокий" уровень Game Dev. Вот почему я сразу решил взять быка за рога и посвятить немного времени, написав эти статьи. Конечно, сразу оговорюсь, что эта серия статей ни в коим случае не претендует на самое полное и подробное руководство по созданию игр, но некоторую информацию я всё же доведу до Вас и мы сделаем оконченную полноценную игру (ну или почти полноценную).
Итак, вернёмся к нашим баранам. Как я уже написал выше, любая игра представляет из себя Tilemap. Некоторые карты уровней представляют собой длинные картинки, которые вытягиваются на несколько тысяч ячеек сетки (в каждой ячейки этой сетки находится Tile, о котором мы говорили выше). Например ниже я представлю панораму всего первого уровня игры Mario, Всем хорошо знакомую с детства с приставки Dendy.
Честно говоря, здесь на Дзене слишком узкая ширина статьи, и не позволяет в полном объёме вставить длинную картинку, поэтому я Вам оставлю ссылку , которая Вас переведёт к картинке первого уровня игры Mario, и Вы можете увеличить и рассмотреть сколько Вам "влезет".
Если бы, как я выше написал, художник рисовал такой уровень, отдавал цельной картинкой программисту и он вставлял её в игру, то появилось бы несколько адских проблем у программиста: 1) во-первых игра бы занимала гораздо больше места, ведь надо хранить цельную картинку в игре, что не рационально 2) во-вторых программисту бы было бы сложнее по координатам привязать Mario (главного героя) к платформе (земле по которой он бегает, более того, Mario ведь может запрыгивать на платформы как-бы висящие в воздухе, плюс ко всему есть трубы, по которым он лазит и так далее. Можно перечислять ещё тонну сопутствующих проблем, некоторые из которых технически сложно реализуемые, а некоторые вообще не реализуемые. Такая бы игра постоянно зависала бы и тормозила, потому что бы сжирала много процессорного времени и мощности.
Поэтому разработчики игр поступают иначе, Они берут у художника (или сами рисуют) так называемый Tileset. Это набор уникальных элементов, встречающихся на данной карте игрового мира. Например для первого уровня игры Mario достаточно иметь следующий Tileset.
Я скажу ещё больше - этого Tileset хватает для всех уровней Mario, вот насколько мы сильно ужали картинку (смотри первый уровень Mario) до скромного Tileset.
Теперь художник, пользуясь как палитрой с краской, этим набором блоков начинает рисовать уровень. Для создания игровых миров существует замечательная программа под названием Tiled Editor, или просто Tiled. В какой-нибудь статье я немного затрону вопрос как сделать свою карту, на примере нашей игры, которую мы будем разбирать в течении всего цикла статей. Так что запаситесь попкорном и наслаждайтесь чтением этих статей.
Прежде чем завершить первую часть нашего мини-курса по созданию игр хотел бы начать с базового шаблона, с которого начинается любое построение игры на Phaser. Немного слов о самом Phaser - это framework, для создания ярких и красочных HTML5 игр, как 2D, так и 3D. В ней используется технология Canvas - это специальный браузерный холст, на котором рисуются различные графические объекты. Так как на дворе уже 2020 год, то и будем рассматривать 3-ю версию Phaser, которая радикально отличается от второй версии. Сначала я приведу стандартный базовый шаблон игры, написанный на Phaser 3, а в другой статье мы обязательно рассмотрим такой вопрос , как модульное программирование и как нашу игру можно преобразовать в модули, что является правильным и профессионально написанным программным кодом.
Любая игра на Phaser 3 строится вокруг глобального объекта Scene. Это что-то похожее на объект State со второй версии Phaser, но более гибкий.
Сначала создаётся объект config, в который передаются все необходимые свойства. Этих свойств на самом деле больше, чем в этом шаблоне, но я представил стандартные, которые используются практически во всех играх. Опишем их:
- type - тип контекста холста, который может принимать значения AUTO, CANVAS и WEBGL. Чаще используют Phaser.AUTO константу, которая сама автоматически определяет возможности Вашего браузера и подключает тот или иной контекст холста.
- width - ширина холста
- height - высота холста
- parent - Id DOM-элемента холста, который вставиться на страницу браузера
- scene - объект, который описывает три функции сцены игры. Это preload, create и update.
Preload содержит в себе методы загрузки всей графики и данных карты уровней. Эта функция запускается когда игра инициализируется и уже на момент создания объектов игры, вся графика будет загружена в память.
Create - функция, в которой создаётся игровой мир, анимации, коллайдеры и так далее, т.е. это сердце Вашей игры, где происходит создание всех объектов.
Update - эта функция запускается каждый раз когда происходит отрисовка на холсте. На самом деле каждый фрейм (или кадр) игры отрисовывается каждые n миллисекунд, так что наш глаз не замечает моргание на экране, потому что частота смены кадров довольно высокая, около 50-60 кадров в секунду, всё зависит от производительности видеокарты Вашего компьютера. В этой функции как правило располагают движение персонажей и вообще динамических объектов в игре.
P.S. На данный момент, это пожалуй всё, что я хотел написать в первой части нашего курса по созданию игр на Phaser 3. В следующей статье мы как-бы откатимся назад и рассмотрим как настроить среду разработки, какие инструменты для этого нужны, как установить сам Phaser, каким образом его импортировать в код программы и так далее. И уже приступим непосредственно к практике, иногда отвлекаясь на необходимые теоретические отступления (как же без них).