В этой статье я опишу основные возможности MightyEditor и процесс разработки игр. Учебник покажет как сделать HTML5 мини-игру в течение часа.
Требования
Новейший браузер Google Chrome. Можно попробовать и другие браузеры, но мы их еще не тестировали.
Что такое MightyEditor?
MightyEditor это онлайн редактор для создания и хостинга HTML5 игры. Он с открытым исходным кодом и совместим с популярным игровым движком Phaser, но вы также можете использовать его и с другими движками. Основные особенности редактора являются: ассет менеджмент, редактирование карт, редактор кода и экспорт данных.
Как работает MightyEditor?
Процесс использования редактора работает следующим образом:
- Создание проекта
- Загрузка текстур
- Создание карты
- Групирование текстуры в слоях например фон, блоки…
- Добавить коллизий и функциональность в редакторе кода
- Открыть игру и экспорт данных
Почему я должен использовать редактор игр?
Имея инструмент в онлайн с функцией редактора карт и кода, позволяет сделать прототип игр быстрее. Открой ссылку в браузере, и ты готов работать. Нет лишних проблем с установкой и настройкой различных программных решений, что существенно экономит Твое драгоценное время.
Сотрудничество с дизайнером, другим разработчиком или клиентом это также просто, как отправить ссылку на проект. Вы также можете работать в команде: назначить иллюстратора который добавит графику, в то время как гейм-дизайнер создает различные уровни в редакторе карт и разработчик добавляет функциональность с JavaScript кодом.
MightyEditor не требует чтобы продукт зависел от него. Все текстуры и код можно экспортировать в любой момент. Что еще лучше – у редактора есть открытый исходный код и данные могут быть перемещены на локальный компьютер с локальной версией редактора. Исходный код можно найти на GitHub https://github.com/TheMightyFingers/mightyeditor.
Идея мини-игры
В этом туториале мы создадим простою мини-игру под названием Digger. Игра о маленьком шахтере, который роет землю, ищет золото и продает его в магазине. Клавиши курсора будут использоваться для навигации и простоя физика и коллизия будут добавлены у объекта шахтера.
Создание проекта
Открой ссылку http://mightyeditor.mightyfingers.com. Введи название проекта –Digger.
На нижней правой панели введи размеры игры: worldWidth, worldHeight 640 x 640. Для простоты мы установим view-port те же размеры 640 x 640.
Загрузка текстур
В следующей части туториала мы будем использовать текстуры, которые можно скачать здесь. В правом верхнем углу панели в списке опций выбери upload file и добавь файлы. В качестве альтернативы можно перетаскивать файлы на панель и текстуры загрузятся автоматически.
Создание карты
Нажми икону в виде штампа на левой панели, затем выбери из панели текстур background_sky.png, затем нажми на карту, таким образом создавая фон (удерживая кнопку Ctrl для привязки к сетке). Для перемещения фона, выбери стрелку в левой панели инструментов. Для более точного положения можно изменить X, Y позицию в панели настроек.
Затем повтори этот шаг со следующими текстурами: background_city.png, background_hill1.png, background_hill2.png, background_grass.png. В конце все должно выглядеть как показано на следующем изображение
Создание группы
А теперь создадим группу для созданных фоновых объектов. На правой панели Objects в списке выбора нажми Add Group. Переименуй группу на bg и перетащи объекты в эту группу. Чтобы выбрать несколько объектов удерживай клавишу Shift.
Добавление остальных текстур
Создадим 5 рядов блоков под группы фона. Есть четыре различных типа блоков: камень, земля, трава, золото (rock, ground, grass, gold). Где Ты должен собирать золотые блоки, но не можешь разбить камни. Объекты должны быть добавлены в группу blocks.
Наконец, мы должны добавить объекты герой и магазин. Что касается текстуры героя – изображение содержит несколько кадров. Нам необходимо определить ширину кадра и высоту в нижней правой панели Settings. Размер 90 x 90. Отдельные кадры можно посмотреть на нижней assetPreview панели. Также нужно отредактировать anchorX и anchorY. Установите их на 0.5
Также можно установить свои собственные переменные для объекта. Открой закладку userData на той же панели и добавь параметр золото со значением 0.
Выбери икону текст на панели слева и напиши “0” в правом верхнем углу карты, таким образом будут отображаться очки. Переименуй текстовый объект в панели Objects на points.
Теперь мы готовы добавить объекты и завершить редактирование карты. Объекты героя и магазина добавляются следующем образом
Мы закончили графическую часть проекта. Далее мы начнем программирование и добавления функциональности: управление героем, физику, коллизии и т.д.
Редактор кода
Перейдем к редактору кода на верхней левой стороне.
На левой стороне отображается список с игровыми файлами. В основном программировать нужно будет в файле state/play.js . Вы можете найти ключевые шорткоды для редактора здесь.
Стейты игры
Для программирования мы собираемся использовать популярный игровой движок Phaser. По умолчанию, редактор дает шаблон с четырьмя стейтами boot, load, menu, play. Для каждого стейта есть некоторые предопределенные методы: preload, create, update, render. Для этого проекта Ты должен знать два метода: метод create вызывается сразу после того, когда все текстуры загрузились и метод update вызывается в игровом цикле 60 раз в секунду. Больше можно узнать в документации.
По умолчанию шаблон вызывает menu стейт. Для простоты мы не будем создавать меню на этот раз и начнем с геймплей. Для этого нужно вызвать play стейт в menu.js файле под метод create .
window.Digger.state.menu = { create: function() { this.game.state.start("play"); } }
Открой игру
Нажми на кнопку Open game на верхней панели, появиться черный экран. Для отображения только что созданных объектов мы должны инициализировать их в play.js под create метод.
create: function() { this.bg = mt.create("bg"); this.blocks = mt.create("blocks"); this.shop = mt.create("shop"); this.character = mt.create("character"); this.points = mt.create("points"); }
Инициализация делается с mt.create функции. “bg” и “blocks” представляют имена групп в панели объектов в правой стороне. “shop” и “character” представляют имена спрайтов, в той же панели и, наконец, “points” представляют текст. Как Ты видишь все объекты (группы, спрайты и текст) инициализируются тем же методом.
Откройте игру сейчас и объекты будут видны на экране.
Добавление физики
По умолчанию физика в Phaser отключена, для лучшей производительности. Мы включим самую легкую и быструю физику из всех доступных – Arcade physics. Откройте вкладку физики в нижнем правом углу. Измените параметр enable на 1 и остальные параметры появятся ниже. Установите размер тела героя width: 60 и height 60. Включите гравитацию и установите y на 1000. И в конце установите collideWorldBounds параметр на 1.
При открытие игры Ты увидеш героя, падающего в нижнюю часть экрана.
Управления героем
Инициализируи клавиши управления в методе create.
this.cursors = this.game.input.keyboard.createCursorKeys();
Эта функция дает нам объект с четырьмя клавишами со стрелками: up, down, left and right. В методе update отследим когда будет нажата клавиша left/right/up и дадим скорость дла героя или остановим его если клавиши не активны.
update: function() { if (this.cursors.left.isDown) { this.character.body.velocity.x = -200; } else if (this.cursors.right.isDown) { this.character.body.velocity.x = 200; } else { this.character.body.velocity.x = 0; } if (this.cursors.up.isDown) { this.character.body.velocity.y = -300; } }
Открой игру и нажми клавиши со стрелками для управления героя.
Коллизии между героям и блоками
Включи физику для блоков и установи их недвижимым в Map editor в правом нижнем панели физики.
Добавим коллизии в методе update. Первые два аргумента означает, что мы будем проверять коллизии объекта спрайта и группы. Третий аргумент является функцией, которая вызывается на столкновений.
this.game.physics.arcade.collide(this.character, this.blocks.self, function(character, block) { console.log('Collision between', character, block); }, null, this);
Открывая игру, герой не будет падать до конца экрана, но приземлится сверху блоков.
Анимации героя
Мы должны определить кадри в спрайт листе для различных типов анимации. Добавьте эти строки в метод create.
this.character.animations.add('stand', [0, 1, 2, 3], 10, true); this.character.animations.add('fly', [4, 5, 6, 7], 10, true); this.character.animations.add('run', [8, 9, 10], 10, true); this.character.animations.add('fall', [12, 13, 14, 15], 10, true); this.character.animations.add('dig', [16, 17, 18], 10, false); this.character.animations.add('dig_down', [20, 21, 22], 10, false); this.character.animations.play('stand');
Последняя строка кода начинает анимацию stand.
Для остальной части анимации мы должны изменить метод update и добавить анимацию для каждого нажатия клавиши. Обратите внимание, что мы имеем ту же анимацию run для левой и правой стрелки клавишы. Для того, чтобы переворачивать по горизонтали спрайт мы используем scale -1.
if (this.cursors.left.isDown) { this.character.body.velocity.x = -200; this.character.animations.play('run'); this.character.scale.x = -1; } else if (this.cursors.right.isDown) { this.character.body.velocity.x = 200; this.character.animations.play('run'); this.character.scale.x = 1; } else { this.character.body.velocity.x = 0; this.character.animations.play('stand'); } if (this.cursors.up.isDown) { this.character.body.velocity.y = -300; this.character.animations.play('fly'); }
Уничтожение блоков
Для того, чтобы копать блоки нужно добавить функциональность для нашей функции колизии:
this.game.physics.arcade.collide(this.character, this.blocks.self, function(character, block) { if (this.cursors.left.isDown) { if (block.body.touching.right) { this.destroyBlock(block); } } if (this.cursors.right.isDown) { if (block.body.touching.left) { this.destroyBlock(block); } } if (this.cursors.down.isDown) { if (block.body.touching.up) { this.destroyBlock(block); } } }, null, this);
Различные блоки должны быть обработаны по-разному. Блоки травы и земли просто уничтожается, каменьы нерушимы и мы можем собирать золото и сохранить его в параметре у героя. Добав метод destroyBlock под стейт play.
destroyBlock: function(block) { switch (block.key) { case '/rock.png': break; case '/grass.png': case '/ground.png': block.destroy(); break; case '/gold.png': this.character.getData().userData.gold++; block.destroy(); break; } },
Перекрытие и продажа золота
На следующем шаге мы должны продать собранную золото в магазине. В конце метода update добавьте следующие строки:
if (this.checkOverlap(this.character, this.shop)) { if (this.character.getData().userData.gold > 0) { var newPoints = parseInt(this.points._text) + this.character.getData().userData.gold; this.points.setText(newPoints); this.character.getData().userData.gold = 0; } }
И создаи новый метод под стейт play state который проверяет границы героя и магазина:
checkOverlap: function(spriteA, spriteB) { var boundsA = spriteA.getBounds(); var boundsB = spriteB.getBounds(); return Phaser.Rectangle.intersects(boundsA, boundsB); }
Рефакторинг и добавления окончательных анимации
Мы добавим анимации dig и сделаем рефактор в методе update для удовлетворения красивой игры. Учитывая предыдущие образцы, код ниже должны быть понятен.
"use strict"; window.Digger.state.play = { create: function(){ this.cursors = this.game.input.keyboard.createCursorKeys(); this.bg = mt.create("bg"); this.blocks = mt.create("blocks"); this.shop = mt.create("shop"); this.character = mt.create("character"); this.points = mt.create("points"); this.character.animations.add('stand', [0, 1, 2, 3], 10, true); this.character.animations.add('fly', [4, 5, 6, 7], 10, true); this.character.animations.add('run', [8, 9, 10], 10, true); this.character.animations.add('fall', [12, 13, 14, 15], 10, true); this.character.animations.add('dig', [16, 17, 18], 10, false); this.character.animations.add('dig_down', [20, 21, 22], 10, false); this.character.animations.play('stand'); }, update: function(){ var collideDown = false; this.game.physics.arcade.collide(this.character, this.blocks.self, function(character, block){ if(this.dig) return; if(this.cursors.left.isDown){ if(block.body.touching.right){ this.dig = this.character.animations.play('dig'); this.dig.onComplete.addOnce(function(){ this.destroyBlock(block); }, this); } else { this.character.animations.play('run'); } } if(this.cursors.right.isDown){ if(block.body.touching.left){ this.dig = this.character.animations.play('dig'); this.dig.onComplete.addOnce(function(){ this.destroyBlock(block); }, this); } else { this.character.animations.play('run'); } } if(this.cursors.down.isDown){ if(block.body.touching.up){ this.dig = this.character.animations.play('dig_down'); this.dig.onComplete.addOnce(function(){ this.destroyBlock(block); }, this); } else { this.character.animations.play('stand'); } } if(block.body.touching.up){ collideDown = true; } }, null, this); if(this.dig){ return; } if(this.cursors.left.isDown){ this.character.scale.x = -1; this.character.body.velocity.x = -200; } else if(this.cursors.right.isDown){ this.character.scale.x = 1; this.character.body.velocity.x = 200; } else { this.character.body.velocity.x = 0; } if(this.cursors.up.isDown){ this.character.body.velocity.y = -300; this.character.animations.play('fly'); } else { if(!collideDown){ this.character.animations.play('fall'); } else if(this.character.body.velocity.x === 0){ this.character.animations.play('stand'); } } if(this.checkOverlap(this.character, this.shop)){ if(this.character.getData().userData.gold > 0){ var newPoints = parseInt(this.points._text) + this.character.getData().userData.gold; this.points.setText(newPoints); this.character.getData().userData.gold = 0; } } }, destroyBlock: function(block){ this.dig = false; switch(block.key){ case '/rock.png': break; case '/grass.png': case '/ground.png': block.destroy(); break; case '/gold.png': this.character.getData().userData.gold++; block.destroy(); break; } }, checkOverlap: function (spriteA, spriteB) { var boundsA = spriteA.getBounds(); var boundsB = spriteB.getBounds(); return Phaser.Rectangle.intersects(boundsA, boundsB); }, stopDig: function(){ this.dig = false; } };
Полный проект игры доступен здесь: http://mightyeditor.mightyfingers.com/#pde5-copy
Финальная игра: http://mightyeditor.mightyfingers.com/data/projects/pde5/phaser/index.html
iframe: