From 6c9d9a149d7a191fcbbb76db8c56b7bf9ca35ac1 Mon Sep 17 00:00:00 2001 From: Thomas Richter Date: Mon, 15 Dec 2025 03:54:44 +0100 Subject: [PATCH] Decouple UI controls from ocean camera movement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Set scrollFactor(0) on all UI elements to fix them to screen - HUD, crosshair, harpoons, buttons, and messages now ignore camera sway - Only whale and ocean background move with camera - Updated collision detection to convert whale world position to screen space - Harpoons shoot straight relative to screen, not world - Creates stable aiming interface while ocean/whale sway dynamically - Much better gameplay feel with separated control and world layers 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- src/scenes/HuntingScene.js | 35 +++++++++++++++++++++++++---------- 1 file changed, 25 insertions(+), 10 deletions(-) diff --git a/src/scenes/HuntingScene.js b/src/scenes/HuntingScene.js index 4b436c3..71c9146 100644 --- a/src/scenes/HuntingScene.js +++ b/src/scenes/HuntingScene.js @@ -153,6 +153,7 @@ export default class HuntingScene extends Phaser.Scene { this.crosshair = this.add.sprite(400, 300, 'crosshair'); this.crosshair.setDepth(100); + this.crosshair.setScrollFactor(0); // Fixed to screen, ignores camera movement } createOceanWaves() { @@ -175,31 +176,36 @@ export default class HuntingScene extends Phaser.Scene { } createHUD() { - // HUD background + // HUD background (fixed to screen, ignores camera movement) const hudBg = this.add.rectangle(400, 30, 780, 50, 0x000000, 0.7); hudBg.setStrokeStyle(2, 0xffffff); + hudBg.setScrollFactor(0); - // Stats + // Stats (fixed to screen) this.statsText = this.add.text(20, 15, '', { fontSize: '16px', fill: '#fff' }); + this.statsText.setScrollFactor(0); - // Control mode indicator + // Control mode indicator (fixed to screen) this.controlModeText = this.add.text(400, 15, 'Controls: MOUSE (TAB to switch)', { fontSize: '16px', fill: '#ffff00' }).setOrigin(0.5, 0); + this.controlModeText.setScrollFactor(0); - // Return button + // Return button (fixed to screen) const returnBtn = this.add.rectangle(750, 30, 80, 35, 0x8B0000); returnBtn.setInteractive({ useHandCursor: true }); returnBtn.setStrokeStyle(2, 0xffffff); + returnBtn.setScrollFactor(0); - this.add.text(750, 30, 'RETURN', { + const returnText = this.add.text(750, 30, 'RETURN', { fontSize: '14px', fill: '#fff' }).setOrigin(0.5); + returnText.setScrollFactor(0); returnBtn.on('pointerdown', () => { this.returnToMap(); @@ -223,6 +229,7 @@ export default class HuntingScene extends Phaser.Scene { backgroundColor: '#000000', padding: { x: 10, y: 5 } }).setOrigin(0.5); + this.messageText.setScrollFactor(0); // Fixed to screen } showMessage(text) { @@ -312,15 +319,17 @@ export default class HuntingScene extends Phaser.Scene { } shootHarpoon() { - // Create harpoon at crosshair position + // Create harpoon at crosshair position (fixed to screen) const harpoon = this.add.rectangle(this.crosshairX, this.crosshairY, 4, 20, 0x8B4513); harpoon.setData('speed', 8); harpoon.setData('active', true); + harpoon.setScrollFactor(0); // Fixed to screen this.harpoons.push(harpoon); - // Sound effect simulation (flash) + // Sound effect simulation (flash) - fixed to screen const flash = this.add.circle(this.crosshairX, this.crosshairY, 10, 0xffff00, 0.8); + flash.setScrollFactor(0); this.tweens.add({ targets: flash, alpha: 0, @@ -363,10 +372,15 @@ export default class HuntingScene extends Phaser.Scene { continue; } - // Simple collision detection + // Collision detection accounting for camera offset + // Harpoon is in screen space (scrollFactor 0) + // Whale is in world space, so convert to screen space + const whaleScreenX = whale.x - this.cameras.main.scrollX; + const whaleScreenY = whale.y - this.cameras.main.scrollY; + const distance = Phaser.Math.Distance.Between( harpoon.x, harpoon.y, - whale.x, whale.y + whaleScreenX, whaleScreenY ); if (distance < 40) { @@ -482,8 +496,9 @@ export default class HuntingScene extends Phaser.Scene { // Show success message this.showMessage(`Whale killed! +1 Whale Oil, -2 Fuel (Oil: ${this.inventory.whaleOil}, Fuel: ${this.inventory.fuel})`); - // Success flash + // Success flash (fixed to screen) const flash = this.add.rectangle(400, 300, 800, 600, 0xffffff, 0.3); + flash.setScrollFactor(0); this.tweens.add({ targets: flash, alpha: 0,