Add whale swimming and diving mechanics

- Whales now swim across screen with directional movement
- Random horizontal speed (0.5-1.0) and vertical drift
- Bounces off screen edges and flips direction
- Diving behavior: dives every 3-7 seconds for 2 seconds
- Fades to 20% opacity when diving, full when surfaced
- Cannot be hit while diving (invulnerable)
- Shows dive/surface messages
- Combines swimming with bobbing animation
- Much more dynamic and challenging hunting
- Whales are now moving targets instead of stationary

🤖 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 04:26:23 +01:00
parent 16ef3dd2aa
commit bbd791bb68

View File

@@ -281,10 +281,17 @@ export default class HuntingScene extends Phaser.Scene {
whale.setData('bodyWidth', 80);
whale.setData('bodyHeight', 40);
whale.setData('healthBar', healthBar);
whale.setData('baseX', x); // Store original position for bobbing
whale.setData('baseY', y);
whale.setData('bobTime', 0); // Timer for bobbing animation
// Swimming movement
whale.setData('swimSpeedX', direction * (0.5 + Math.random() * 0.5)); // 0.5-1.0 speed
whale.setData('swimSpeedY', (Math.random() - 0.5) * 0.3); // Slight vertical drift
// Diving mechanics
whale.setData('diving', false);
whale.setData('diveTimer', 0);
whale.setData('nextDiveTime', 3 + Math.random() * 4); // Dive every 3-7 seconds
// Flip if moving right
if (direction > 0) {
whale.setScale(-1, 1);
@@ -304,20 +311,66 @@ export default class HuntingScene extends Phaser.Scene {
return;
}
// Gentle bobbing movement
// Update dive timer
let diveTimer = whale.getData('diveTimer');
diveTimer += 0.016; // ~60fps
whale.setData('diveTimer', diveTimer);
// Handle diving behavior
const diving = whale.getData('diving');
const nextDiveTime = whale.getData('nextDiveTime');
if (!diving && diveTimer >= nextDiveTime) {
// Start diving
this.startDive(whale);
} else if (diving && diveTimer >= nextDiveTime + 2) {
// Resurface after 2 seconds
this.endDive(whale);
}
// Swimming movement
const swimSpeedX = whale.getData('swimSpeedX');
const swimSpeedY = whale.getData('swimSpeedY');
whale.x += swimSpeedX;
whale.y += swimSpeedY;
// Bobbing animation (on top of swimming)
let bobTime = whale.getData('bobTime');
bobTime += 0.02;
whale.setData('bobTime', bobTime);
const baseX = whale.getData('baseX');
const baseY = whale.getData('baseY');
const bobOffsetX = Math.sin(bobTime) * 15; // Reduced from 30 since we're swimming
const bobOffsetY = Math.cos(bobTime * 0.7) * 10; // Reduced from 20
// Horizontal and vertical oscillation
const offsetX = Math.sin(bobTime) * 30; // 30 pixels horizontal movement
const offsetY = Math.cos(bobTime * 0.7) * 20; // 20 pixels vertical movement
whale.x += bobOffsetX;
whale.y += bobOffsetY;
whale.x = baseX + offsetX;
whale.y = baseY + offsetY;
// Bounce off screen edges
if (whale.x < 50 || whale.x > 750) {
whale.setData('swimSpeedX', -swimSpeedX);
whale.setScale(whale.scaleX * -1, whale.scaleY); // Flip whale
}
if (whale.y < 100 || whale.y > 550) {
whale.setData('swimSpeedY', -swimSpeedY);
}
// Update opacity based on diving
if (diving) {
whale.alpha = Math.max(0.2, whale.alpha - 0.05);
}
}
startDive(whale) {
whale.setData('diving', true);
this.showMessage('Whale is diving!');
}
endDive(whale) {
whale.setData('diving', false);
whale.setData('diveTimer', 0);
whale.setData('nextDiveTime', 3 + Math.random() * 4); // Next dive in 3-7 seconds
whale.alpha = 1; // Full opacity
this.showMessage('Whale surfaced!');
}
shootHarpoon() {
@@ -367,6 +420,11 @@ export default class HuntingScene extends Phaser.Scene {
const whale = this.currentWhale;
// Can't hit whale while diving
if (whale.getData('diving')) {
return;
}
for (let h = this.harpoons.length - 1; h >= 0; h--) {
const harpoon = this.harpoons[h];