« Back to Blog

Phaser Platformer Series: 17 Mushrooms

posted on 12 July 2021

In this tutorial, we’ll take a look at a powerup that changes the player’s size ala mushrooms in Super Mario. Collecting a mushroom makes the player grow bigger, move faster, and jump higher. If they get hit they shrink back down to size.

Traditionally you wouldn’t have a heart’s hit system *and* also mushrooms – in Super Mario mushrooms are your hit system. If you are big, you know you can within stand two hits, if you’re small, one hit and you’re dead. We’ve already put hearts in so we are starting to mix things that possibly shouldn’t be mixed, but heh, it all helps with the learning.

Also, our characters jumping and movement are set up fairly nicely for the size they are. We could double their size, but this would make them way overpowered. Instead, we’ll change our player to start half the size they currently are.

Here is what we’ll be making:

See the Pen
Phaser Platformer Series: 17 Mushrooms
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.

It would be easy, and tempting, to resize the player using their scale parameter as we do with the tweens that play on their death. This would work fine, and as we are just currently using a white square as our sprite we’d get away with it. For an actual sprite with a pixel art character, scaling it will probably make it look awful, so we’re going to try and do it properly so when some decent sprites are added in it still works well.

With that in mind, we need a new sprite for our small character. This is just going to be a slightly smaller square. We also need another powerup – for now, we’ll just reuse the invincibility powerup sprite and tint it to make it look different. We need to add a global variable for our mushroom pickup:

 mushroom,

we also need some more global variables to control how high the player jumps based on their size:

jumpVelocity = -165,
jumpVelocitySmall = -165,
jumpVelocityBig = -330,

Before we had one variable jumpVelocity that we apply when the player jumps. From now on we’ll have two velocities and we will change the value of jumpVelocity according to the player’s size.

In preload we add our new smaller hero sprite:

this.load.image('hero-small', 'hero-small.jpg');

In our create function we change our player to use the new sprite:

player = this.physics.add.sprite(40, 350, 'hero-small');

Then we add our mushroom powerup reusing the invincibility power up sprite, and tint it orange:

//add mushroom powerup, set it to rotate around its center and tint it orange
mushroom = this.physics.add.sprite(120, 360, 'powerup');
mushroom.setOrigin(.5, .5);
mushroom.setTintFill(0xff9800);

And then the collision and overlap detection so our mushroom powerup sits on the platforms and can be collected by our hero:

this.physics.add.collider(mushroom, platforms);
this.physics.add.overlap(player, mushroom, collectMushroom, null, this);

When the player collects the mushroom the function collectMushroom will be called:

  function collectMushroom(player, mushroom) {
    //stop the players movement
    player.body.velocity.x = 0;
    player.body.velocity.y = 0;
    //set a flag saying the player is transitioning sizes
    player.isChangingSize = true;

    //disable the mushroom so it can only be triggered once
    mushroom.disableBody(false, false);

    //tween the player scaling up in size
    var tween = this.tweens.add({
        targets: player,
        scaleX: 1.5,
        scaleY: 1.5,
        yoyo: 1,
        repeat: 1,
        ease: 'Linear',
        duration: 100,
        onComplete: function() {
            //when the tween is over call this function
            growHero();
        },
    });

    //tween powerup to scale up and then remove
    var tween = this.tweens.add({
        targets: mushroom,
        alpha: 0.3,
        angle: 90,
        scaleX: 0.3,
        scaleY: 0.3,
        ease: 'Linear',
        duration: 500,
        onComplete: function() {
            destroyGameObject(mushroom);
        },
    });
}

This should look familiar as it’s a lot like the callback for the collection of our invincibility powerup. The main difference is that we remove the player’s velocity to stop them in their tracks and also set a flag isChangingSize. We do this, as when we tween the hero’s size and it yoyos back and forth we don’t want the hero to accidentally collide with a baddie just because they are getting bigger. Setting the flag means we know when they are in this transitional state and we can make sure we ignore collisions with a baddie at this point. We tween the hero to grow and shrink (using a yoyo tween) and then when the tween is finished the hero will be double-sized and the growHero function is called:

function growHero() {
    //change sprite to be our larger one
    player.setTexture("hero");
    //manually change the size
    player.setSize(32, 32);
    //set flag we know the player is in big mode
    player.isBig = true;
    //reset our transitional flag
    player.isChangingSize = false;
}

The sprite is changed and we call setSize which rejigs our physics to deal with the new sprite (the new sprite is 32px x 32px). Finally we set a new flag isBig so have recorded that the player is in a larger state.

In our update function we then set the jumpVelocity by checking the players isBig flag:

//set jump velocity depending on whether we are big or small
    if (player.isBig) jumpVelocity = jumpVelocityBig;
    else jumpVelocity = jumpVelocitySmall;

That handles the collection and animation of our hero into the bigger version and the different jumping abilities. Next up we look at the collision detection for when the player is big. If the baddie hits them or the fall on spikes then they should shrink back down to the original (this new original that is) size. In our playerHit function we change the code where the player gets hit and jumps into the air flashing and goes invulnerable for a short period time. Instead of always doing this, we check the isBig flag and have different code for this scenario:

if (player.isBig) {
    player.body.velocity.x = 0;
    player.body.velocity.y = -220;
    player.isChangingSize = true;

    var tween = this.tweens.add({
        targets: player,
        scaleX: 0.8,
        scaleY: 0.8,
        alpha: 0.3,
        yoyo: 2,
        repeat: 2,
        ease: 'Linear',
        duration: 100,
        onComplete: function() {
            shrinkHero();
        },
    });
} else {
    //perform the regular old hit code..

If the player is big, we stop their x velocity and jump them in the air slightly whilst playing a flashing tween of them shrinking. When the tween ends we call shrinkHero.

function shrinkHero() {
    //change player to smaller sprire
    player.setTexture("hero-small");
    //manually resize so physics adjusts
    player.setSize(22, 22);
    //set isBig for false so we know the player is small
    player.isBig = false;
    //reset our transitional flag
    player.isChangingSize = false;
}

This changes the sprite, and again rejigs the physics using setSize using the size of the sprite (24px x 24px). We then reset the flags so we know the player is small and no longer in a transitional state.

Finally, we need to make a change to our hitBaddie function. We change our check for when we land on the baddies head and kill them to also check that we are not in a transitional state:

//baddie was hit on the head and hasn't already been hit, and not animating shrink
if (baddie.body.touching.up && !baddie.hit && !player.isChangingSize)

We check the isChangingSize flag and if that is set then the baddie doesn’t get hit. This stops the growing or shrinking animation from accidentally killing the baddie if they happened to be close enough. The most likely scenario we are protecting against here, is that the baddie hits the hero, the hero shrinks, but in the process of doing so collides with the baddies head, thus killing them. It just looks really buggy that way, and this tidies that up.

There we have it, a growing and shrinking hero with different jumping abilities. In Super Mario this sort of power-up wouldn’t be lying around, it would be released when you hit a block from underneath and that’s what we’ll tackle next in question mark boxes.

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