HTML5 Game Tutorial: Making A Platformer (PART 1)

DOWNLOAD SOURCE HERE

I’ve been developing a totally new game for Tetrageddon. It’s going to be available for mobile (iOS, and Android), as well as the desktop.

This is an HTML5 game (for a change), with CreateJS, using FlashCC’s HTML5 Canvas document. Doing so will make things easier for me animation wise, as well as managing complex animated “cut scenes”, and other graphical aspects…

The game is codenamed “Face The Music” because it will essentially be about death and “giving up” — in a playful yet poetic pixel art style. :)
Best of all, “Face The Music” is a platformer game!

I will be documenting the development process, and releasing it as a series of tutorials that will walk you through creating this game. I will be doing this for all of Tetrageddon’s projects from now on, because I want to place even more emphasis on the “learning resource” aspect of Tetrageddon Games. This will provide excellent content for that.

Let’s begin!

*************

The Basic Platformer

DOWNLOAD SOURCE HERE

The finished product will behave like this. Sorry, it’s in the “programmer art” stage. :)


http://nathalielawhead.com/sourcefiles/Tutorial_HTML5_Platformer_Part1/FaceTheMusic_Tutorial1.html

LEFT/RIGHT = Move
DOWN = Duck
UP = Jump (hold up to jump higher)
Falling off = Death
Getting to right of screen = Win (it’s a short game at the moment)

*************

The Setup

For starters head down to https://github.com/madrobby/keymaster and grab a copy of keymaster.js. I’m using this because I figure I’ll want more complex keyboard functionality (maybe I’ll change this later, but for now I’m using this).

The code to import this will be as follows (first thing, first frame):

//import .js
var js_keys = document.createElement("script");
js_keys.src = "libs/keymaster.js";
js_keys.type = "text/javascript";
document.getElementsByTagName("head")[0].appendChild(js_keys);

There are some miscellaneous functions that will handle returning various calculations.
num_randrange, which returns a random number between a minimum and maximum specified value…

//Math
function num_randrange(num_max, num_min)
{
     return Math.ceil(Math.random()*(num_max-num_min)+num_min);
}

and gotoAndStopRandom, which sets a sprite to a random frame (I’ll be using this for the player sprite in later versions of the game).

//Timelines
function gotoAndStopRandom(clip){
	clip.gotoAndStop(Math.ceil(Math.random()*clip.timeline.duration));
};

Moving on to the actual meat of the game, we’ll set up the “world properties” (like gravity, friction, and stage width/height, and other necessary Arrays, variables…)

this.stop();

//Stage
_stage = this;
num_stageWidth = 800;
num_stageHeight = 480;

//"World" properties
friction = 0.6;
gravity = 0.8;

//Booleans
bool_keyDown = false;//key is held down
bool_jumpDown = false;//jump key is down

bool_lastpanel = true;//false;//is this the last panel, if so the game will win after you leave the screen

//Sprites
//Every sprite set is stored in that set's own array - 
//for collision and sprite specific properties/functionality
//the player
mc_frombie = null;
arr_players = [];//array of any hero sprites [0] = mc_frombie
//ground
arr_colidable = [];//array of any colidable platform

Most of this is fairly self explanatory.

bool_lastpanel is the current screen you’re on. I’m dividing the game up like it’s comic book panels that you are playing through. This being set to true indicates that once you leave the right of the screen, you “win”.

The last two arrays: arr_players and arr_colidable, are sprites that will check against each-others collision… I mean, I put everything in their respective arrays to handle the “object type”, if it’s in arr_colidable then it’s a platform and the player (arr_players) will stand on it.

*************

Managing Sprites

I’m wrapping up managing sprites into a set of functions. The first one (addSprite) is going to be responsible for adding sprites. It takes five properties. They are as follows.
libItem = name of library item. As you can see, I have any sprites that need to be manipulated through code added on the “first frame”. This way it registers — workaround for not having library linkages.
name = new name of the added sprite.
arr = the array it should be added to. Such as arr_players (for a player), arr_colidable (if it’s a collideable platform).
x = x position.
y = y position.
addSprite creates a clip via var clip = new libItem();
Adds it to _stage (our “root timeline” as saved in the variable from the above setup), names it, and adds it to the specified array, then places it at the desired x/y coordinates.

