综合编程

“Stick Hero” HTML5 prototype built with Phaser using no physics – step 2: flipping the hero…

微信扫一扫,分享到朋友圈

“Stick Hero” HTML5 prototype built with Phaser using no physics – step 2: flipping the hero…
0

Did you enjoy the first step of Stick Hero prototype
?

The entire game was built without any physics engine, just using tweens. Now it’s time to add coins and the hero capability of flipping vertically to collect them, without hitting walls.

Have a look at the game now:

Tap and hold to make the pole grow. Release to cross the gap and reach next platform. Once on the pole, tap to flip the hero and collect coins, but don’t hit the walls.

I know what you’re thinking: a-ha! Collision checking! Now you’ll have to use a physics engine! Actually, I don’t. I will just be checking if sprite bounding boxes intersect. Which can be seen as the bare bones of a physics engine but in the real world it’s just a rectangle Vs rectangle intersection.

This is the source code, still uncommented, but if you are interested in the collision checking, just search for getBounds
and Intersection
methods, you’ll clearly figure it out while I optimize and add comments to the code.

let game;
let gameOptions = {
    platformGapRange: [200, 400],
    platformWidthRange: [50, 150],
    platformHeight: 600,
    playerWidth: 32,
    playerHeight: 64,
    poleWidth: 8,
    growTime: 500,
    rotateTime: 500,
    walkTime: 3,
    fallTime: 500,
    scrollTime: 250
}
const IDLE = 0;
const WAITING = 1;
const GROWING = 2;
const WALKING = 3;
window.onload = function() {
    let gameConfig = {
        type: Phaser.AUTO,
        width: 750,
        height: 1334,
        scene: [playGame],
        backgroundColor: 0x0c88c7
    }
    game = new Phaser.Game(gameConfig);
    window.focus();
    resize();
    window.addEventListener("resize", resize, false);
}
class playGame extends Phaser.Scene{
    constructor(){
        super("PlayGame");
    }
    preload(){
        this.load.image("tile", "tile.png");
        this.load.image("coin", "coin.png");
        this.load.image("player", "player.png");
    }
    create(){
        this.addCoin();
        this.addPlatforms();
        this.addPlayer();
        this.addPole();
        this.input.on("pointerdown", this.grow, this);
        this.input.on("pointerup", this.stop, this);
    }
    addPlatforms(){
        this.mainPlatform = 0;
        this.platforms = [];
        this.platforms.push(this.addPlatform(0));
        this.platforms.push(this.addPlatform(game.config.width));
        this.tweenPlatform();
    }
    addPlatform(posX){
        let platform = this.add.sprite(posX, game.config.height - gameOptions.platformHeight, "tile");
        platform.displayWidth = (gameOptions.platformWidthRange[0] + gameOptions.platformWidthRange[1]) / 2;
        platform.displayHeight = gameOptions.platformHeight;
        platform.alpha = 0.7;
        platform.setOrigin(0, 0);
        return platform
    }
    addCoin(){
        this.coin = this.add.sprite(0, game.config.height - gameOptions.platformHeight + gameOptions.playerHeight / 2, "coin");
        this.coin.visible = false;
    }
    placeCoin(){
        this.coin.x = Phaser.Math.Between(this.platforms[this.mainPlatform].getBounds().right + 10, this.platforms[1 - this.mainPlatform ].getBounds().left - 10);
        this.coin.visible = true;
    }
    tweenPlatform(){
        let destination = this.platforms[this.mainPlatform].displayWidth + Phaser.Math.Between(gameOptions.platformGapRange[0], gameOptions.platformGapRange[1]);
        let size = Phaser.Math.Between(gameOptions.platformWidthRange[0], gameOptions.platformWidthRange[1]);
        this.tweens.add({
            targets: [this.platforms[1 - this.mainPlatform]],
            x: destination,
            displayWidth: size,
            duration: gameOptions.scrollTime,
            callbackScope: this,
            onComplete: function(){
                this.gameMode = WAITING;
                this.placeCoin();
            }
        })
    }
    addPlayer(){
        this.player = this.add.sprite(this.platforms[this.mainPlatform].displayWidth - gameOptions.poleWidth, game.config.height - gameOptions.platformHeight, "player");
        this.player.setOrigin(1, 1)
    }
    addPole(){
        this.pole = this.add.sprite(this.platforms[this.mainPlatform].displayWidth, game.config.height - gameOptions.platformHeight, "tile");
        this.pole.setOrigin(1, 1);
        this.pole.displayWidth = gameOptions.poleWidth;
        this.pole.displayHeight = gameOptions.playerHeight / 4;
    }
    grow(){
        if(this.gameMode == WAITING){
            this.gameMode = GROWING;
            this.growTween = this.tweens.add({
                targets: [this.pole],
                displayHeight: gameOptions.platformGapRange[1] + gameOptions.platformWidthRange[1],
                duration: gameOptions.growTime
            });
        }
        if(this.gameMode == WALKING){
            if(this.player.flipY){
                this.player.flipY = false;
                this.player.y = game.config.height - gameOptions.platformHeight;
            }
            else{
                this.player.flipY = true;
                this.player.y = game.config.height - gameOptions.platformHeight + gameOptions.playerHeight - gameOptions.poleWidth;
                let playerBound = this.player.getBounds();
                let platformBound = this.platforms[1 - this.mainPlatform].getBounds();
                if(Phaser.Geom.Rectangle.Intersection(playerBound, platformBound).width != 0){
                    this.player.flipY = false;
                    this.player.y = game.config.height - gameOptions.platformHeight;
                }
            }
        }
    }
    stop(){
        if(this.gameMode == GROWING){
            this.gameMode = IDLE;
            this.growTween.stop();
            if(this.pole.displayHeight > this.platforms[1 - this.mainPlatform].x - this.pole.x){
                this.tweens.add({
                    targets: [this.pole],
                    angle: 90,
                    duration: gameOptions.rotateTime,
                    ease: "Bounce.easeOut",
                    callbackScope: this,
                    onComplete: function(){
                        this.gameMode = WALKING;
                        if(this.pole.displayHeight < this.platforms[1 - this.mainPlatform].x + this.platforms[1 - this.mainPlatform].displayWidth - this.pole.x){
                            this.walkTween = this.tweens.add({
                                targets: [this.player],
                                x: this.platforms[1 - this.mainPlatform].x + this.platforms[1 - this.mainPlatform].displayWidth - this.pole.displayWidth,
                                duration: gameOptions.walkTime * this.pole.displayHeight,
                                callbackScope: this,
                                onComplete: function(){
                                    this.coin.visible = false;
                                    this.tweens.add({
                                        targets: [this.player, this.pole, this.platforms[1 - this.mainPlatform], this.platforms[this.mainPlatform]],
                                        props: {
                                            x: {
                                                value: "-= " +  this.platforms[1 - this.mainPlatform].x
                                            }
                                        },
                                        duration: gameOptions.scrollTime,
                                        callbackScope: this,
                                        onComplete: function(){
                                            this.prepareNextMove();
                                        }
                                    })
                                }
                            })
                        }
                        else{
                            this.platformTooLong();
                        }
                    }
                })
            }
            else{
                this.platformTooShort();
            }
        }
    }
    platformTooLong(){
        this.walkTween = this.tweens.add({
            targets: [this.player],
            x: this.pole.x + this.pole.displayHeight + this.player.displayWidth,
            duration: gameOptions.walkTime * this.pole.displayHeight,
            callbackScope: this,
            onComplete: function(){
                this.fallAndDie();
            }
        })
    }
    platformTooShort(){
        this.tweens.add({
            targets: [this.pole],
            angle: 90,
            duration: gameOptions.rotateTime,
            ease: "Cubic.easeIn",
            callbackScope: this,
            onComplete: function(){
                this.gameMode = WALKING;
                this.tweens.add({
                    targets: [this.player],
                    x: this.pole.x + this.pole.displayHeight,
                    duration: gameOptions.walkTime * this.pole.displayHeight,
                    callbackScope: this,
                    onComplete: function(){
                        this.tweens.add({
                            targets: [this.pole],
                            angle: 180,
                            duration: gameOptions.rotateTime,
                            ease: "Cubic.easeIn"
                        })
                        this.fallAndDie();
                    }
                })
            }
        })
    }
    fallAndDie(){
        this.gameMode = IDLE;
        this.tweens.add({
            targets: [this.player],
            y: game.config.height + this.player.displayHeight * 2,
            duration: gameOptions.fallTime,
            ease: "Cubic.easeIn",
            callbackScope: this,
            onComplete: function(){
                this.shakeAndRestart();
            }
        })
    }
    prepareNextMove(){
        this.gameMode = IDLE;
        this.platforms[this.mainPlatform].x = game.config.width;
        this.mainPlatform = 1 - this.mainPlatform;
        this.tweenPlatform();
        this.pole.angle = 0;
        this.pole.x = this.platforms[this.mainPlatform].displayWidth;
        this.pole.displayHeight = gameOptions.poleWidth;
    }
    shakeAndRestart(){
        this.cameras.main.shake(800, 0.01);
        this.time.addEvent({
            delay: 2000,
            callbackScope: this,
            callback: function(){
                this.scene.start("PlayGame");
            }
        })
    }
    update(){
        if(this.player.flipY){
            let playerBound = this.player.getBounds();
            let coinBound = this.coin.getBounds();
            let platformBound = this.platforms[1 - this.mainPlatform].getBounds();
            if(Phaser.Geom.Rectangle.Intersection(playerBound, platformBound).width != 0){
                this.walkTween.stop();
                this.gameMode = IDLE;
                this.shakeAndRestart();
            }
            if(this.coin.visible && Phaser.Geom.Rectangle.Intersection(playerBound, coinBound).width != 0){
                this.coin.visible = false;
            }
        }
    }
};
function resize(){
    let canvas = document.querySelector("canvas");
    let windowWidth = window.innerWidth;
    let windowHeight = window.innerHeight;
    let windowRatio = windowWidth / windowHeight;
    let gameRatio = game.config.width / game.config.height;
    if(windowRatio < gameRatio){
        canvas.style.width = windowWidth + "px";
        canvas.style.height = (windowWidth / gameRatio) + "px";
    }
    else{
        canvas.style.width = (windowHeight * gameRatio) + "px";
        canvas.style.height = windowHeight + "px";
    }
}

Easy and lightweight, I made a completely working prototype in about 250 lines. Download the source code
.

阅读原文...

微信扫一扫,分享到朋友圈

“Stick Hero” HTML5 prototype built with Phaser using no physics – step 2: flipping the hero…
0
Emanuele Feronato

Reddit users are the least valuable of any social network

上一篇

A Million Little Things: Ending the Blame Game

下一篇

评论已经被关闭。

插入图片

热门分类

往期推荐

“Stick Hero” HTML5 prototype built with Phaser using no physics – step 2: flipping the hero…

长按储存图像,分享给朋友