diff --git a/src/game-v4.js b/src/game-v4.js index 91a2124..bbd8b4c 100644 --- a/src/game-v4.js +++ b/src/game-v4.js @@ -98,7 +98,7 @@ class GameScene extends Phaser.Scene { this.player.setDepth(6).setCollideWorldBounds(true).setDisplaySize(66, 126); this.player.body.setAllowGravity(false); this.player.body.setCircle(44, 20, 84); - this.player.play('player-idle'); + this.player.setFrame(0); this.pirates = this.physics.add.group(); this.playerShots = this.physics.add.group(); @@ -255,11 +255,11 @@ class GameScene extends Phaser.Scene { } createAnimations() { - if (!this.anims.exists('player-idle')) { + if (!this.anims.exists('player-forward')) { this.anims.create({ - key: 'player-idle', + key: 'player-forward', frames: this.anims.generateFrameNumbers('player-airship', { start: 0, end: 3 }), - frameRate: 5, + frameRate: 6, repeat: -1, }); } @@ -449,6 +449,18 @@ class GameScene extends Phaser.Scene { this.player.angle += PLAYER_TURN_RATE * turnStrength * directionSign * turnInput * dt; + const forwardThrust = clamp(this.playerSpeed / PLAYER_MAX_SPEED, 0, 1); + if (forwardThrust > 0.06) { + if (!this.player.anims.isPlaying || this.player.anims.currentAnim?.key !== 'player-forward') { + this.player.play('player-forward'); + } + this.player.anims.timeScale = 0.65 + forwardThrust * 1.35; + } else { + if (this.player.anims.isPlaying) this.player.anims.stop(); + this.player.setFrame(0); + this.player.anims.timeScale = 1; + } + const h = headingRad(this.player); this.player.setVelocity(Math.cos(h) * this.playerSpeed, Math.sin(h) * this.playerSpeed); diff --git a/tests/wiring.test.mjs b/tests/wiring.test.mjs index d744a77..2299bda 100644 --- a/tests/wiring.test.mjs +++ b/tests/wiring.test.mjs @@ -194,7 +194,7 @@ test('player and pirate broadsides use the cannonball image asset', async () => assert.doesNotMatch(source, /generateTexture\('pirate-shot'/); }); -test('player uses the four-frame north-facing airship sheet with a compact circular body', async () => { +test('player uses the four-frame north-facing sheet as a forward propulsion animation', async () => { const source = await read('src/game-v4.js'); assert.match(source, /import playerAirshipUrl from '.\/assets\/player-airship-4frame\.png\?url'/); @@ -202,8 +202,12 @@ test('player uses the four-frame north-facing airship sheet with a compact circu assert.match(source, /this\.physics\.add\.sprite\(1200, 1550, 'player-airship', 0\)/); assert.match(source, /setDisplaySize\(66, 126\)/); assert.match(source, /this\.player\.body\.setCircle\(44, 20, 84\)/); + assert.match(source, /key: 'player-forward'/); assert.match(source, /generateFrameNumbers\('player-airship', \{ start: 0, end: 3 \}\)/); - assert.doesNotMatch(source, /this\.player\.body\.setSize\(42, 56, true\)/); + assert.match(source, /const forwardThrust = clamp\(this\.playerSpeed \/ PLAYER_MAX_SPEED, 0, 1\)/); + assert.match(source, /this\.player\.anims\.timeScale = 0\.65 \+ forwardThrust \* 1\.35/); + assert.match(source, /this\.player\.setFrame\(0\)/); + assert.doesNotMatch(source, /key: 'player-idle'/); }); test('mobile HUD skips hidden Phaser rendering and throttles DOM state publishing', async () => {