Search code examples
typescriptphaser-frameworkphaserjs

how can I set up a T-shaped hitbox for an umbrella?


I have started learning Phaser 3.60 and unfortunately I am stuck. I can't find a way to set up the hitbox. Exactly what I would like is to have the raindrop falling from the top down and have an umbrella that when the raindrop falls on it, it cancels the raindrop and generates a new one. The mechanics are written but I can't rewrite the hitbox. I would like your help with this. I will send you a few lines of my code.

Umbrella:

export class Umbrella extends Phaser.Physics.Arcade.Sprite {
    private raindrops: Phaser.Physics.Arcade.Group;
    private debugGraphic: Phaser.GameObjects.Graphics; // debugGraphic tulajdonság hozzáadása

    constructor(
        scene: Phaser.Scene,
        x: number,
        y: number,
        raindrops: Phaser.Physics.Arcade.Group
    ) {
        super(scene, x, y, "umbrella");

        scene.add.existing(this);
        this.scene.physics.world.enable(this); // Engedélyezzük a fizikai testet az esernyő Sprite-hoz

        // Inicializáljuk a debugGraphic-t
        this.debugGraphic = scene.add.graphics();

        (this.body as Phaser.Physics.Arcade.Body).allowGravity = false; // Kikapcsoljuk a gravitációt

        const hitboxWidth = 100; // A hitbox szélessége
        const hitboxHeight = 100; // A hitbox magassága

        const topHeight = hitboxHeight * 0.25; // A felső téglalap magassága (25%)
        const bottomHeight = hitboxHeight - topHeight; // Az alsó téglalap magassága

        this.raindrops = raindrops;
    }

    public mouseMove(input: Phaser.Input.InputPlugin): void {
        // Itt mozgatjuk az egérrel az esernyőt ha kattintunk
        var pointer = input.activePointer;
        if (pointer.isDown) {
            this.x = pointer.x;
            this.y = pointer.y;
        }

        // Itt mozgatjuk az egérrel az esernyőt ha simán mozgatjuk.
        input.on("pointermove", (pointer) => {
            this.x = pointer.x;
            this.y = pointer.y;

            this.drawHitbox(this.x, this.y);
        });
    }

    private drawHitbox(x: number, y: number): void {
        const hitbox = this.body as Phaser.Physics.Arcade.Body;
        // Rajzolás a debugGraphic segítségével
        this.debugGraphic.clear();
        this.debugGraphic.lineStyle(2, 0xff0000); // Vonalstílus beállítása (2 pixel vastag, piros szín)
        this.debugGraphic.strokeRect(
            x - hitbox.width / 2,
            y - hitbox.height / 2,
            hitbox.width,
            hitbox.height
        );
    }
}

MainGame Scene:

collision event:

//Az esőcsepp és az esernyő detektálása.
    this.physics.add.overlap(
        this.umbrella,
        this.raindrops,
        this.collectDrop,
        null,
        this
    );
}

Collision detection:

private collectDrop(
    umbrella: Phaser.Physics.Arcade.Sprite,
    drop: Phaser.Physics.Arcade.Sprite
): void {

    // // Eltávolítjuk a cseppet a csoportból
    this.raindrops.remove(drop, true, true);

    // Generálunk egy új esőcseppet
    const newDrop = new Raindrop(
        this,
        Math.floor(Math.random() * Number(this.game.config.width)),
        -100
    );
    this.raindrops.add(newDrop);
}

Solution

  • As @zenly mentioned thin-bar is enough. To create this you can use the functions setSize and setOffset of the physics body, shown in the following demo (link to the documentation).

    btw.: you don't really need, to create a debug graphics object, since phaser offers it out-of-the-box, with the config property debug, just set it to true.

    Here a short demo:

    document.body.style = 'margin:0;';
    class Umbrella extends Phaser.Physics.Arcade.Sprite {
        constructor( scene, x, y, raindrops ) {
            super(scene, x, y, "umbrella");
    
            scene.add.existing(this);
            this.scene.physics.world.enable(this); 
    
            this.body.allowGravity = false;
    
            // size of hitbox
            this.setSize(80, 5);
            // offset of hitbox
            this.setOffset(-25, -20);
    
            const hitboxWidth = 100;
            const hitboxHeight = 100;
    
            const topHeight = hitboxHeight * 0.25;
            const bottomHeight = hitboxHeight - topHeight;
    
            this.raindrops = raindrops;
        }
        
        //...
    }
    
    var config = {
        type: Phaser.AUTO,
        width: 536,
        height: 183,
        physics: {
            default: 'arcade',
            arcade: {
                // shows debug hitbox
                debug: true
            }
        },
        scene: { create }
    }; 
    
    function create () {    
         let i = new Umbrella(this, 100, 100, []);
    }
    
    new Phaser.Game(config);
    <script src="//cdn.jsdelivr.net/npm/phaser/dist/phaser.min.js"></script>

    If you want the create a T-shaped hitbox. I could create a custom Phaser Container and add two physics objects/bodies, and position the with the above mentioned functions.