phaserjs / phaser

Phaser is a fun, free and fast 2D game framework for making HTML5 games for desktop and mobile web browsers, supporting Canvas and WebGL rendering.
https://phaser.io
MIT License
37.13k stars 7.1k forks source link

Initial rectangle positioning varies depending on width #6777

Closed codeimpossible closed 2 months ago

codeimpossible commented 7 months ago

Version

Description

This could definitely be a documentation issue, it's not clear if the x and y values passed into scene.add.rectangle() are intended to be the world-space of the center of the rectangle, or the world-space of the top-left of the rectangle. If they are meant to be the top-left then there is a bug with how the rectangle placement is calculated as it changes depending on the rectangle size at creation.

What I did

I created two rectangles at the same x,y position. The first has a fixed size and the second starts with a smaller width and increases over time.

What happened

The first rectangle (fixed size) is rendered with its center point seemingly where the top-left of the second rectangle is in world-space. The second rectangle (dynamic size) stays in place, but expands to the right over time (as I expected).

What did I expect to happen

I expected that the first rectangle would have the same behavior as the second, treating the x,y position as the location of the top-left corner instead of the center point.

Example Test Code

class Example extends Phaser.Scene
{
    timedEvent;
    progressBar;
    progressBarWrapper;
    progressBarSize;

    init() {
        const centerX = 400, centerY = 300;
        this.progressBarSize = { width: 800 / 2, height: 32 };
        const progressBarPos = { x: centerX - this.progressBarSize.width / 2, y: centerY - this.progressBarSize.height / 2 };
        const progressBarStartWidth = 4;

        this.progressBarWrapper = this.add.rectangle(progressBarPos.x - 1, progressBarPos.y - 1, this.progressBarSize.width + 2, this.progressBarSize.height + 2).setStrokeStyle(1, 0xffffff);
        this.progressBarWrapper.width = this.progressBarSize.width;
        this.progressBar = this.add.rectangle(progressBarPos.x, progressBarPos.y, progressBarStartWidth, this.progressBarSize.height, 0xffffff);
        this.timedEvent = this.time.delayedCall(3000, this.finishLoading, [], this);
    }

    updateProgress(progress) {
        this.progressBar.width = this.progressBarSize.width * progress;
    }

    update ()
    {
        this.updateProgress(this.timedEvent.getProgress());
    }

    finishLoading() {

    }
}

const config = {
    type: Phaser.AUTO,
    width: 800,
    height: 600,
    backgroundColor: '#2d2d2d',
    parent: 'phaser-example',
    scene: Example
};

const game = new Phaser.Game(config);

Image of the above code running on the Phaser Labs site: image

photonstorm commented 7 months ago

x/y coordinates for all Game Objects is the center by default. This can be changed via the setOrigin() method.

UnaiNeuronUp commented 6 months ago

Changing width property is ignoring the origin of the rectangle.


class MainScene extends Phaser.Scene {
    timedEvent;
    progressBar;

    constructor() {
        super({ key: "MainScene" });
    }

    create() {
        this.rectWidth = 200;
        this.add.rectangle(200, 200, this.rectWidth, 60).setStrokeStyle(1, 0xffffff);

        // Use one of these lines to see different behaviors
        this.progressBar = this.add.rectangle(200, 200, 0, 60, 0xffffff);
        // this.progressBar = this.add.rectangle(200, 200, this.rectWidth, 60, 0xffffff);

        this.timedEvent = this.time.delayedCall(3000);
    }

    update() {
        this.progressBar.width = this.rectWidth * this.timedEvent.getProgress();
    }

}

const game = new Phaser.Game({
    type: Phaser.AUTO,
    width: 800,
    height: 800,
    backgroundColor: '#111111',
    scale: {
        mode: Phaser.Scale.FIT,
        autoCenter: Phaser.Scale.CENTER_BOTH
    },
    scene: [ MainScene ]
})
photonstorm commented 6 months ago

If you want to change the intrinsic width (as above) then you can use the width property like this, and it will extend out from the origin to the right. If you want to change how it renders, factoring in the origin, use displayWidth instead.