Server in USA

MightyEditor gets more and more users every day. Part of them comes from US and that is far away from our server here in Europe. We wanted to please gamedevs across the ocean and set up server there.

You can get to US server with this link – http://us.mightyeditor.mightyfingers.com. Hopefully, it will resolve many problems due to slow connection to the editor. Mightyeditor will detect clients ipgeo location and – if the user comes from North America – it will redirect to the US server.

You can force to use the EU server with the url: http://mightyeditor.mightyfingers.com/#no-redirect
or USA server with the url: http:// us.mightyeditor.mightyfingers.com/

Projects are not shared between servers automatically (the reason is very simple – to save the disk space on the servers), but you can still move projects manually from US to EU and back by clicking Project -> clone (eu / us).

Some minor bugfixes and improvements:

  • Tool-tips for tools and the upload notification box added
  • Missing minified files (e.g. jshint) added to improve the loading speed
  • Physics debug highlight fixed (if camera has been zoomed)
  • Regression bug with Google fonts fixed
  • Export option fixed – in some cases it failed to export project completely
  • Object texture change fixed – sometimes the wrong object got affected

Video tutorial “Digger”

This video tutorial shows you how to create a mini-game in the cloud using MightyEditor tool within 30 minutes. First part of tutorial covers graphical part of the game: loading assets, creating objects, grouping them. Second part is dedicated to add some code and functionality. There are covered such game development aspects as: game states, sprite animations, input controls, game loop, physics, collision detection, overlapping.

Text version of the tutorial can be found in article Tutorial “Digger”.

Update and usability improvements


Usability improvements:

  • Added scale, rotate and move anchor gizmos
  • Hold down shift key to maintain aspect ratio while re-sizing an object
  • Hold down ctrl key to increase object’s size by 10% while re-sizing an object or to change an angle by 15 degrees while rotating an object
  • Now you can drag an image or a file right into the folder
  • Added viewport width/height – now you can see bounds right on the map editor

A bit older updates:


Source editor
Source editor comes with:

  • Basic autocomplete – for common javascript keywords and Phaser static members (e.g. constants)
  • jshint – so errors and typos can be cought earlier
  • Basic game template


Physics
Physics is enabled by clicking on object and selecting “physics” tab from right panel. See red mark in image. You can see overview of physics objects and their bodies by selecting physics icon from left toolbar.

User data
Now you can add key/value pairs to the Asset or Object. Sprites will inherit user data from asset – it is useful if you want to create multiple objects from a single sprite in other words – use the asset as a template for multiple sprites. You can access the user data from game in the following way:

// create predefined sprite
var mySprite = mt.create("mySprite");
// get editor data from sprite
var data = mySprite.getData();
// get userData
var myData = data.userData;

Just remember that the editor data and user data are shared between sprites. e.g.

// create sprite
var mySprite1 = mt.create("mySprite");
// create same sprite again
var mySprite2 = mt.create("mySprite");
mySprite1.getData() == mySprite2.getData() // true

Tutorial ‘Digger’

In this article I will give you basic introduction to the MightyEditor and development process that surrounds it. Tutorial will show how to actually prototype a mini-game within an hour.

Requirements

Newest Google Chrome browser. You can try other browsers, but we don’t test them yet.

What is MightyEditor?

MightyEditor is open-source cloud based solution for creating and hosting HTML5 games. It is compatible with Phaser game development framework, but you can also use it with other tools. Main features of the editor are: asset management, map editing, code editor, data export.

How does MightyEditor work?

Design process of using editor works by following steps:

  1. Create a project
  2. Upload assets
  3. Drag and drop assets to the map
  4. Group assets in layers e.g. background, blocks…
  5. Add collisions and functionality in code editor
  6. Open game and export data

Why should I use MightyEditor?

Having a browser based tool with all of the basic functionality of map and code editor allows you to focus on fast prototyping of games. Open a link in browser and you are good to go. There is no hassle with installing and configuring various software solutions thus saving your precious time.

Cooperation with designer, another team member or a client has been made as easy as sharing link to the project. You can really work as a team, assign an illustrator to dealing with assets while game designer creates different levels in map editor and developer adds functionality with JavaScript code.

MightyEditor does not require your project to depend on it. All assets and code can be exported at any time. Whats even better – the editor is open-source and data can be moved to your local machine with local version of editor. The source code can be found on github  https://github.com/TheMightyFingers/mightyeditor.

Idea of mini-game

In this tutorial we will create a simple mini-game called Digger. The game is about a little miner who digs dirt block for gold and sells various minerals at the store. Arrow keys will be used for navigation and a simple physics and collision will be added to miner object.

Creating a project

Open the link http://mightyeditor.mightyfingers.com. Enter project title – in this case it will be Digger.

On the bottom right panel enter game dimensions: worldWidth, worldHeight 640 x 640. For sake of simplicity we will set view-port sizes the same 640 x 640.

 Upload game assets

In the following part of tutorial we will use assets that you can download here. On the top right panel from select list use upload file option and add files. Alternatively you can drag and drop files on to the panel and the assets will upload automatically.

Create a map

Click stamp icon on the left tool panel and then select background_sky.png in assets panel and then click on map thus creating background (hold Ctrl button for snapping to grid). You can change position of background by selecting arrow from the left tool panel. For more accurate positioning change x, y position in the settings panel.

Then repeat this step with following assets: background_city.png, background_hill1.png, background_hill2.png, background_grass.png. At the end everything should look like it’s shown in the following image

Create group

Let’s create group for newly created background objects. On right panel Objects section from select list choose Add Group. Rename group to bg and drag objects to this group. To drag multiple objects hold Shift key.

Add rest of graphics

