Improve whale hunting mechanics with multi-hit system
- Changed to single whale spawning (one at a time) - Added crosshair shake effect for increased difficulty (2px random shake) - Implemented whale health system (3 hits to kill) - Added dynamic health bar above whales (green -> yellow -> red) - Visual feedback on hits: red flash, whale shake animation - Health bar updates in real-time as whale takes damage - New whales spawn 1.5 seconds after previous whale dies or leaves - Separated hitWhale() and killWhale() functions for damage vs death - Shows health status messages on each hit - Much more challenging and engaging hunting gameplay 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -9,10 +9,11 @@ export default class HuntingScene extends Phaser.Scene {
|
||||
this.inventory = data.inventory || { whaleOil: 0, fuel: 100, penguins: 0 };
|
||||
this.whalesHunted = 0;
|
||||
this.harpoons = [];
|
||||
this.whales = [];
|
||||
this.currentWhale = null;
|
||||
this.crosshairX = 400;
|
||||
this.crosshairY = 300;
|
||||
this.crosshairSpeed = 5;
|
||||
this.crosshairShakeAmount = 2; // Pixels of shake
|
||||
this.useKeyboard = false; // Toggle between mouse and keyboard
|
||||
}
|
||||
|
||||
@@ -26,15 +27,7 @@ export default class HuntingScene extends Phaser.Scene {
|
||||
this.createCrosshair();
|
||||
this.createInstructions();
|
||||
|
||||
// Spawn whales periodically
|
||||
this.time.addEvent({
|
||||
delay: 3000,
|
||||
callback: this.spawnWhale,
|
||||
callbackScope: this,
|
||||
loop: true
|
||||
});
|
||||
|
||||
// Spawn initial whale
|
||||
// Spawn single whale
|
||||
this.spawnWhale();
|
||||
|
||||
// Input setup
|
||||
@@ -52,14 +45,16 @@ export default class HuntingScene extends Phaser.Scene {
|
||||
this.updateCrosshairMouse();
|
||||
}
|
||||
|
||||
// Update crosshair sprite position
|
||||
this.crosshair.setPosition(this.crosshairX, this.crosshairY);
|
||||
// Update crosshair sprite position with shake
|
||||
const shakeX = (Math.random() - 0.5) * this.crosshairShakeAmount * 2;
|
||||
const shakeY = (Math.random() - 0.5) * this.crosshairShakeAmount * 2;
|
||||
this.crosshair.setPosition(this.crosshairX + shakeX, this.crosshairY + shakeY);
|
||||
|
||||
// Update harpoons
|
||||
this.updateHarpoons();
|
||||
|
||||
// Update whales
|
||||
this.updateWhales();
|
||||
// Update whale
|
||||
this.updateWhale();
|
||||
|
||||
// Check collisions
|
||||
this.checkCollisions();
|
||||
@@ -232,12 +227,17 @@ export default class HuntingScene extends Phaser.Scene {
|
||||
}
|
||||
|
||||
spawnWhale() {
|
||||
// Don't spawn if there's already a whale
|
||||
if (this.currentWhale && this.currentWhale.getData('alive')) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Random position and direction
|
||||
const fromLeft = Math.random() > 0.5;
|
||||
const x = fromLeft ? -50 : 850;
|
||||
const y = 150 + Math.random() * 300;
|
||||
const direction = fromLeft ? 1 : -1;
|
||||
const speed = 1 + Math.random() * 1.5;
|
||||
const speed = 0.8 + Math.random() * 0.7; // Slightly slower for single whale
|
||||
|
||||
// Create whale body
|
||||
const whale = this.add.container(x, y);
|
||||
@@ -258,27 +258,38 @@ export default class HuntingScene extends Phaser.Scene {
|
||||
0x1a1a1a
|
||||
);
|
||||
|
||||
whale.add([body, tail, fin]);
|
||||
// Health bar background
|
||||
const healthBg = this.add.rectangle(0, -35, 60, 6, 0x000000);
|
||||
// Health bar (will be updated as whale takes damage)
|
||||
const healthBar = this.add.rectangle(0, -35, 60, 6, 0x00ff00);
|
||||
|
||||
whale.add([body, tail, fin, healthBg, healthBar]);
|
||||
whale.setData('direction', direction);
|
||||
whale.setData('speed', speed);
|
||||
whale.setData('alive', true);
|
||||
whale.setData('health', 3); // Requires 3 hits
|
||||
whale.setData('maxHealth', 3);
|
||||
whale.setData('bodyWidth', 80);
|
||||
whale.setData('bodyHeight', 40);
|
||||
whale.setData('healthBar', healthBar);
|
||||
|
||||
// Flip if moving right
|
||||
if (direction > 0) {
|
||||
whale.setScale(-1, 1);
|
||||
}
|
||||
|
||||
this.whales.push(whale);
|
||||
this.currentWhale = whale;
|
||||
}
|
||||
|
||||
updateWhales() {
|
||||
for (let i = this.whales.length - 1; i >= 0; i--) {
|
||||
const whale = this.whales[i];
|
||||
updateWhale() {
|
||||
if (!this.currentWhale) {
|
||||
return;
|
||||
}
|
||||
|
||||
const whale = this.currentWhale;
|
||||
|
||||
if (!whale.getData('alive')) {
|
||||
continue;
|
||||
return;
|
||||
}
|
||||
|
||||
// Move whale
|
||||
@@ -286,11 +297,14 @@ export default class HuntingScene extends Phaser.Scene {
|
||||
const speed = whale.getData('speed');
|
||||
whale.x += direction * speed;
|
||||
|
||||
// Remove if off screen
|
||||
// If whale goes off screen, spawn a new one
|
||||
if (whale.x < -100 || whale.x > 900) {
|
||||
whale.destroy();
|
||||
this.whales.splice(i, 1);
|
||||
}
|
||||
this.currentWhale = null;
|
||||
// Spawn new whale after a short delay
|
||||
this.time.delayedCall(1500, () => {
|
||||
this.spawnWhale();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -333,6 +347,12 @@ export default class HuntingScene extends Phaser.Scene {
|
||||
}
|
||||
|
||||
checkCollisions() {
|
||||
if (!this.currentWhale || !this.currentWhale.getData('alive')) {
|
||||
return;
|
||||
}
|
||||
|
||||
const whale = this.currentWhale;
|
||||
|
||||
for (let h = this.harpoons.length - 1; h >= 0; h--) {
|
||||
const harpoon = this.harpoons[h];
|
||||
|
||||
@@ -340,13 +360,6 @@ export default class HuntingScene extends Phaser.Scene {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (let w = this.whales.length - 1; w >= 0; w--) {
|
||||
const whale = this.whales[w];
|
||||
|
||||
if (!whale.getData('alive')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Simple collision detection
|
||||
const distance = Phaser.Math.Distance.Between(
|
||||
harpoon.x, harpoon.y,
|
||||
@@ -360,11 +373,61 @@ export default class HuntingScene extends Phaser.Scene {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
hitWhale(whale, harpoon) {
|
||||
whale.setData('alive', false);
|
||||
harpoon.setData('active', false);
|
||||
harpoon.destroy();
|
||||
|
||||
// Reduce whale health
|
||||
let health = whale.getData('health');
|
||||
health -= 1;
|
||||
whale.setData('health', health);
|
||||
|
||||
// Update health bar
|
||||
const healthBar = whale.getData('healthBar');
|
||||
const maxHealth = whale.getData('maxHealth');
|
||||
const healthPercent = health / maxHealth;
|
||||
healthBar.setDisplaySize(60 * healthPercent, 6);
|
||||
|
||||
// Change health bar color based on health
|
||||
if (healthPercent > 0.6) {
|
||||
healthBar.setFillStyle(0x00ff00); // Green
|
||||
} else if (healthPercent > 0.3) {
|
||||
healthBar.setFillStyle(0xffff00); // Yellow
|
||||
} else {
|
||||
healthBar.setFillStyle(0xff0000); // Red
|
||||
}
|
||||
|
||||
// Hit flash effect
|
||||
const hitFlash = this.add.circle(whale.x, whale.y, 50, 0xff0000, 0.6);
|
||||
this.tweens.add({
|
||||
targets: hitFlash,
|
||||
alpha: 0,
|
||||
scale: 1.5,
|
||||
duration: 300,
|
||||
onComplete: () => hitFlash.destroy()
|
||||
});
|
||||
|
||||
// Whale damaged animation (shake)
|
||||
this.tweens.add({
|
||||
targets: whale,
|
||||
x: whale.x + 5,
|
||||
yoyo: true,
|
||||
repeat: 2,
|
||||
duration: 50
|
||||
});
|
||||
|
||||
if (health <= 0) {
|
||||
// Whale is dead!
|
||||
this.killWhale(whale);
|
||||
} else {
|
||||
// Whale is still alive
|
||||
this.showMessage(`Hit! Whale health: ${health}/${maxHealth}`);
|
||||
}
|
||||
}
|
||||
|
||||
killWhale(whale) {
|
||||
whale.setData('alive', false);
|
||||
|
||||
// Check if enough fuel to process the whale
|
||||
if (this.inventory.fuel < 2) {
|
||||
@@ -376,11 +439,15 @@ export default class HuntingScene extends Phaser.Scene {
|
||||
duration: 1000,
|
||||
onComplete: () => {
|
||||
whale.destroy();
|
||||
this.currentWhale = null;
|
||||
// Spawn new whale
|
||||
this.time.delayedCall(1500, () => {
|
||||
this.spawnWhale();
|
||||
});
|
||||
}
|
||||
});
|
||||
harpoon.destroy();
|
||||
|
||||
this.showMessage('Whale hit but no fuel to process it! Need 2 fuel to cook whale oil.');
|
||||
this.showMessage('Whale killed but no fuel to process it! Need 2 fuel to cook whale oil.');
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -393,12 +460,14 @@ export default class HuntingScene extends Phaser.Scene {
|
||||
duration: 1000,
|
||||
onComplete: () => {
|
||||
whale.destroy();
|
||||
this.currentWhale = null;
|
||||
// Spawn new whale after delay
|
||||
this.time.delayedCall(1500, () => {
|
||||
this.spawnWhale();
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Remove harpoon
|
||||
harpoon.destroy();
|
||||
|
||||
// Consume fuel for processing
|
||||
this.inventory.fuel -= 2;
|
||||
|
||||
@@ -408,7 +477,7 @@ export default class HuntingScene extends Phaser.Scene {
|
||||
this.updateStats();
|
||||
|
||||
// Show success message
|
||||
this.showMessage(`Whale hunted! +1 Whale Oil, -2 Fuel (Oil: ${this.inventory.whaleOil}, Fuel: ${this.inventory.fuel})`);
|
||||
this.showMessage(`Whale killed! +1 Whale Oil, -2 Fuel (Oil: ${this.inventory.whaleOil}, Fuel: ${this.inventory.fuel})`);
|
||||
|
||||
// Success flash
|
||||
const flash = this.add.rectangle(400, 300, 800, 600, 0xffffff, 0.3);
|
||||
|
||||
Reference in New Issue
Block a user