coding

Creating hero HUD on Phaser JS - Skate Platformer Game Devlog #10

Written in November 5, 2020 - 🕒 3 min. read

Hey guys, in today’s game devlog I’ll show you how I did to create the HUD with the hero’s status.

The first thing I did was to cut the HUD design from Ítalo into small reusable parts so I could increase/decrease the meter bars at will. My final atlas PNG looks like this:

Hero HUD
Hero HUD

After having all the HUD parts separated, I created a GameGroup with all the images, and whenever I need to increase or decrease the life of the hero I call the functions increasePlayerLife and decreasePlayerLife.

class PlayerHud extends GameGroup {
    constructor(scene) {
        const children = [];
        // create all the game object images
        [
            'hud_meter_border',
            'hud_meter_point_border',
            'player_face_hud',
            'player_life_hud',
            'skate_hud',
            'skate_life_hud',
            'collectable_times',
            'coin',
        ].forEach((asset) => {
            if (
              ['hud_meter_border', 'hud_meter_point_border'].includes(asset)
            ) {
                ['skate', 'player'].forEach((hudType) => {
                    const assetName = `${hudType}_${asset}`;
                    const child = new GameObjects.Image(
                        scene,
                        x,
                        y,
                        asset
                    );

                    child.setOrigin(0, 0);
                    child.setName(assetName);
                    child.setScrollFactor(0);
                    children.push(child);
                });
                return;
            }

            const child = new GameObjects.Image(
                scene,
                x,
                y,
                asset
            );

            child.setOrigin(0, 0);
            child.setName(asset);
            child.setScrollFactor(0);
            children.push(child);
        });

        super(scene, children);

        // create a dummy game object to store the data manager
        const dataGameobject = new GameObjects.Rectangle(scene, x, y);
        this.data = new Data.DataManager(dataGameobject);

        // set data manager listeners
        this.data.set(PLAYER_LIFE_DATA, initialPlayerLife);
        this.data.set(SKATE_LIFE_DATA, initialSkateLife);
        this.data.set(COLLECTED_NUTS_DATA, initialCollectedNuts);
        this.data.events.on(
          `changedata-${SKATE_LIFE_DATA}`,
          this.onSkateLifeChanged
        );
        this.data.events.on(
          `changedata-${PLAYER_LIFE_DATA}`,
          this.onPlayerLifeChanged
        );
        this.data.events.on(
          `changedata-${COLLECTED_NUTS_DATA}`,
          this.onCollectedNutsChanged
        );

        // After everythibg is set
        this.setHudPositions();
    }

    setHudPositions = () => {
        // TODO
    }

    increasePlayerLife = () => {
        // TODO
    }

    decreasePlayerLife = () => {
        // TODO
    }
}

As I didn’t want to make the construct function too big, I created the setHudPositions function that sets all the positions of the HUD images.

setHudPositions = () => {
    const { width, height } = this.scene.cameras.main;
    const paddingX = 10;
    const paddingY = 10;
    const skateLife = this.data.get(SKATE_LIFE_DATA);
    const playerLife = this.data.get(PLAYER_LIFE_DATA);
    this.getChildren().forEach((child) => {
        const { name } = child;
        child.setX(paddingX);
        child.setY(paddingY);

        switch (name) {
            case 'player_face_hud': {
                // TODO
                break;
            }
            case 'player_hud_meter_border': {
                child.setX(child.x + 32);
                child.setY(child.y + 15);
                child.setScale(playerLife - 1, 1);
                child.setDepth(child.depth - 1);
                break;
            }
            case 'player_hud_meter_point_border': {
                child.setX(child.x + playerLife + 31);
                child.setY(child.y + 16);
                child.setDepth(child.depth - 1);
                break;
            }
            case 'player_life_hud': {
                child.setX(child.x + 32);
                child.setY(child.y + 16);
                child.setScale(playerLife, 1);
                child.setDepth(child.depth - 2);
                break;
            }
            case 'skate_hud': {
                child.setY(child.y + 32);
                break;
            }
            case 'skate_hud_meter_border': {
                child.setX(child.x + 32);
                child.setY(child.y + 34);
                child.setScale(skateLife - 1, 1);
                child.setDepth(child.depth - 1);
                break;
            }
            case 'skate_hud_meter_point_border': {
                child.setX(child.x + skateLife + 31);
                child.setY(child.y + 35);
                child.setDepth(child.depth - 1);
                break;
            }
            case 'skate_life_hud': {
                child.setX(child.x + 32);
                child.setY(child.y + 35);
                child.setScale(skateLife, 1);
                child.setDepth(child.depth - 2);
                break;
            }
            case 'coin': {
                child.setY(child.y + 48);
                break;
            }
            case 'nut_text': {
                child.setY(child.y + 42);
                child.setX(child.x + 25);
                break;
            }
            case 'collectable_times': {
                child.setY(child.y + 52);
                child.setX(child.x + 17);
                break;
            }
            default: {
                break;
            }
        }
    });
}

And last but not least the functions increasePlayerLife and decreasePlayerLife:

decreasePlayerLife = (value) => {
    const playerLife = this.data.get(PLAYER_LIFE_DATA);
    this.data.set(PLAYER_LIFE_DATA, playerLife - value);
}

increasePlayerLife = (value) => {
    const playerLife = this.data.get(PLAYER_LIFE_DATA);
    this.data.set(PLAYER_LIFE_DATA, playerLife + value);
}

Now I can simply add gameHud.decreasePlayerLife(5) in the collision function between the hero and the enemies and that’s it 😄

And that concludes this week’s game devlog, don’t forget to leave your comment both here and in the video about what you think of these posts and videos.

Tags:


Post a comment

Comments

Zayyad on 11/9/20

This is very nice. I'm learning lessons from these blog posts