« Back to Blog

Phaser Platformer Series: 12 Shells

posted on 2 June 2021

In this tutorial, we’ll be adding projectiles in the form of Mario’s favourite, shells. If our hero walks into a shell or jumps of it, it should fly off in the direction it was sent. If it hits a baddie, they’re toast.

Here’s what we will be making:

See the Pen
Phaser Platformer: 12 Shells
by Digitherium (@digitherium)
on CodePen.


If you are viewing on a mobile, you can open a version of it here without all the codepen chrome taking up screen space so you play it in landscape mode.

As usual we’ll need to add some new variables to our globals at the top of the file. One for our new shell object, and variable called shellSpeed to control how fast the shell moves:

shell,
shellSpeed = 500;

and then load in the sprite in the preload function:

this.load.image('shell', 'shell.png');

Then in our create function we create the sprite:


 shell = this.physics.add.sprite(200, 350, 'shell');

and setup our collisions. The shell needs to sit and interact on the platforms, collide with the player and collide with the enemy:

this.physics.add.collider(shell, platforms);
this.physics.add.collider(player, shell, shellHit, null, this);
this.physics.add.overlap(shell, baddie, shellHitBaddie, null, this);

We’re using collide for both the platforms and our hero, but for the baddies we’ll use an overlap. This will just allow us to play our own death animation without the baddie being physically moved by the impact of the shell hit as no physics will be carried out.

Let’s take a look at what happens when our hero collides with the shell:

 function shellHit(player, shell) {
//work out the center point of the shell and player
var threshold = shell.x + (shell.width / 2),
    playerX = player.x + (player.width / 2);

//if the player has jumped on top of the shell...
if (shell.body.touching.up) {
    //if player landed on left hand side of shell send shell off to right
    if (playerX < threshold) shell.body.velocity.x = shellSpeed;
    //if player landed on right hand side of shell send shell off to left
    else shell.body.velocity.x = -shellSpeed;
}
//player hit shell from left so send right
if (shell.body.touching.left) {
    shell.body.velocity.x = shellSpeed;
}
 //player hit shell from right so send left
if (shell.body.touching.right) {
    shell.body.velocity.x = -shellSpeed;
}
//make player react to shell by bouncing slightly
player.body.velocity.y = -200;
}

There are three things that can happen when our hero collides with the shell – they walk into it from the right sending the shell left, they walk into the shell from the left sending the shell right OR they jump on the shell. The first two are easy and are dealt with using touching.left and touching.right:

//player hit shell from left so send right
if (shell.body.touching.left) {
    shell.body.velocity.x = shellSpeed;
}
 //player hit shell from right so send left
if (shell.body.touching.right) {
    shell.body.velocity.x = -shellSpeed;
}

Upon collision, we just apply a velocity to the shell to send it off in the right direction.

Jumping on the shell is a little bit more complicated as we don’t have an immediately obvious direction to send the shell in. What we want is to look at where our hero lands on the shell. If the hero’s center point lands on the left-hand side of the shell then the shell fires off to the right, if they land on the right-hand side then the shell fires off to the left. This is what our threshold and playerX variables are used for:

//work out the center point of the shell and player
var threshold = shell.x + (shell.width / 2),
    playerX = player.x + (player.width / 2);

//if the player has jumped on top of the shell...
if (shell.body.touching.up) {
    //if player landed on left hand side of shell send shell off to right
    if (playerX < threshold) shell.body.velocity.x = shellSpeed;
    //if player landed on right hand side of shell send shell off to left
    else shell.body.velocity.x = -shellSpeed;
}

We check that something is touching the top of the shell (as our shell doesn’t move on it’s own it can only be our hero) and then check which side the hero fell and apply the appropriate velocity – positive for right, negative for left. When we position our game objects it’s from their left corner, so when a shell is positioned at 200, it’s actually the left edge of shell at 200, and as our shell is 18px wide, then the half way point would be 209. i.e. By taking the x coordinate of our object and adding half it’s width we get the center point.

Then to finish things off, regardless of where our hero collided with the shell we make them jump slightly so it’s more visually interesting:

 //make player react to shell by bouncing slightly
player.body.velocity.y = -200;

If a shell collides with a baddie, the baddie should die, and the shell should disappear. This is pretty straight forward and very similar to previous collisions between our hero and baddie:

function shellHitBaddie(shell, baddie) {
    if (!baddie.hit) {
        // set baddie as being hit and remove physics
        baddie.disableBody(false, false);
        //play baddie death animation
        var tween = this.tweens.add({
            targets: baddie,
            alpha: 0.3,
            scaleX: 1.5,
            scaleY: 1.5,
            ease: 'Linear',
            duration: 200,
            onComplete: function() {
                destroyGameObject(baddie);
            },
        });

        //disable physics of shell
        shell.disableBody(false, false);
        //play shell hit animation
        var tween2 = this.tweens.add({
            targets: shell,
            alpha: 0.3,
            scaleX: 2,
            scaleY: 2,
            y: "-=100",
            rotation: -360,
            ease: 'Linear',
            duration: 200,
            onComplete: function() {
                destroyGameObject(shell);
            },
        });
    }
}

We just disabled the physics for both objects and play a nice animation for each. On completion of each animation, each game object is destroyed.

And that’s us done. Shells ahoy. Next up hearts / lives.

chromeless mobile version
view all the code on codepen
download the source on github