From 71ce5a00e935e9475f9f54d2980254c876a3237c Mon Sep 17 00:00:00 2001 From: Admin Date: Sat, 19 Sep 2026 06:44:15 +0000 Subject: [PATCH] fix: sync decoupled squirrel collision body --- src/main.js | 54 ++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 37 insertions(+), 17 deletions(-) diff --git a/src/main.js b/src/main.js index ef79e39..af4fa15 100644 --- a/src/main.js +++ b/src/main.js @@ -102,7 +102,7 @@ class ForestScene extends Phaser.Scene { if (this.mushrooms < this.totalMushrooms || this.finished) return; this.finished = true; this.player.setVelocityX(0); - this.player.setTint(0xfff2bd); + this.playerVisual.setTint(0xfff2bd); this.showEnding(); }); } @@ -198,6 +198,11 @@ class ForestScene extends Phaser.Scene { createTextures() { const g = this.make.graphics({ add: false }); + g.clear(); + g.fillStyle(0xffffff, 1); + g.fillRect(0, 0, 44, 72); + g.generateTexture('player-body', 44, 72); + g.clear(); g.fillStyle(0x6e482b, 1); g.fillEllipse(24, 30, 35, 24); @@ -447,14 +452,28 @@ class ForestScene extends Phaser.Scene { } createPlayer() { - this.player = this.physics.add.sprite(160, 520, 'player-game', 0); - this.player.setScale(0.42); + // Keep physics independent from animation artwork. The body is a simple, + // stable capsule-like rectangle while the squirrel art follows it. + this.player = this.physics.add.sprite(160, 520, 'player-body'); + this.player.setAlpha(0); this.player.setCollideWorldBounds(true); this.player.setDragX(900); this.player.setMaxVelocity(330, 760); - this.player.body.setSize(95, 145, true); - this.player.body.setOffset(92, 65); - this.player.play('squirrel-idle'); + this.player.body.setSize(40, 68, true); + + this.playerVisual = this.add.sprite(160, 520, 'player-game', 0); + this.playerVisual.setScale(0.42); + // Every normalized player frame has its paw baseline at source y=209. + // Pin that exact baseline to the physics body's bottom. + this.playerVisual.setOrigin(0.5, 209 / 220); + this.playerVisual.setDepth(12); + this.playerVisual.play('squirrel-idle'); + this.syncPlayerVisual(); + } + + syncPlayerVisual() { + if (!this.player?.body || !this.playerVisual) return; + this.playerVisual.setPosition(this.player.x, this.player.body.bottom); } createCollectibles() { @@ -681,7 +700,7 @@ class ForestScene extends Phaser.Scene { if (!this.player?.body) return; if (this.player.body.blocked.down || this.player.body.touching.down) { this.player.setVelocityY(-520); - this.player.play('squirrel-jump', true); + this.playerVisual.play('squirrel-jump', true); } } @@ -750,10 +769,10 @@ class ForestScene extends Phaser.Scene { if (left && !right) { this.player.setAccelerationX(-1050); - this.player.setFlipX(true); + this.playerVisual.setFlipX(true); } else if (right && !left) { this.player.setAccelerationX(1050); - this.player.setFlipX(false); + this.playerVisual.setFlipX(false); } else { this.player.setAccelerationX(0); } @@ -762,32 +781,33 @@ class ForestScene extends Phaser.Scene { if (grounded && !this.wasGrounded) { this.landing = true; - this.player.play('squirrel-land', true); - this.player.once('animationcomplete-squirrel-land', () => { + this.playerVisual.play('squirrel-land', true); + this.playerVisual.once('animationcomplete-squirrel-land', () => { this.landing = false; }); } if (grounded) { - this.player.setAngle(0); + this.playerVisual.setAngle(0); if (!this.landing) { if (Math.abs(this.player.body.velocity.x) > 35) { - this.player.play('squirrel-run', true); + this.playerVisual.play('squirrel-run', true); } else { - this.player.play('squirrel-idle', true); + this.playerVisual.play('squirrel-idle', true); } } } else if (this.player.body.velocity.y < 0) { this.landing = false; this.player.play('squirrel-jump', true); - this.player.setAngle(Phaser.Math.Clamp(this.player.body.velocity.x * 0.012, -5, 5)); + this.playerVisual.setAngle(Phaser.Math.Clamp(this.player.body.velocity.x * 0.012, -5, 5)); } else { this.landing = false; - this.player.play('squirrel-fall', true); - this.player.setAngle(Phaser.Math.Clamp(this.player.body.velocity.x * 0.012, -5, 5)); + this.playerVisual.play('squirrel-fall', true); + this.playerVisual.setAngle(Phaser.Math.Clamp(this.player.body.velocity.x * 0.012, -5, 5)); } this.wasGrounded = grounded; + this.syncPlayerVisual(); this.acornGroup.children.iterate(acorn => { if (!acorn?.active) return;