deploy: update image to latest

This commit is contained in:
Thomas Richter
2026-02-05 23:31:23 +01:00
parent 283c88134a
commit fd3517da85
3 changed files with 258 additions and 4 deletions

View File

@@ -1,6 +1,6 @@
{
"name": "whalehunting-game",
"version": "1.1.0",
"version": "1.2.0",
"description": "A Monkey Island-style point-and-click adventure game about 18th century whaling",
"main": "src/main.js",
"scripts": {

View File

@@ -11,6 +11,9 @@ export default class DeepSeaHuntingScene extends Phaser.Scene {
this.inventory = data.inventory || { whaleOil: 0, fuel: 100, penguins: 0 };
this.whalesHunted = 0;
this.currentWhale = null;
this.harpoons = [];
this.crosshairX = 400;
this.crosshairY = 300;
}
create() {
@@ -27,11 +30,248 @@ export default class DeepSeaHuntingScene extends Phaser.Scene {
// Fullscreen button
createFullscreenButton(this);
// Create crosshair
this.createCrosshair();
// Setup input
this.setupInput();
// Spawn first whale
this.spawnWhale();
// Detect mobile
this.isMobile = /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent);
// Show initial message
this.showMessage('The leviathan approaches... Watch the depths!');
const shootMessage = this.isMobile ? 'The leviathan approaches... Tap to harpoon!' : 'The leviathan approaches... Click to harpoon!';
this.showMessage(shootMessage);
}
update() {
// Update crosshair position
this.crosshairX = this.input.x;
this.crosshairY = this.input.y;
this.crosshair.setPosition(this.crosshairX, this.crosshairY);
// Update harpoons
this.updateHarpoons();
// Check collisions
this.checkCollisions();
}
createCrosshair() {
const graphics = this.add.graphics();
graphics.lineStyle(3, 0x4a9fff, 1);
// Crosshair lines
graphics.beginPath();
graphics.moveTo(-20, 0);
graphics.lineTo(-5, 0);
graphics.moveTo(5, 0);
graphics.lineTo(20, 0);
graphics.moveTo(0, -20);
graphics.lineTo(0, -5);
graphics.moveTo(0, 5);
graphics.lineTo(0, 20);
graphics.strokePath();
// Center circle
graphics.lineStyle(2, 0x4a9fff, 1);
graphics.strokeCircle(0, 0, 3);
// Convert to texture and create sprite
graphics.generateTexture('crosshair_deep', 40, 40);
graphics.destroy();
this.crosshair = this.add.sprite(400, 300, 'crosshair_deep');
this.crosshair.setDepth(100);
}
setupInput() {
// Mouse/touch click to shoot
this.input.on('pointerdown', () => {
this.shootHarpoon();
});
// Space to shoot
this.spaceKey = this.input.keyboard.addKey(Phaser.Input.Keyboard.KeyCodes.SPACE);
this.spaceKey.on('down', () => {
this.shootHarpoon();
});
// Hide cursor on desktop
if (!/Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent)) {
this.input.setDefaultCursor('none');
}
}
shootHarpoon() {
// Create harpoon at crosshair position
const harpoon = this.add.container(this.crosshairX, this.crosshairY);
// Harpoon shaft with glow effect
const glow = this.add.rectangle(0, 0, 8, 30, 0x4a9fff, 0.3);
const shaft = this.add.rectangle(0, 0, 4, 25, 0x6abfff);
const tip = this.add.triangle(0, -15, 0, -8, -5, 0, 5, 0, 0x4a9fff);
harpoon.add([glow, shaft, tip]);
harpoon.setData('active', true);
harpoon.setDepth(50);
this.harpoons.push(harpoon);
// Flash effect
const flash = this.add.circle(this.crosshairX, this.crosshairY, 15, 0x4a9fff, 0.6);
this.tweens.add({
targets: flash,
alpha: 0,
scale: 2,
duration: 200,
onComplete: () => flash.destroy()
});
}
updateHarpoons() {
for (let i = this.harpoons.length - 1; i >= 0; i--) {
const harpoon = this.harpoons[i];
if (!harpoon.getData('active')) {
continue;
}
// Move harpoon up
harpoon.y -= 10;
// Remove if off screen
if (harpoon.y < -30) {
harpoon.destroy();
this.harpoons.splice(i, 1);
}
}
}
checkCollisions() {
if (!this.currentWhale || !this.currentWhale.getData('alive')) {
return;
}
const whale = this.currentWhale;
for (let i = this.harpoons.length - 1; i >= 0; i--) {
const harpoon = this.harpoons[i];
if (!harpoon.getData('active')) {
continue;
}
const distance = Phaser.Math.Distance.Between(
harpoon.x, harpoon.y,
whale.x, whale.y
);
if (distance < 90) {
this.hitWhale(whale, harpoon, i);
break;
}
}
}
hitWhale(whale, harpoon, harpoonIndex) {
harpoon.setData('active', false);
harpoon.destroy();
this.harpoons.splice(harpoonIndex, 1);
// Reduce 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(120 * healthPercent, 10);
// Change color based on health
if (healthPercent > 0.6) {
healthBar.setFillStyle(0x00ff00);
} else if (healthPercent > 0.3) {
healthBar.setFillStyle(0xffff00);
} else {
healthBar.setFillStyle(0xff0000);
}
// Hit flash
const hitFlash = this.add.circle(whale.x, whale.y, 60, 0x4a9fff, 0.5);
this.tweens.add({
targets: hitFlash,
alpha: 0,
scale: 1.5,
duration: 300,
onComplete: () => hitFlash.destroy()
});
if (health <= 0) {
this.killWhale(whale);
} else {
this.showMessage(`Hit! Leviathan health: ${health}/${maxHealth}`);
}
}
killWhale(whale) {
whale.setData('alive', false);
// Stop the path tween
this.tweens.killTweensOf(whale.getData('pathData'));
// Check fuel
if (this.inventory.fuel < 3) {
this.tweens.add({
targets: whale,
alpha: 0,
y: whale.y + 100,
duration: 1500,
onComplete: () => {
whale.destroy();
this.currentWhale = null;
this.time.delayedCall(2000, () => this.spawnWhale());
}
});
this.showMessage('Leviathan slain but no fuel to process! Need 3 fuel.');
return;
}
// Death animation
this.tweens.add({
targets: whale,
alpha: 0,
y: whale.y + 100,
angle: whale.rotation * (180 / Math.PI) + 90,
duration: 1500,
onComplete: () => {
whale.destroy();
this.currentWhale = null;
this.time.delayedCall(2000, () => this.spawnWhale());
}
});
// Rewards - leviathans give more oil
this.inventory.fuel -= 3;
this.inventory.whaleOil += 3;
this.whalesHunted++;
this.updateStats();
this.showMessage(`Leviathan slain! +3 Oil, -3 Fuel`);
// Success flash
const flash = this.add.rectangle(400, 300, 800, 600, 0x4a9fff, 0.3);
this.tweens.add({
targets: flash,
alpha: 0,
duration: 500,
onComplete: () => flash.destroy()
});
}
createDeepOceanAtmosphere() {
@@ -124,10 +364,22 @@ export default class DeepSeaHuntingScene extends Phaser.Scene {
ease: 'Sine.inOut'
});
whale.add([tail, body, belly, dorsalFin, eyeGlow, eye]);
// Health bar background
const healthBg = this.add.rectangle(0, -55, 120, 10, 0x000000);
healthBg.setStrokeStyle(1, 0x4a9fff);
// Health bar
const healthBar = this.add.rectangle(0, -55, 120, 10, 0x00ff00);
whale.add([tail, body, belly, dorsalFin, eyeGlow, eye, healthBg, healthBar]);
whale.setRotation(angle);
whale.setDepth(10);
// Set whale data
whale.setData('alive', true);
whale.setData('health', 5); // Leviathans are tougher - 5 hits
whale.setData('maxHealth', 5);
whale.setData('healthBar', healthBar);
this.currentWhale = whale;
// Subtle bobbing animation during movement
@@ -170,6 +422,7 @@ export default class DeepSeaHuntingScene extends Phaser.Scene {
// Store path progress
const pathData = { t: 0 };
whale.setData('pathData', pathData);
// Animate along curved path
this.tweens.add({
@@ -279,6 +532,7 @@ export default class DeepSeaHuntingScene extends Phaser.Scene {
}
returnToMap() {
this.input.setDefaultCursor('default');
this.scene.start('MapScene', { inventory: this.inventory });
}
}

View File

@@ -84,7 +84,7 @@ export default class IntroScene extends Phaser.Scene {
createFullscreenButton(this);
// Version display
this.add.text(790, 590, 'v1.1.0', {
this.add.text(790, 590, 'v1.2.0', {
fontSize: fontSize(12),
fill: '#ffffff',
alpha: 0.5