Let’s create 5 rows of blocks under background. There are four different types of them: rock, ground, grass, gold. Gold blocks are collectible and you can’t dig rocks. Objects have to be added in blocks group.

Finally we need to add character and shop objects. As for the character asset – the image contains multiple frames. We need to define frame width and height in bottom right panel Settings panel. The size is 90 x 90. Separated frames can be viewed at bottom assetPreview panel. Also edit anchorX and anchorY. Set them both to 0.5

You can also define your own variables for object. Open userData tab in the same panel and add gold parameter with 0 value;

Select text icon on left tools panel and put a text object on top right corner of map. Write “0” as text will represent points. Rename text object in Objects panel on the right side.

Now we are ready to add objects and finish working with map editing. Character and shop objects are added like in image below

We have finished graphical part of tutorial. Next we’ll go in to coding and adding functionality like character controls, collisions, etc.

Source editor

Switch to source editor on top left side.

On the left side menu with game files are displayed. You will have to code mostly in state/play.js file. You can find key shortcodes for the editor here.

Game states

For coding we are going to use Phaser development framework. The states in Phaser are a separate parts of the game logic. By default editor gives you a template with four states boot, load, menu, play. For each state there are some predefined methods: preload, create, update, render. For demo purposes you should know that create method is called right after all assets are loaded and update method is called by game loop 60 times a second. You can learn more in documentation.

By default template calls load state. We need to redirect to play state. For this edit menu.js file under create method.

window.Digger.state.load = {
    preload: function(){
        ...
    },

    create: function() {
        this.game.state.start("play");
    }
}

Open game

First open game from top panel Open game button. At the moment there is only black screen. To display just made objects we have to initialize them in play.js file create method.

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");
}

Initializing is done with mt.create function. “bg” and “blocks” represent group names in object panel on the right side. “shop” and “character” represent sprite names in the same panel and finally “points” represent text. As you see all objects group, sprite and text are initialized with the same method.

Open the game now and initialized objects will be visible on the screen.

Adding physics

By default physics are disabled in Phaser for better performance reasons. We will enable the lightest and fastest physics from all available – Arcade physics. Open physics tab in bottom right corner. Change parameter enable to 1 and rest of parameters will appear below. Set character body size width: 60 and height 60. Enable gravity and set y to 1000. At last set collideWorldBounds parameter to 1.

Opening game you will see character falling down to the bottom of the screen.

Character controls

Initialize cursor keys in create method.

this.cursors = this.game.input.keyboard.createCursorKeys();

This  function give us an object with the four arrow keys to play with: up, down, left and right. In update method we will track when left/right/up arrow key is pressed and give a velocity to character or stop it keys are not inactive.

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;
    }
}

Open game and try arrow keys to control character.

Collision between character and blocks

Enable physics for blocks and set them immovable in the Map editor bottom right physics panel.

Next add collision detection in update method. First two arguments declare that we will check collision between sprite object and group of object. Third argument is a 2 argument function which is called on collision.

this.game.physics.arcade.collide(this.character, this.blocks, function(character, block) {
    console.log('Collision between', character, block);
}, null, this);

Opening game you will see character won’t fall to the end of screen, but will land on top of the blocks.

Character animations

First we need to define frames in spritesheet for different types of animations. Add these lines in create method.

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');

Last line of code starts play default animation stand.

For rest of animations we have to change update method and add play specific animation for each key press. Note that we have the same animation for left and right run. In order to flip horizontally sprite we are using 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');
}

Destroying blocks

In order to dig blocks we need to add functionality to our collide function:

this.game.physics.arcade.collide(this.character, this.blocks, function(character, block) {
    if (this.cursors.left.isDown) {
        if (block.body.touching.right) {
            this.destroyBlock(block);
        }
    }
    else if (this.cursors.right.isDown) {
        if (block.body.touching.left) {
            this.destroyBlock(block);
        }
    }
    else if (this.cursors.down.isDown) {
        if (block.body.touching.up) {
            this.destroyBlock(block);
        }
    }
}, null, this);

Various blocks need to be handled differently. Grass and ground blocks are simply destroyed, rocks are indestructible and we can collect gold and save it in character gold parameter. Add destroyBlock method under play state.

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;
    }
},

Overlapping and selling gold

In the next step we need to sell collected gold at the shop. At first you need to go back to map editor and set physics for shop object similar how it was done with character. Set parameters enable: 1, gravity->allow: 0, immovable: 1. After that go to source editor and change update method with following lines:

this.game.physics.arcade.overlap(this.character, this.shop,
    function(character, shop) {
        if (character.getData().userData.gold > 0) {
            var newPoints = parseInt(this.points._text) + character.getData().userData.gold;
            this.points.setText(newPoints);
            character.getData().userData.gold = 0;
        }
    }, null, this
);

Refactoring and adding final animations

We will add digging animations as final step of this tutorial and re-factor update method to meet our needs of good looking game. Given previous samples the code below should be self explaining.

"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,
		  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');
				}					
			}

			else 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');
				}

			}

			else 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');
			}
		}
		
		this.game.physics.arcade.overlap(this.character, this.shop,
		 	function(character, shop){
				if(character.getData().userData.gold > 0){
					var newPoints = parseInt(this.points._text) + character.getData().userData.gold;
					this.points.setText(newPoints);
					character.getData().userData.gold = 0;
				}
			}, null, this
		);
	},
	
	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;
		}
	},
	
	stopDig: function(){
		this.dig = false;	
	}
};

Full game project is available here: http://mightyeditor.mightyfingers.com/#pde5-copy
Final game here: http://mightyeditor.mightyfingers.com/data/projects/pde5/phaser/index.html
iframe: