Imagine a very simple scene:
private create(): void {
const circ = this.add.circle(
400, 320, 200, 0xff0000
);
const l1 = this.add.line(
0, 0, 400, 320, 400, 100, 0x0000ff
).setOrigin(0);
const l2 = this.add.line(
0, 0, 400, 320, 200, 320, 0x0000ff
).setOrigin(0);
}
So far so good.
Now I want to scale this simple figure, same config 1.5x its current size:
private create(): void {
const circ = this.add.circle(
400, 320, 200, 0xff0000
);
const l1 = this.add.line(
0, 0, 400, 320, 400, 100, 0x0000ff
).setOrigin(0);
const l2 = this.add.line(
0, 0, 400, 320, 200, 320, 0x0000ff
).setOrigin(0);
this.tweens.add({
targets: [circ, l1, l2],
scale: 1.5,
yoyo: false,
duration: 2000,
ease: 'Sine.easeInOut'
});
}
Expected behavior:
Actual behavior:
As things stand, only #1 fit my expectations. The lines, however, translate as opposed to merely scaling. And the translation seems affected by the scale parameter passed to tweens.add. What gives? What am I missing here?
Given the various configurations for "origin" wrt lines in Phaser 3, the worst I was expecting was that the lines would emanate/grow differently than the circle (which emanates from the center/origin). But I definitely expect the lines to stay still/keep their intersection at the circle's center.
Can you explain what exactly Phaser is doing here and what might I do to get my desired effect?
There are a bunch of things that might be unintuitive with the Line GameObject in Phaser 3, all contributing to this behavior. Let's break them down.
First of all, make the distinction between line as a geometric entity and line as a Phaser 3 Game Object. They are related but the confusion stems from the subtleties.
For the Phaser 3 line Game Object, there are three ordered pairs p (x, y) you need to keep in mind:
Another important thing is that the game world is basically a Cartesian coordinate system flipped around the x-axis. So negative x values still go to the left but negative y values go up and positive y values go down.
Now let's define the origin, which I will just paraphrase from the official docs:
An object's origin is a normalized value in the range [0, 1].
For the x-axis, 0 means the left of the Game Object and 1 means the right.
For the y-axis, 0 means the top of the Game Object and 1 means the bottom.
By default, the origin is set at 0.5, the center of the object.
Let's take the horizontal line l2
in the example and figure out how it's being drawn.
const l2 = this.add.line(
0, 0, 400, 320, 200, 320, 0x0000ff
).setOrigin(0);
The important observation here is that the origin is completely outside the geometric line defined. In effect, there is a considerable invisible space in the rectangular area between your origin (at (0, 0)), left of the game object and the right, lowermost corner (at (400, 320)).
Now, when the tween is invoked, it actually scales the game object rather than just the geometric line. And since most of the game object is "invisible" (the geometric line being the only part visible), the effect is as if the geometric line is translating!
To get the desired effect, constrain the game object to exactly the area taken up by the geometric line. One such way to do this would be:
Putting it all together,
private create(): void {
const circ = this.add.circle(
400, 320, 200, 0xff0000
);
const l1 = this.add.line(
400, 320, 0, 0, 0, -100, 0x0000ff
).setOrigin(0);
const l2 = this.add.line(
400, 320, 0, 0, -200, 0, 0x0000ff
).setOrigin(0);
this.tweens.add({
targets: [circ, l1, l2],
scale: 1.5,
yoyo: false,
duration: 2000,
ease: 'Sine.easeInOut'
});
}