//create the sprite
//usage: addSprite(lib.Player, "mc_frombie", arr_players, 150, 150);
function addSprite(libItem, name, arr, x, y){
	//
	var clip = new libItem();//lib.LINKAGE
	_stage.addChild(clip);
	clip.name = name;
	arr.push(clip);
	//
	clip.x = x;
	clip.y = y;
};

Then there’s removeAllSprites(). This one gets called for game win, or game over (dying). To clear off everything on the stage. It simply loops through all the arrays, and removes their contents from _stage.

//remove anything created by game
//could use removeAllChildren, but I don't know what I might want to keep...
function removeAllSprites(){
	//get rid of the player
	for(var plr = 0; plr<arr_players.length; ++plr){
		_stage.removeChild(arr_players[plr]);
	};
	//get rid of anything colidable
	for(var col = 0; col<arr_colidable.length; ++col){
		_stage.removeChild(arr_colidable[col]);
	};
};

And finally we have a set of functions specific to managing the player’s states; player_die, player_win, and player_duck.
player_die and player_win are basically identical, but they set the _stage to a different “frame”.
player_die first calls evnt_removeAll(), which removes all event listeners (will explain later). Then removeAllSprites, then sends _stage to “gameover”. player_win does the same thing.

//Player
function player_die(){
	//remove all listeners
	evnt_removeAll();
	//remove all created children
	removeAllSprites();
	//
	console.log("gameover");
	//go to gameover
	_stage.gotoAndStop("gameover");
};

function player_win(){
	//remove all listeners
	evnt_removeAll();
	//remove all created children
	removeAllSprites();
	//
	console.log("gamewin");
	//go to gameover
	_stage.gotoAndStop("win");
};

player_duck handles the player’s “crouched” state. The player ducks when you press the DOWN key, or he will be ducked down (in an “ouch my head!” animated state) if a collision takes place where the player hits his head on the bottom of a platform… like, jumps up against something… as a cute detail.
To duck, the players ducking state is set to true, and then the player’s height reduced (I will explain player properties later). If a certain type "duck", or "ouch", then set the player to that state…
The finished function is as follows:

//ducking acts as an "ouch my head", and "be careful my head" animation
//like he's sensitive about his head... aside from reducing his height so he can crawl through small areas
function player_duck(type){
	mc_frombie.ducking = true;
	mc_frombie.height = 10;
	if(type=="duck"){
		mc_frombie.gotoAndStop("duck");
	}
	//hit his head on something, now sees stars or some type of injury
	if(type=="ouch"){
		mc_frombie.gotoAndStop("ouch");
	};
};

Finally, we’ll add the sprites to the stage.
This is a prototype of a game “level”… a very, very, small level. So we’ll create a few platforms (of different types), and the player.
Starting with the player.
The player is first added, and the currently controllable player saved to a variable (mc_frombie), so that any collision detection, and controlling will only apply to him — in the event that I want to add more controllable characters, I can just pull from the array and re-assign mc_frombie to the desired controllable sprite.
Then we have the player properties (values), which are set manually.
We set the .width and .height, this is important for collision detection (which uses width height to check). When the player crouches/ducks the .height is set to the crouch value. These values will change throughout the game, depending on the player’s state.
Then there are the last remaining properties that have to do with the physics, and states like jumping, if the player is on the ground, and ducking…
mc_frombie.speed = the speed of the player.
mc_frombie.jumpHeight = how high the player’s initial jump is. The player jumps higher if the up key is held down longer. If the up key is tapped then the player jumps at this default value.
mc_frombie.velX = the x velocity.
mc_frombie.velY = the y velocity.
mc_frombie.jumping = is the player jumping?
mc_frombie.grounded = is the player on the ground (on a platform)?
mc_frombie.ducking = is the player ducking (crouching)?

In conclusion, player setup looks like this:

//PLAYER
addSprite(lib.Player, "mc_frombie", arr_players, 150, 150);
mc_frombie = arr_players[0];
//player properties
//width and height is set manually
//this is the standing position
//crouching is adjusted in the down arrow event (reduce height, and go to another frame)
//this way I don't need fancy collision detection because I always know the w/h values...
mc_frombie.width = 40;//66
mc_frombie.height = 110;
//
mc_frombie.speed = 6;//9;
mc_frombie.jumpHeight = 1.5;//2
mc_frombie.velX = 0;
mc_frombie.velY = 0;
mc_frombie.jumping = false;
mc_frombie.grounded = false;
mc_frombie.ducking = false;
//
mc_frombie.stop();
gotoAndStopRandom(mc_frombie.mc_frombie);

Now we set up our platforms/floors. There are two types of floors. One is the classic version where if you hit the sides, and bottom, it will register as a collision and the player may not move there. The second is the one where you can jump through it, and land on it… Hope that makes sense. Envision the first being a box, and the second is like a cloud…
Each platform is added to arr_colidable, and variable assigned to it.
Each platform needs to have its own width/height set, and then its isPlatform boolean set. False means you can’t jump through it (collision registers on all sides), true means you can jump through it and land on it (collision only registers for top).
We have four platforms to start with.
The end result looks like this:

//GROUND
addSprite(lib.Colidable_Floor, "mc_floor1", arr_colidable, 50, 300);
mc_floor1 = arr_colidable[0];
//properties
mc_floor1.width = 800;
mc_floor1.height = 50;
mc_floor1.isPlatform = false;

//GROUND 2
addSprite(lib.Colidable_Floor, "mc_floor2", arr_colidable, 1000, 130);
mc_floor2 = arr_colidable[1];
//properties
mc_floor2.width = 800;
mc_floor2.height = 50;
mc_floor2.isPlatform = false;

//GROUND 3
addSprite(lib.Colidable_Platform, "mc_floor3", arr_colidable, 300, 50);
mc_floor3 = arr_colidable[2];
//properties
mc_floor3.width = 100;
mc_floor3.height = 50;
mc_floor3.isPlatform = false;

//Platform, you can walk through it, and jump up through it, but you can stand on it
addSprite(lib.Colidable_Platform, "mc_platform1", arr_colidable, 500, 200);
mc_platform1 = arr_colidable[3];
//properties
mc_platform1.width = 100;
mc_platform1.height = 50;
mc_platform1.isPlatform = true;//if it is a platform you can stand on it, but hitting the bottom and sides does nothing

*************

Collision Detection!

I wanted the simplest, most basic, and corner cutting approach possible, because I want to move on to making the game. I never really thought about the finer aspects of collision detection before, since there are so many libraries available. You can just use what’s already provided. It was interesting to wrap my head around it.
I found Somethinghitme’s explanation of collision detection to be an excellent example for getting my head thinking in those terms. I recommend checking it out, it’s basically what I’m doing here…

To begin we will calculate the amount of overlap between the two objects (object1 and object2), on both sides, top and bottom:

leftDist    = (object2.x - object2.width/2) - (object1.x + object1.width/2);
rightDist   = (object1.x - object1.width/2) - (object2.x + object2.width/2);
topDist     = (object2.y - object2.height/2) - (object1.y + object1.height/2);
bottomDist  = (object1.y - object1.height/2) - (object2.y + object2.height/2);

And then the half width and height of both objects. This will be used later for determining which side the collision occurred on.

var hWidths = (object1.width / 2) + (object2.width / 2);
var hHeights = (object1.height / 2) + (object2.height / 2);

Then we’ll move on to our if block. First to just get a collision (regardless of what side):

