Real Graphics
Whenever we decide to develop a game in the office, I usually want to get started on it right away. Of course, the artists need time to develop the artwork. In the meantime, I use temporary graphics or what one of my artist friends calls “Dev Art”. I also sometimes use this on a game I’m developing which I’m not sure will be released, and don’t want to put a lot of time in before I’m sure.
The Runner
For the runner, I’m using one of my go-to character animations, a freebie courtesy of gameart2d.com.
I’ve used the TexturePackerGUI software to create the sprite sheet. You can read about how I use this to make sprite sheets in this TexturePackerGUI Tutorial.
I’ve also made a standalone character download. You can download those files if you wish to use them to follow along with this post.
Load the Sprite Sheet
After copying the explorer.png and explorer.json files to the images folder, we now need to assign the hero key to the sprite sheet instead of our temporary hero.png. I’ve commented out the old code and added one to load the sprite sheet.
preload: function() { game.load.image("ground", "images/ground.png"); // game.load.image("hero", "images/hero.png"); game.load.image("bar", "images/powerbar.png"); game.load.image("block", "images/block.png"); game.load.image("bird", "images/bird.png"); game.load.image("playAgain", "images/playAgain.png"); game.load.image("clouds", "images/clouds.png"); game.load.atlasJSONHash('hero', 'images/explorer.png', 'images/explorer.json'); },
Add The Animations
Next, we need to add the animations. I’ve left out the slide and idle animations as we won’t be needing them.
I’ve also added a support function called makeArray so we don’t have to type out [31,32,33,…
Place this just after the create function
makeArray:function(start,end) { var myArray=[]; for (var i = start; i < end; i++) { myArray.push(i); } return myArray; }
Add these lines inside your create function to define the animations
this.hero.animations.add("die",this.makeArray(0,10),12,false); this.hero.animations.add("jump",this.makeArray(20,30),12,false); this.hero.animations.add("run",this.makeArray(30,40),12,true);
Next, we set the hero’s animation to running.
this.hero.animations.play("run");
At the end of the mouseUp function, we can play the jump animation
this.hero.animations.play("jump");
To detect when the hero is back on the ground we need to add a function to the collision detection between the hero and the ground called onGround
game.physics.arcade.collide(this.hero, this.ground,this.onGround,null,this);
If the onGround function is called, it sets the hero’s animation back to running. For some reason, this was being called even before the hero sprite was being created, so I’ve put a quick if-then to check that the hero already exists.
onGround() { if (this.hero) { this.hero.animations.play("run"); } }
In the delayOver function we will play the die animation for when the hero gets hit
if (this.hero) { this.hero.animations.play("die"); this.hero.body.velocity.y = 100; }
Scaling the Runner
To make up for the changes in height I’ve put the hero on the ground by changing:
this.hero = game.add.sprite(game.width * .2, this.ground.y-25, "hero");
to
this.hero = game.add.sprite(game.width * .2, this.ground.y, "hero");
And to resize the hero I’ve made it 1/12 of the game’s with and scaled it proportionately and set the anchor so the foot is at the y position of the hero.
this.hero.width=game.width/12; this.hero.scale.y=this.hero.scale.x; this.hero.anchor.set(0.5,1);
This is the entire StateMain.js
var StateMain = { preload: function() { game.load.image("ground", "images/ground.png"); // game.load.image("hero", "images/hero.png"); game.load.image("bar", "images/powerbar.png"); game.load.image("block", "images/block.png"); game.load.image("bird", "images/bird.png"); game.load.image("playAgain", "images/playAgain.png"); game.load.image("clouds", "images/clouds.png"); game.load.atlasJSONHash('hero', 'images/explorer.png', 'images/explorer.json'); }, create: function() { this.clickLock = false; this.power = 0; //turn the background sky blue game.stage.backgroundColor = "#00ffff"; //add the ground this.ground = game.add.sprite(0, game.height * .9, "ground"); //add the hero in this.hero = game.add.sprite(game.width * .2, this.ground.y, "hero"); //make animations this.hero.animations.add("die", this.makeArray(0, 10), 12, false); this.hero.animations.add("jump", this.makeArray(20, 30), 12, false); this.hero.animations.add("run", this.makeArray(30, 40), 12, true); this.hero.animations.play("run"); this.hero.width = game.width / 12; this.hero.scale.y = this.hero.scale.x; this.hero.anchor.set(0.5, 1); //add the power bar just above the head of the hero this.powerBar = game.add.sprite(this.hero.x + this.hero.width / 2, this.hero.y - this.hero.height / 2, "bar"); this.powerBar.width = 0; //add the clouds this.clouds = game.add.sprite(0, 0, "clouds"); this.clouds.width = game.width; //start the physics engine game.physics.startSystem(Phaser.Physics.ARCADE); //enable the hero for physics game.physics.enable(this.hero, Phaser.Physics.ARCADE); game.physics.enable(this.ground, Phaser.Physics.ARCADE); //game.physics.arcade.gravity.y = 100; this.hero.body.gravity.y = 200; this.hero.body.collideWorldBounds = true; //this.hero.body.bounce.set(0, .2); this.ground.body.immovable = true; //record the initial position this.startY = this.hero.y; //set listeners game.input.onDown.add(this.mouseDown, this); this.blocks = game.add.group(); this.makeBlocks(); this.makeBird(); }, makeArray: function(start, end) { var myArray = []; for (var i = start; i < end; i++) { myArray.push(i); } return myArray; }, mouseDown: function() { if (this.clickLock == true) { return; } if (this.hero.y != this.startY) { return; } game.input.onDown.remove(this.mouseDown, this); this.timer = game.time.events.loop(Phaser.Timer.SECOND / 1000, this.increasePower, this); game.input.onUp.add(this.mouseUp, this); }, mouseUp: function() { game.input.onUp.remove(this.mouseUp, this); this.doJump(); game.time.events.remove(this.timer); this.power = 0; this.powerBar.width = 0; game.input.onDown.add(this.mouseDown, this); this.hero.animations.play("jump"); }, increasePower: function() { this.power++; this.powerBar.width = this.power; if (this.power > 50) { this.power = 50; } }, doJump: function() { this.hero.body.velocity.y = -this.power * 12; }, makeBlocks: function() { this.blocks.removeAll(); var wallHeight = game.rnd.integerInRange(1, 4); for (var i = 0; i < wallHeight; i++) { var block = game.add.sprite(0, -i * 50, "block"); this.blocks.add(block); } this.blocks.x = game.width - this.blocks.width this.blocks.y = this.ground.y - 50; // //Loop through each block //and apply physics this.blocks.forEach(function(block) { //enable physics game.physics.enable(block, Phaser.Physics.ARCADE); //set the x velocity to -160 block.body.velocity.x = -150; //apply some gravity to the block //not too much or the blocks will bounce //against each other block.body.gravity.y = 4; //set the bounce so the blocks //will react to the runner block.body.bounce.set(1, 1); }); }, makeBird: function() { //if the bird already exists //destory it if (this.bird) { this.bird.destroy(); } //pick a number at the top of the screen //between 10 percent and 40 percent of the height of the screen var birdY = game.rnd.integerInRange(game.height * .1, game.height * .4); //add the bird sprite to the game this.bird = game.add.sprite(game.width + 100, birdY, "bird"); //enable the sprite for physics game.physics.enable(this.bird, Phaser.Physics.ARCADE); //set the x velocity at -200 which is a little faster than the blocks this.bird.body.velocity.x = -200; //set the bounce for the bird this.bird.body.bounce.set(2, 2); }, onGround() { if (this.hero) { this.hero.animations.play("run"); } }, update: function() { game.physics.arcade.collide(this.hero, this.ground, this.onGround, null, this); // //collide the hero with the blocks // game.physics.arcade.collide(this.hero, this.blocks, this.delayOver, null, this); // //collide the blocks with the ground // game.physics.arcade.collide(this.ground, this.blocks); // //when only specifying one group, all children in that //group will collide with each other // game.physics.arcade.collide(this.blocks); //colide the hero with the bird // game.physics.arcade.collide(this.hero, this.bird, this.delayOver, null, this); // //get the first child var fchild = this.blocks.getChildAt(0); //if off the screen reset the blocks if (fchild.x < -game.width) { this.makeBlocks(); } //if the bird has flown off screen //reset it if (this.bird.x < 0) { this.makeBird(); } if (this.hero.y < this.hero.height) { this.hero.body.velocity.y = 200; this.delayOver(); } }, delayOver: function() { this.clickLock = true; if (this.hero) { this.hero.animations.play("die"); this.hero.body.velocity.y = 100; } game.time.events.add(Phaser.Timer.SECOND, this.gameOver, this); }, gameOver: function() { game.state.start("StateOver"); } }
Here is the result:
Hi, your tutorial has been quite useful for me, I’m learning how to code JS so I don’t know a lot. I’ve been trying to add coins for the player to collect them but all attempts have been unsuccessful. Any ideas how to do it?
It would be awesome if you could help me,
thanks!
I’ll try to put something together for you!
Awesome! Thanks a lot