Creating an Endless Runner Game in Phaser Part 4 Movement

Creating Movement

Although we will create the illusion of running, as you probably have guessed by now, we will actually be moving the blocks. The temptation is to just move the group as one in the update function.

update:function()
{
  this.blockGroup.x--;
}

But if we did that we couldn’t take advantage of the built in physics that Phaser has to offer. For the arcade physics collision detection to work the blocks inside the group need to be enabled for physics and they need to have velocity set.

So to do this I’ve modified the makeBlocks function by looping through the group and applying physics to each one. I’ve also increased the distance between blocks from 25 to 50, as the earlier value was a mistake, and adjusted the wallHeight variable from 1-6, to 1-4.

makeBlocks: function() {
        //remove all the blocks from the group
        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);
        });
    }

Now we need 3 things to happen

  • The blocks to not fall through the ground
  • The blocks not to fall through each other
  • The blocks to react when they hit the player

So to accomplish that we do the same as we did to make sure the player stayed on the ground. We set up a collision for each one. Place this in the update function.

//
        //collide the hero with the blocks
        //
        game.physics.arcade.collide(this.hero, this.blocks);
        //
        //colide 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);
Endless Runner Part 4 Result

Resetting the blocks

The last thing to do is to reset the blocks if the player successfully jumps the blocks. If we were moving the group we could just check the x position of the group, and check if that were less than zero. Since we are moving the blocks instead and the blocks’ x position is relative to the group, meaning they have an x position of 0 at the start and moves a negative rate as the game goes on. So for the blocks to be off the left of the screen they will have to be a negative value of the game.width (-game.width);

Instead of checking every block, since all blocks should be on the game x position unless they get hit, we can just check the first child of the group.

//get the first child
var fchild = this.blocks.getChildAt(0);
//if off the screen reset the blocks
if (fchild.x < -game.width) {
    this.makeBlocks();
}

Here is the complete code in StateMain.js so far

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");
    },
    create: function() {
        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 - 25, "hero");
        //add the power bar just above the head of the hero
        this.powerBar = game.add.sprite(this.hero.x + 25, this.hero.y - 25, "bar");
        this.powerBar.width = 0;
        //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();
    },
    mouseDown: function() {
        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);
    },
    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);
        });
    },
    update: function() {
        game.physics.arcade.collide(this.hero, this.ground);
        //
        //collide the hero with the blocks
        //
        game.physics.arcade.collide(this.hero, this.blocks);
        //
        //colide 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);
        //
        //get the first child
        var fchild = this.blocks.getChildAt(0);
        //if off the screen reset the blocks
        if (fchild.x < -game.width) {
            this.makeBlocks();
        }
    }
}

Check out the result here

2 thoughts on “Creating an Endless Runner Game in Phaser Part 4 Movement”

  1. Hey William, thanks for the tutorial!

    I have a question though: I realise that, if I add the blocks next to each other (instead of on top of each other), the blocks positioned after a certain x position won’t be rendered. For instance, if I add 20 blocks, one next to each other, by increasing the x position, I will only see a couple of blocks. If I position the second block further than a certain point, I won’t see it.

    That will depend on the position of the blocks object, I mean, if I set its x position to be 0, I will see many blocks. Now if I set its position to be the game width, I will only see a couple of blocks. As if there was a constrain in order to prevent objects to be positioned too far away from the actual viewport.

    Thanks!

    1. Hi Isaac,
      You are correct if the blocks if the blocks run off the screen you won’t see them. You would also need to increase the x position by the width of the block or more or the blocks would overlap. Sorry if I am missing something, but what is your question?

Leave a Comment