if(leftDist < 0 && rightDist < 0 && topDist < 0 && bottomDist < 0){

In this block we’ll fine tune our check, and return what side the collision took place on.
First we’ll set up the string direction_string. This will return "left", "right", "top", or "bottom".

Then we have our distance variables (as the comment suggests) between the two objects:

var xDist = object1.x - object2.x;
var yDist = object1.y - object2.y;

The last set of variables is where the magic happens! This oX and oY determine what side the collision occurred on. Simply put:

var oX = hWidths - Math.abs(xDist);
var oY = hHeights - Math.abs(yDist);

Moving on to our final set of if‘s… These check on what side/top/bottom the collision took place, and set direction_string to that side. Then object1‘s (the player) .y or .x is set to oY or oX (landed on it, or can’t go beyond it)… just force it to that value.
All that looks like this:

if (oX >= oY) {
	if (yDist > 0 && !object2.isPlatform) {//hit the top
		direction_string = "top";
		object1.y += oY;
	}
	if (yDist < 0){//standing on it
		direction_string = "bottom";
		object1.y -= oY;
	}
} else {
	if (xDist > 0 && !object2.isPlatform) {//left of
		direction_string = "left";
		object1.x += oX;
	} 
	if (xDist < 0 && !object2.isPlatform) {//right of
		direction_string = "right";
		object1.x -= oX;
	}
}

Finally return the value of direction_string. We worked hard to get this!

return direction_string;

The entire colisionCheck is as follows:

//colision detection for player and platform (ground)
function colisionCheck(object1, object2) {
	//amount of overlap
	leftDist    = (object2.x - object2.width/2) - (object1.x + object1.width/2);
	rightDist   = (object1.x - object1.width/2) - (object2.x + object2.width/2);
	topDist     = (object2.y - object2.height/2) - (object1.y + object1.height/2);
	bottomDist  = (object1.y - object1.height/2) - (object2.y + object2.height/2);
    //half widths and half heights of the objects
    var hWidths = (object1.width / 2) + (object2.width / 2);
    var hHeights = (object1.height / 2) + (object2.height / 2);
	//
	if(leftDist < 0 && rightDist < 0 && topDist < 0 && bottomDist < 0){
		//left, right, top, bottom
		var direction_string;
		//distance variables
		var xDist = object1.x - object2.x;
		var yDist = object1.y - object2.y;
		//which side does the colision occur (get the side it occurs on)
		var oX = hWidths - Math.abs(xDist);
		var oY = hHeights - Math.abs(yDist);
		//
		if (oX >= oY) {
			if (yDist > 0 && !object2.isPlatform) {//hit the top
				direction_string = "top";
				object1.y += oY;
			}
			if (yDist < 0){//standing on it
				direction_string = "bottom";
				object1.y -= oY;
			}
		} else {
			if (xDist > 0 && !object2.isPlatform) {//left of
				direction_string = "left";
				object1.x += oX;
			} 
			if (xDist < 0 && !object2.isPlatform) {//right of
				direction_string = "right";
				object1.x -= oX;
			}
		}
			//console.log("direction_string: "+direction_string);
			return direction_string;
	}
}

To use the above, we just need to loop through our arrays, and check if mc_frombie collided with any arr_colidable.
Basically it will look like this:

for (var i = 0; i < arr_colidable.length; i++) {
     dir = colisionCheck(mc_frombie, arr_colidable[i]);
	console.log(dir);
};

We will handle this in a Ticker, later.

*************

Physics & Player Movement

I created a couple of physics prototypes for this. They are both good examples of basic “physics”, and are great for getting your head into it.

Click to generate particles on mouse position.

http://nathalielawhead.com/sourcefiles/Super_Simple_Snippets/gravity_gibsJS.html
DOWNLOAD SOURCE HERE

Click FIRE! to generate particles.

http://nathalielawhead.com/sourcefiles/Projectiles/gravity_projectileJS.html
DOWNLOAD SOURCE HERE

In this game’s case, the approach is similar, except we are also checking for collision, and then we handle that appropriately (depending on platform type). Since we already have collision detection done, we just need things to fall on things now…

We’ll start with setting up the Ticker (to update positions), and the keyboard (to move the player).
Like I said, I’m using keymaster.js for controlling… as things later turned out, I needed to use KEY UP events (releasing UP after holding it down – to jump really high, and “un-crouching”), so I had to resort to old-school keyboard functionality. This is messy, and not efficient (I know!). I will be phasing out keymaster.js later (or fixing it so I use only keymaster.js), but (for now) we have two approaches…

We’ll create the events:

//Events
createjs.Ticker.addEventListener("tick", event_movement_ticker);
document.onkeydown = evnt_KEYDOWN;
document.onkeyup = event_KEYUP;

And also make sure to create evnt_removeAll(); (usage explained above). I realize that you could also use removeAllEventListeners([type]) to remove absolutely everything, but I’m not sure what events I will want to keep in the future, so I’m doing this for now…

//remove events
function evnt_removeAll(){
	createjs.Ticker.removeEventListener("tick", event_movement_ticker);
	document.onkeydown = null;
	document.onkeyup = null;
};

Now we’ll set up the keyCode‘s necessary for KEY UP:

KEY_UP = 38;
KEY_DOWN = 40;
KEY_S = 83;

There are two classic key down and key up functions. These take care of ducking, and jumping.
Key down manages jumping mostly (at the moment). This increases mc_frombie.jumpHeight. The longer up is pressed the higher the player will jump. This is going to be an important mechanic later on in the game. It also sets bool_keyDown to true to indicate that a key is being pressed.
Key down looks like this:

function evnt_KEYDOWN(event){
	//
	if(!event){ var event = window.event; }
	//get ready for jump height - the longer it's pressed the heigher he will jump
	if (key.isPressed("up") || key.isPressed("w")) {
		mc_frombie.jumpHeight += .5;
		bool_keyDown = true;
	};
};

Then there’s the key up event. It sets bool_keyDown to false, indicating that the key has been released.
In the case of the up key having been released (if the player isn’t already jumping), it sets bool_jumpDown to true. The jump will now be handled in the Ticker event.
Ducking is a little simpler. If the DOWN or S key are released, and mc_frombie is ducking, set ducking to false. The actual “un-ducking” will also be handled in the Ticker.
The finished KEY UP event is as follows:

function event_KEYUP(event){
	//
	if(!event){ var event = window.event; }
	//
	bool_keyDown = false;
	//now trigger the jump (only if not already jumping and the key is not down)
	//greater than default is how it tells if you triggered a jump)
	if ((!bool_keyDown && !mc_frombie.jumping) && 
		(event.keyCode == KEY_UP)) {
		bool_jumpDown = true;
	};
	//unduck - ducking is in ticker because it needs to happen imediately - there is a keydown delay in multiple key
	if ((event.keyCode == KEY_DOWN || event.keyCode == KEY_S) 
		&& (mc_frombie.ducking)) {
		mc_frombie.ducking = false;
	};
};

Moving on to the actual player physics, I’ll break down the basics of how it works…

Jumping is the first thing you’ll notice. As the if condition suggests, you may only jump if bool_jumpDown is true (this is set in KEY UP event), mc_frombie isn’t already jumping, and mc_frombie is on the ground.
If this is the case then jumping is set to true, grounded is false (he’s jumping now), and ducking is false (resets ducking if he was ducking), and then set the velY to move:

mc_frombie.velY = -mc_frombie.speed * mc_frombie.jumpHeight;

That’s the important part.
The last two bool_jumpDown and bool_keyDown being set to false basically resets things. Once player is back on the ground you can jump again.
The above looks like this:

if (bool_jumpDown && !mc_frombie.jumping && mc_frombie.grounded) {
	//
	mc_frombie.jumping = true;
	mc_frombie.grounded = false;
	mc_frombie.ducking = false;//reset ducking also if up is pressed
	//
	mc_frombie.velY = -mc_frombie.speed * mc_frombie.jumpHeight;
	//reset
	bool_jumpDown = false;
	bool_keyDown = false;
}

There’s another condition that follows which resets mc_frombie.jumpHeight to the default value.

if(!bool_jumpDown && mc_frombie.jumping && !mc_frombie.grounded){
	mc_frombie.jumpHeight = 1.5;
};

After jumping you’ll notice ducking. Ducking is simple. If DOWN or S, and you’re not jumping, and on the ground, player_duck("duck"); is called.

if ((key.isPressed("down") || key.isPressed("s")) && 
	(!mc_frombie.jumping && mc_frombie.grounded)) {
	player_duck("duck");
}

You may then unduck only if height is less than the default (so no conflict with other gotoAndStop labels takes place), and if mc_frombie.ducking is false. If that’s the case then the height is set back to normal, and player is set back to "walk".
Unduck looks like this:

if(!mc_frombie.ducking && mc_frombie.height<110){
	mc_frombie.height = 110;
	mc_frombie.gotoAndStop("walk");
};

Finally we have our left and right movements.
Left/right looks like this, and is fairly self explanatory:

//left/right movement
if ((key.isPressed("left") || key.isPressed("a"))) {
    if (mc_frombie.velX > -mc_frombie.speed) {
        mc_frombie.velX-=mc_frombie.speed;
    }
}
if ((key.isPressed("right") || key.isPressed("d"))) {
	if (mc_frombie.velX < mc_frombie.speed) {
        mc_frombie.velX+=mc_frombie.speed;
    }
}

After we’re done with all the above, we need to set mc_frombie’s velX and velY (friction, and gravity), and set mc_frombie.grounded to false. Basically calculate all the above to apply later… which looks like this:

//friction to velX and and gravity to velY (horizontal and vertical values)
mc_frombie.velX *= friction;
mc_frombie.velY += gravity;
//
mc_frombie.grounded = false;

Then we have the fun part! Checking collision, and acting appropriately.
We loop through arr_colidable, and set variable dir to the returned value of colisionCheck.
Then there’s our condition for each direction (left, right, top, or bottom).
Left and right are basically the same thing. They stop velX, and set mc_frombie.jumping to false.
Bottom means you’re standing on the ground. So mc_frombie.grounded is set to true and mc_frombie.jumping is set to false (you’re not in the air anymore).
Top means that he hit his head on the bottom of a platform. velY is set back (push him down), and then the "ouch" state is set — he’s ducking, and I’ll have a cute animation there.
The entire block looks like this:

for (var i = 0; i < arr_colidable.length; i++) {
    //
    dir = colisionCheck(mc_frombie, arr_colidable[i]);
	//
    if (dir === "left" || dir === "right") {
        mc_frombie.velX = 0;
        mc_frombie.jumping = false;
    } else if (dir === "bottom") {
        mc_frombie.grounded = true;
        mc_frombie.jumping = false;
    } else if (dir === "top") {
        mc_frombie.velY *= -1;
		//if you hit the top then he protects his head (you scared him)
		//jumping resets this
		player_duck("ouch");
		//
    }
}

After that we manage velY if he’s on the ground (not jumping anymore, above collision with ground took place).
Just reset/set velY to 0 (default state):

if(mc_frombie.grounded){
     mc_frombie.velY = 0;
}

FINALLY, we need to set the player’s x and y to the calculated values.
Simply put:

mc_frombie.x += mc_frombie.velX;
mc_frombie.y += mc_frombie.velY;

The last bit manages the player falling off the screen and dying, or walking off the right and winning:

//Player death
//fell off stage
if(mc_frombie.y > (num_stageHeight + mc_frombie.height)){
	player_die();
};
//Player went to next screen
if(mc_frombie.x> (num_stageWidth + mc_frombie.width)){
	if(bool_lastpanel){
		player_win();
	}else{
		console.log("next panel");
	};
};

That’s it! The entire thing looks like this:

function event_movement_ticker(event) {
	//key presses
	//jump
	//make the jump - set to values - reset after
	if (bool_jumpDown && !mc_frombie.jumping && mc_frombie.grounded) {
		//
		mc_frombie.jumping = true;
		mc_frombie.grounded = false;
		mc_frombie.ducking = false;//reset ducking also if up is pressed
		//
		mc_frombie.velY = -mc_frombie.speed * mc_frombie.jumpHeight;
		//reset
		bool_jumpDown = false;
		bool_keyDown = false;
	}
	//reset the jump height while in the air
	//if done above sometimes it doesn't reset
	if(!bool_jumpDown && mc_frombie.jumping && !mc_frombie.grounded){
		mc_frombie.jumpHeight = 1.5;
	};
	//start ducking - ducking is in the ticker because it needs to trigger RIGHT AWAY
	if ((key.isPressed("down") || key.isPressed("s")) && 
		(!mc_frombie.jumping && mc_frombie.grounded)) {
		//duck
		player_duck("duck");
	}
	//unduck - only if also height is less than default so that no conflict with other gotoAndStop labels...
	if(!mc_frombie.ducking && mc_frombie.height<110){
		mc_frombie.height = 110;
		mc_frombie.gotoAndStop("walk");
	};
	//left/right movement
	if ((key.isPressed("left") || key.isPressed("a"))) {
        if (mc_frombie.velX > -mc_frombie.speed) {
            mc_frombie.velX-=mc_frombie.speed;
        }
	}
	//stop player movement
	if ((key.isPressed("right") || key.isPressed("d"))) {
		//
		if (mc_frombie.velX < mc_frombie.speed) {
            mc_frombie.velX+=mc_frombie.speed;
        }
		//
	}
	//friction to velX and and gravity to velY (horizontal and vertical values)
	mc_frombie.velX *= friction;
    mc_frombie.velY += gravity;
	//
	mc_frombie.grounded = false;
	//
	//HIT-----
    for (var i = 0; i < arr_colidable.length; i++) {
        //
        dir = colisionCheck(mc_frombie, arr_colidable[i]);
		//
        if (dir === "left" || dir === "right") {
            mc_frombie.velX = 0;
            mc_frombie.jumping = false;
        } else if (dir === "bottom") {
            mc_frombie.grounded = true;
            mc_frombie.jumping = false;
        } else if (dir === "top") {
            mc_frombie.velY *= -1;
			//if you hit the top then he protects his head (you scared him)
			//jumping resets this
			player_duck("ouch");
			//
        }
    }
	//END HIT-----
	//if on the ground then set velY to default state
	if(mc_frombie.grounded){
         mc_frombie.velY = 0;
    }
	//now set the actual x and y to calculated values
	mc_frombie.x += mc_frombie.velX;
    mc_frombie.y += mc_frombie.velY;
	//
	//Player death
	//fell off stage
	if(mc_frombie.y > (num_stageHeight + mc_frombie.height)){
		player_die();
	};
	//Player went to next screen
	if(mc_frombie.x> (num_stageWidth + mc_frombie.width)){
		if(bool_lastpanel){
			player_win();
		}else{
			console.log("next panel");
		};
	};
}

Finished! Now we have the groundwork for a simple platformer game.
This is stage one. Obviously it’s a work in progress, and I still need to optimize parts, but… small steps! :)
I’m now moving on to incorporating a few levels, and some of the features I want in the game… as well as WAY better artwork. :)

