В этой статье я опишу основные возможности 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: