Now that we have the real runner graphics in place, it is time to add some scrolling to the game to really make it look like our guy is really running.<\/p>\n
First though, let’s clean up some of the graphics.<\/p>\n
The first thing is to is to replace the bird block with an animation.\u00a0 We will do this in the same way that we did for the runner, by using a sprite sheet with a .json file<\/p>\n
<\/p>\n
<\/p>\n
Bird Sprite Sheet<\/p>\n
Replace the line<\/p>\n
game.load.image(\"bird\", \"images\/bird.png\");<\/pre>\nWith<\/p>\n
game.load.atlasJSONHash('bird','images\/bird.png','images\/bird.json');<\/pre>\nThen we just need to add the animations to the bird. lines 3 and 4 below.<\/p>\n
\/\/add the bird sprite to the game\r\nthis.bird = game.add.sprite(game.width + 100, birdY, \"bird\");\r\nthis.bird.animations.add(\"fly\",this.makeArray(0,8),12,true);\r\nthis.bird.animations.play(\"fly\");<\/pre>\nIf we leave the bird graphics as they are, it will be too big for the screen, so we can set the bird’s width to 10 percent of the game’s width and then scale the bird’s height proportionately.<\/p>\n
this.bird.width=game.width*.1;\r\nthis.bird.scale.y=this.bird.scale.x;<\/pre>\nIf you run the code now you’ll see the bird is the right size, but facing the wrong direction. We can reverse it by flipping the scale.x property<\/p>\n
this.bird.scale.x=-this.bird.scale.x;<\/pre>\n<\/h2>\n
I also replaced some of the temporary graphics with real ones and added a background and simply stretched it to fit the game’s width and height.<\/p>\n
<\/h2>\n
\/\/in preload\r\ngame.load.image(\"background\",\"images\/background.png\");<\/pre>\n\/\/in the create function\r\n \/\/background\r\n this.background=game.add.sprite(0,0,\"background\");\r\n this.background.width=game.width;\r\n this.background.height=game.height;<\/pre>\n<\/h2>\n
Scroll The Ground<\/h2>\n
Currently, we are using the\u00a0graphic below and stretching it to fit the width.<\/p>\n
<\/p>\n
ground.png<\/p>\n
Let’s replace it with something more suitable for our game.<\/p>\n
<\/p>\n
grass.png<\/p>\n
Replace the line<\/p>\n
game.load.image(\"ground\", \"images\/ground.png\");<\/pre>\nwith<\/p>\n
game.load.image(\"grass\", \"images\/grass.png\");<\/pre>\nNow, of course, if we are to take that block and stretch it, the ground would look distorted.\u00a0 By one of the very nice features of Phaser is the\u00a0tileSprite.<\/p>\n
It is similar in nature to a normal sprite, but as the name implies, it tiles, or repeat the image.<\/p>\n
A tilesprite is added to the game by using the following code<\/p>\n
game.add.tileSprite(x,y,width,height,imageKey);<\/pre>\nThe tile sprite will fill in the space provided by width and height settings with the image. In other words tile the space as if it were a floor.<\/p>\n
If we were to give the width and height as 250 x 250 Phaser would fill in our sprite like this<\/p>\n
game.add.tileSprite(0,0,250,250,\"grass\");<\/pre>\nWe would get this result.<\/p>\n
<\/p>\n
To get a horizontal line, we need only restrict the height in the tileSprite to equal that of the image, which in this case is 50 px.<\/p>\n
game.add.tileSprite(0,0,250,50,\"grass\");<\/pre>\n<\/p>\n
So to get a line of grass blocks to stretch across the bottom we just need to set the width to equal the game width and adjust the y position.<\/p>\n
We will replace the original ground sprite code with<\/p>\n
\/\/ this.ground = game.add.sprite(0, game.height * .9, \"ground\");\r\nthis.ground=game.add.tileSprite(0,game.height*.9,game.width,50,\"grass\");<\/pre>\nNow here is were the magic come in. A tileSprite has a function called autoScroll. We can set that to scroll by an x and y value and just leave Phaser to do its work. (I won’t take the time to explain all the hours I wasted getting this to work in Flash)<\/p>\n
this.ground.autoScroll(xScroll,yScroll);<\/pre>\n\/\/we only want to scroll by x, so leave y at 0\r\nthis.ground.autoScroll(-150,0);<\/pre>\nNow our ground moves along with our runner! I had to try several different values to get the running and the scrolling just right.<\/p>\n
I also used the same technique to add some mountains and replaced the clouds, and put autoScroll on all of them.<\/p>\n
<\/p>\n
Here is what my StateMain.js looks like now:<\/p>\n
var StateMain = {\r\n preload: function() {\r\n \/\/game.load.image(\"ground\", \"images\/ground.png\");\r\n \/\/ game.load.image(\"hero\", \"images\/hero.png\");\r\n game.load.image(\"bar\", \"images\/powerbar.png\");\r\n game.load.image(\"block\", \"images\/block.png\");\r\n game.load.image(\"grass\", \"images\/grass.png\");\r\n\r\n game.load.atlasJSONHash('bird','images\/bird.png','images\/bird.json');\r\n game.load.image(\"playAgain\", \"images\/playAgain.png\");\r\n game.load.image(\"clouds\", \"images\/clouds.png\");\r\n game.load.atlasJSONHash('hero', 'images\/explorer.png', 'images\/explorer.json');\r\n \/\/\r\n \/\/\r\n \/\/\r\n game.load.image(\"background\",\"images\/background.png\");\r\n game.load.image(\"mountains1\",\"images\/mountains1.png\");\r\n game.load.image(\"mountains2\",\"images\/mountains2.png\");\r\n\r\n },\r\n create: function() {\r\n this.clickLock = false;\r\n this.power = 0;\r\n \/\/turn the background sky blue\r\n game.stage.backgroundColor = \"#00ffff\";\r\n\r\n\r\n \/\/background\r\n \/\/\r\n this.background=game.add.sprite(0,0,\"background\");\r\n this.background.width=game.width;\r\n this.background.height=game.height;\r\n\r\n \/\/mountains\r\n \/\/\r\n this.mountain1=game.add.tileSprite(0,0,game.width,game.height\/2,\"mountains1\");\r\n this.mountain1.y=game.height-this.mountain1.height;\r\n\r\n this.mountain2=game.add.tileSprite(0,0,game.width,game.height\/3,\"mountains2\");\r\n this.mountain2.y=game.height-this.mountain2.height;\r\n\r\n this.mountain1.autoScroll(-50,0);\r\n this.mountain2.autoScroll(-150,0);\r\n\r\n \/\/add the ground\r\n \/\/ this.ground = game.add.sprite(0, game.height * .9, \"ground\");\r\n this.ground=game.add.tileSprite(0,game.height*.9,game.width,50,\"grass\");\r\n this.ground.autoScroll(-150,0);\r\n \/\/\r\n \/\/\r\n \/\/add the hero in \r\n this.hero = game.add.sprite(game.width * .2, this.ground.y, \"hero\");\r\n \/\/make animations\r\n this.hero.animations.add(\"die\", this.makeArray(0, 10), 12, false);\r\n this.hero.animations.add(\"jump\", this.makeArray(20, 30), 12, false);\r\n this.hero.animations.add(\"run\", this.makeArray(30, 40), 12, true);\r\n this.hero.animations.play(\"run\");\r\n this.hero.width = game.width \/ 12;\r\n this.hero.scale.y = this.hero.scale.x;\r\n this.hero.anchor.set(0.5, 1);\r\n \/\/add the power bar just above the head of the hero\r\n this.powerBar = game.add.sprite(this.hero.x + this.hero.width \/ 2, this.hero.y - this.hero.height \/ 2, \"bar\");\r\n this.powerBar.width = 0;\r\n \/\/add the clouds\r\n \r\n this.clouds=game.add.tileSprite(0,0,game.width*1.1,100,\"clouds\");\r\n this.clouds.autoScroll(-50,0);\r\n \/\/start the physics engine\r\n \/\/\r\n \/\/\r\n game.physics.startSystem(Phaser.Physics.ARCADE);\r\n \/\/enable the hero for physics\r\n \/\/\r\n \/\/\r\n game.physics.enable(this.hero, Phaser.Physics.ARCADE);\r\n game.physics.enable(this.ground, Phaser.Physics.ARCADE);\r\n \/\/game.physics.arcade.gravity.y = 100;\r\n \/\/\r\n \/\/\r\n this.hero.body.gravity.y = 200;\r\n this.hero.body.collideWorldBounds = true;\r\n \/\/this.hero.body.bounce.set(0, .2);\r\n this.ground.body.immovable = true;\r\n \/\/record the initial position\r\n this.startY = this.hero.y;\r\n \/\/set listeners\r\n game.input.onDown.add(this.mouseDown, this);\r\n this.blocks = game.add.group();\r\n this.makeBlocks();\r\n this.makeBird();\r\n },\r\n makeArray: function(start, end) {\r\n var myArray = [];\r\n for (var i = start; i < end; i++) {\r\n myArray.push(i);\r\n }\r\n return myArray;\r\n },\r\n mouseDown: function() {\r\n if (this.clickLock == true) {\r\n return;\r\n }\r\n if (this.hero.y != this.startY) {\r\n return;\r\n }\r\n game.input.onDown.remove(this.mouseDown, this);\r\n this.timer = game.time.events.loop(Phaser.Timer.SECOND \/ 1000, this.increasePower, this);\r\n game.input.onUp.add(this.mouseUp, this);\r\n },\r\n mouseUp: function() {\r\n game.input.onUp.remove(this.mouseUp, this);\r\n this.doJump();\r\n game.time.events.remove(this.timer);\r\n this.power = 0;\r\n this.powerBar.width = 0;\r\n game.input.onDown.add(this.mouseDown, this);\r\n this.hero.animations.play(\"jump\");\r\n },\r\n increasePower: function() {\r\n this.power++;\r\n this.powerBar.width = this.power;\r\n if (this.power > 50) {\r\n this.power = 50;\r\n }\r\n },\r\n doJump: function() {\r\n this.hero.body.velocity.y = -this.power * 12;\r\n },\r\n makeBlocks: function() {\r\n this.blocks.removeAll();\r\n var wallHeight = game.rnd.integerInRange(1, 4);\r\n for (var i = 0; i < wallHeight; i++) {\r\n var block = game.add.sprite(0, -i * 50, \"block\");\r\n this.blocks.add(block);\r\n }\r\n this.blocks.x = game.width - this.blocks.width\r\n this.blocks.y = this.ground.y - 50;\r\n \/\/\r\n \/\/Loop through each block\r\n \/\/and apply physics\r\n this.blocks.forEach(function(block) {\r\n \/\/enable physics\r\n game.physics.enable(block, Phaser.Physics.ARCADE);\r\n \/\/set the x velocity to -160\r\n block.body.velocity.x = -150;\r\n \/\/apply some gravity to the block\r\n \/\/not too much or the blocks will bounce\r\n \/\/against each other\r\n block.body.gravity.y = 4;\r\n \/\/set the bounce so the blocks\r\n \/\/will react to the runner\r\n block.body.bounce.set(1, 1);\r\n });\r\n },\r\n makeBird: function() {\r\n \/\/if the bird already exists \r\n \/\/destory it\r\n if (this.bird) {\r\n this.bird.destroy();\r\n }\r\n \/\/pick a number at the top of the screen\r\n \/\/between 10 percent and 40 percent of the height of the screen\r\n var birdY = game.rnd.integerInRange(game.height * .1, game.height * .4);\r\n \/\/add the bird sprite to the game\r\n this.bird = game.add.sprite(game.width + 100, birdY, \"bird\");\r\n this.bird.animations.add(\"fly\",this.makeArray(0,8),12,true);\r\n this.bird.animations.play(\"fly\");\r\n \/\/\r\n \/\/\r\n \/\/enable the sprite for physics\r\n game.physics.enable(this.bird, Phaser.Physics.ARCADE);\r\n \/\/set the x velocity at -200 which is a little faster than the blocks\r\n this.bird.body.velocity.x = -200;\r\n \/\/set the bounce for the bird\r\n this.bird.body.bounce.set(2, 2);\r\n\r\n this.bird.width=game.width*.1;\r\n this.bird.scale.y=this.bird.scale.x;\r\n this.bird.scale.x=-this.bird.scale.x;\r\n\r\n },\r\n onGround() {\r\n if (this.hero) {\r\n this.hero.animations.play(\"run\");\r\n }\r\n },\r\n update: function() {\r\n game.physics.arcade.collide(this.hero, this.ground, this.onGround, null, this);\r\n \/\/\r\n \/\/collide the hero with the blocks\r\n \/\/\r\n game.physics.arcade.collide(this.hero, this.blocks, this.delayOver, null, this);\r\n \/\/\r\n \/\/collide the blocks with the ground\r\n \/\/\r\n game.physics.arcade.collide(this.ground, this.blocks);\r\n \/\/\r\n \/\/when only specifying one group, all children in that\r\n \/\/group will collide with each other\r\n \/\/\r\n game.physics.arcade.collide(this.blocks);\r\n \/\/colide the hero with the bird\r\n \/\/\r\n game.physics.arcade.collide(this.hero, this.bird, this.delayOver, null, this);\r\n \/\/\r\n \/\/get the first child\r\n var fchild = this.blocks.getChildAt(0);\r\n \/\/if off the screen reset the blocks\r\n if (fchild.x < -game.width) {\r\n this.makeBlocks();\r\n }\r\n \/\/if the bird has flown off screen\r\n \/\/reset it\r\n if (this.bird.x < 0) {\r\n this.makeBird();\r\n }\r\n if (this.hero.y < this.hero.height) {\r\n this.hero.body.velocity.y = 200;\r\n this.delayOver();\r\n }\r\n },\r\n delayOver: function() {\r\n this.clickLock = true;\r\n if (this.hero) {\r\n this.hero.animations.play(\"die\");\r\n this.hero.body.velocity.y = 100;\r\n }\r\n game.time.events.add(Phaser.Timer.SECOND, this.gameOver, this);\r\n },\r\n gameOver: function() {\r\n game.state.start(\"StateOver\");\r\n }\r\n}<\/pre>\nYou can see the result here<\/a><\/p>\n\t