Hey,
I know this is a year after this was posted, but I ran into this problem as well. I’m on Phaser version 3.23.0.
I came up with a solution for it, and I wanted to post it just incase you or anyone else still needs it.
I modified your example and pasted it below.
For a quick explanation, I basically added a function named “arcadeSpriteFix()” at the bottom, and just call it after the sprite gets created in plantBomb. It fixes the flickering problem, and aligns the sprite’s body like intended.
class Bomb extends Phaser.Physics.Arcade.Sprite {
constructor(scene, x, y) {
super(scene, x, y, 'bomb')
scene.add.existing(this)
scene.physics.add.existing(this)
this.body.setSize(128, 128)
}
}
class Player extends Phaser.Physics.Arcade.Sprite {
constructor(scene, x, y) {
super(scene, x, y, 'player')
scene.add.existing(this)
scene.physics.add.existing(this)
this.body.setSize(32, 32)
}
plantBomb() {
const bomb = new Bomb(this.scene, this.x, this.y)
this.scene.bombs.add(bomb)
arcadeSpriteFix(bomb); //<-- add this line
}
}
var config = {
type: Phaser.AUTO,
width: 800,
height: 600,
backgroundColor: '#2d2d2d',
parent: 'phaser-example',
scene: {
key: 'testing',
preload: preload,
create: create,
update: update
},
physics: {
default: 'arcade',
arcade: {
debug: true
}
}
};
var game = new Phaser.Game(config);
function preload ()
{
this.load.image('player', 'assets/sprites/mine.png');
this.load.image('bomb', 'assets/sprites/saw.png');
}
function create ()
{
this.bombs = this.add.group()
this.player = new Player(this, 150, 150)
this.player.setDepth(1);
this.scene.pause();
setInterval(() => {
this.scene.resume()
}, 1000)
}
function update ()
{
// Only create 1 bomb
if (!this.bombs.getChildren().length) {
this.player.plantBomb()
}
const bomb = this.bombs.getFirst(true)
console.log('Bomb body coordinates: ', bomb.body.x, bomb.body.y)
this.scene.pause();
}
//This is to fix the arcade sprite when the sprite is created in the update function instead of the create function.
//This basically realligns the sprite body's hitbox so it doesn't get out of sync with the sprite game object.
//You only need to call this once, and only after you create the sprite with this.scene.add.sprite(...);
//This also works with images.
//If you need to set the size, scale, and offset of the body on creation, do it after you create the sprite and THEN call this function.
/*Ex:
var s = this.scene.physics.add.sprite(50, 50, "spritesheethere", 0);
s.body.setOffset(5, 5);
s.setScale(2, 1);
s.body.setSize(10, 19, false);
arcadeSpriteFix(s);
*/
function arcadeSpriteFix(arcadeSprite) {
var newx = arcadeSprite.x - (0.5 * arcadeSprite.displayWidth) + (arcadeSprite.scaleX * arcadeSprite.body.offset.x);
var newy = arcadeSprite.y - (0.5 * arcadeSprite.displayHeight) + (arcadeSprite.scaleY * arcadeSprite.body.offset.y);
arcadeSprite.body.position.x = newx;
arcadeSprite.body.position.y = newy;
arcadeSprite.body.prev.x = newx;
arcadeSprite.body.prev.y = newy;
arcadeSprite.body.prevFrame.x = newx;
arcadeSprite.body.prevFrame.y = newy;
arcadeSprite.body.transform.scaleX = arcadeSprite.scaleX;
arcadeSprite.body.transform.scaleY = arcadeSprite.scaleY;
arcadeSprite.body.width = Math.floor(arcadeSprite.body.width * arcadeSprite.scaleX);
arcadeSprite.body.height = Math.floor(arcadeSprite.body.height * arcadeSprite.scaleY);
}
I’ll be honest, I actually experienced a different bug than the one you posted, and this function fixed my problem. When I applied it to your example, it fixed it as well. In my scenario, I was creating a sprite in the update loop (like you), but I was just doing “this.scene.physics.add.sprite(50, 50, “slime”, 0)”, and my bug was always moving my sprite.x/y to the upper left hand corner.
In my scenario, when the sprite gets created in the update loop, the sprite.x/y coordinates are initially correct (center coordinates of the sprite drawing), and the sprite.body.x/y coordinates are initially correct as well (top left corner of the rectangular body). However, the sprite.body.prevFrame.x/y are NOT correct (the previous frame’s top left corner of the rectangular body).
What happened is that the engine sees that the body’s prevFrame position is different than the current position, so it thinks that the body has moved. Because the engine sees that the body has moved, it applies the movement to the sprite.x/y as well. In the source code, it does this in src > physics > arcade > Body.js > postUpdate(). Here is the part of the function from the source code (Phaser version 3.23.0):
postUpdate: function () {
var dx = this.position.x - this.prevFrame.x;
var dy = this.position.y - this.prevFrame.y;
if (this.moves)
{
...
this.gameObject.x += dx;
this.gameObject.y += dy;
}
...
}
I’m not sure HOW the prevFrame got out of sync, but it did. So in my scenario, I just had to recalculate the position of the of the body based on the scale, offset, and size, and then apply the recalculation to the prevFrame. This is basically what the “arcadeSpriteFix()” function does.
Again, not exactly sure why it fixes your scenario too…but it does haha!