Decouple UI controls from ocean camera movement

- 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 <noreply@anthropic.com>
This commit is contained in:
Thomas Richter
2025-12-15 03:54:44 +01:00
parent cfed5503ac
commit 6c9d9a149d

View File

@@ -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,