DOWNLOAD SOURCE HERE

PLAY IT HERE

Or check out my other tutorials:
* Tutorial: Building A Game In Edge Animate (Offender)
* Tutorial: Building A Game With Flash HTML5 Canvas & CreateJS (Haxatron 2000)

This monster belongs in Games, Web/Game Dev: Tutorials & Sourcecode. Bookmark the permalink. Follow any flames or other attacks to it with the RSS feed for this abominable creature. Voice your rage or leave a /b/roback: /b/roback URL.

2 /B/romments

  1. sam
    Raged December 21, 2015 at 1:48 pm | Permalink

    Hi, thanks for your website, some good stuff on here. I am playing with flash html5 canvas and have an interactive graphc where I am trying to open a youtube window in a new window, on top of my graphic. Any tips would be great. Im new to javascript. thanks!

  2. Raged January 9, 2018 at 5:35 pm | Permalink

    Unassuming Question:
    Ticker timer – Choppy animations seem abound with createJS goodness, tried using delta time, mathrounding movement, etc etc unless i smash the ticker refresh to some crazy amount there is always joddery animation….

    SO…

    Have you come across this, and how did you smash it ?

    Regards…..

Post a /B/romment

Chill, /b/ro. Your email is probably not, but most likely impossibly going to be not shared. Required fields are marked, yo... *

*
*

Use these /b/ro HTML haxxx: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

Beerme: