deploy: update image to latest
This commit is contained in:
@@ -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": {
|
||||
|
||||
@@ -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 });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user