I think I’ve found a solution, I’ll confirm it here once I’ve tested it enough. My problem was basically linked to the default size of a container (0x0) resulting in a 64x64 body.
The 64x64 body would have its upper-left corner centered on my sprite.
To solve this, I simply had to set the container’s size to match the sprite’s BEFORE creating the physics body:
export default class GameCharacter extends Phaser.GameObjects.Container {
private bodyWidthFlipOffsetX = 0.4;
body: Phaser.Physics.Arcade.Body;
private charBody: Phaser.GameObjects.Sprite;
private charWeapon: Phaser.GameObjects.Sprite;
constructor(scene: Phaser.Scene, x: number, y: number, characterId: string) {
super(scene, x, y);
this.charBody = scene.add.sprite(0, 0, "astro", "astro-red-idle_armed-6.png");
this.charBody.anims.play("astro-red-idle");
this.setSize(this.charBody.width, this.charBody.height); // DO THIS
this.add(this.charBody);
this.charWeapon = scene.add.sprite(0, 0, "astro", "astro-gun02_still1.png");
this.add(this.charWeapon);
}
The same class would then simply align the weapon on the sprite in the preUpdate() method:
preUpdate(t: number, dt: number) {
this.charWeapon.x = 12; // hard coded for the example
this.charWeapon.y = 19; // hard coded for the example
}
Then in case it can help, I’ve implemented the horizontal flipping in the update() method (called by the scene’s update method):
update(cursors: Phaser.Types.Input.Keyboard.CursorKeys) {
if (!cursors) {
return;
}
if (cursors.left.isDown) {
this.setFlippedX(true);
this.body.setVelocity(-100, 0);
} else if (cursors.right.isDown) {
this.setFlippedX(false);
this.body.setVelocity(100, 0);
} else {
this.body.setVelocity(0, 0);
}
}
The set flippedX method will simply handle the physics offset based on the object’s bodyWidthFlipOffsetX property:
setFlippedX(flipped: boolean) {
if (flipped) {
this.scaleX = -1;
this.body.offset.x = this.body.width + this.body.width * this.bodyWidthFlipOffsetX;
} else {
this.scaleX = 1;
this.body.offset.x = this.body.width * this.bodyWidthFlipOffsetX;
}
}