Files
whalehunting/src/scenes/ShipDeckScene.js
Thomas Richter b1db1c1402 Center barrel groups within their deck sections
- Calculate total width of each barrel group
- Center fuel barrels in left quarter of deck
- Center oil barrels in right quarter of deck
- More balanced and symmetrical layout

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
2025-12-17 04:00:32 +01:00

293 lines
10 KiB
JavaScript

import Phaser from 'phaser';
export default class ShipDeckScene extends Phaser.Scene {
constructor() {
super({ key: 'ShipDeckScene' });
this.inventory = {
whaleOil: 0,
fuel: 100,
penguins: 0
};
}
init(data) {
// Receive inventory data when returning from other scenes
if (data && data.inventory) {
this.inventory = data.inventory;
}
}
create() {
// Background - ship deck
this.add.rectangle(400, 300, 800, 600, 0x8B4513);
this.add.text(400, 30, 'Ship Deck - The Whaling Vessel', {
fontSize: '24px',
fill: '#fff'
}).setOrigin(0.5);
// Create interactive areas
this.createDeck();
this.createBarrels();
this.createWheel();
this.createInventoryDisplay();
this.createMessageBox();
// Instructions
this.add.text(400, 560, 'Click on objects to interact', {
fontSize: '16px',
fill: '#ffff99'
}).setOrigin(0.5);
}
createDeck() {
// Ship deck dimensions
this.deckCenterX = 400;
this.deckWidth = 700;
this.deckTopY = 200;
this.deckPlankSpacing = 30;
this.deckPlankCount = 8;
// Calculate deck boundaries
this.deckLeftX = this.deckCenterX - this.deckWidth / 2;
this.deckRightX = this.deckCenterX + this.deckWidth / 2;
this.deckBottomY = this.deckTopY + (this.deckPlankCount - 1) * this.deckPlankSpacing;
// Ship deck planks
for (let i = 0; i < this.deckPlankCount; i++) {
this.add.rectangle(this.deckCenterX, this.deckTopY + i * this.deckPlankSpacing, this.deckWidth, 25, 0x654321)
.setStrokeStyle(2, 0x3d2817);
}
}
createBarrels() {
// Initialize barrel arrays
this.fuelBarrels = [];
this.oilBarrels = [];
// Create stacked barrels
this.createFuelBarrels();
this.createOilBarrels();
// Penguin cage (hidden until discovered)
this.penguinCage = this.add.rectangle(650, 350, 80, 80, 0x333333);
this.penguinCage.setInteractive({ useHandCursor: true });
this.penguinCage.setStrokeStyle(3, 0x000000);
this.penguinEmoji = this.add.text(650, 350, '🐧', {
fontSize: '32px'
}).setOrigin(0.5);
// Hide penguin elements if not yet discovered
const discovered = this.inventory.penguins > 0;
this.penguinCage.setVisible(discovered);
this.penguinEmoji.setVisible(discovered);
this.penguinCage.on('pointerdown', () => {
if (this.inventory.penguins > 0) {
this.showMessage(`${this.inventory.penguins} penguins. They're... emergency fuel. Dark times call for dark measures.`);
} else {
this.showMessage('Empty penguin cage. Should we catch some for... fuel?');
}
});
}
createFuelBarrels() {
const barrelCount = Math.ceil(this.inventory.fuel / 10);
if (barrelCount === 0) return;
const barrelWidth = 50;
const barrelHeight = 70;
const horizontalSpacing = 60;
const verticalSpacing = 75;
const barrelsPerRow = 5;
// Calculate group width and center it in left half of deck
const groupWidth = (Math.min(barrelCount, barrelsPerRow) * horizontalSpacing);
const leftHalfCenter = this.deckLeftX + (this.deckWidth / 4);
const baseX = leftHalfCenter - (groupWidth / 2) + (horizontalSpacing / 2);
const baseY = this.deckBottomY + 40;
// Create barrels in stacking pattern
for (let i = 0; i < barrelCount; i++) {
const row = i % barrelsPerRow;
const stackLevel = Math.floor(i / barrelsPerRow);
const x = baseX + (row * horizontalSpacing);
const y = baseY - (stackLevel * verticalSpacing);
const barrel = this.add.rectangle(x, y, barrelWidth, barrelHeight, 0x8B0000);
barrel.setStrokeStyle(3, 0x000000);
this.fuelBarrels.push(barrel);
// Add label only on first barrel
if (i === 0) {
const label = this.add.text(x, y, 'FUEL', {
fontSize: '12px',
fill: '#fff'
}).setOrigin(0.5);
this.fuelBarrels.push(label);
}
}
// Create interactive zone covering all fuel barrels
const zoneWidth = Math.min(barrelCount, barrelsPerRow) * horizontalSpacing + barrelWidth;
const zoneHeight = Math.ceil(barrelCount / barrelsPerRow) * verticalSpacing + barrelHeight;
const zoneX = baseX + ((Math.min(barrelCount, barrelsPerRow) - 1) * horizontalSpacing) / 2;
const zoneY = baseY - ((Math.ceil(barrelCount / barrelsPerRow) - 1) * verticalSpacing) / 2;
const interactiveZone = this.add.rectangle(zoneX, zoneY, zoneWidth, zoneHeight, 0x000000, 0);
interactiveZone.setInteractive({ useHandCursor: true });
interactiveZone.on('pointerdown', () => {
this.showMessage(`Fuel supply: ${barrelCount} barrels (${this.inventory.fuel} units). Needed for boiling down whale blubber.`);
});
this.fuelBarrels.push(interactiveZone);
}
createOilBarrels() {
const barrelCount = Math.ceil(this.inventory.whaleOil / 10);
if (barrelCount === 0) return;
const barrelWidth = 50;
const barrelHeight = 70;
const horizontalSpacing = 60;
const verticalSpacing = 75;
const barrelsPerRow = 3;
// Calculate group width and center it in right half of deck
const groupWidth = (Math.min(barrelCount, barrelsPerRow) * horizontalSpacing);
const rightHalfCenter = this.deckCenterX + (this.deckWidth / 4);
const baseX = rightHalfCenter - (groupWidth / 2) + (horizontalSpacing / 2);
const baseY = this.deckBottomY + 40;
// Create barrels in stacking pattern
for (let i = 0; i < barrelCount; i++) {
const row = i % barrelsPerRow;
const stackLevel = Math.floor(i / barrelsPerRow);
const x = baseX + (row * horizontalSpacing);
const y = baseY - (stackLevel * verticalSpacing);
const barrel = this.add.rectangle(x, y, barrelWidth, barrelHeight, 0x4B4B00);
barrel.setStrokeStyle(3, 0x000000);
this.oilBarrels.push(barrel);
// Add label only on first barrel
if (i === 0) {
const label = this.add.text(x, y, 'OIL', {
fontSize: '12px',
fill: '#fff'
}).setOrigin(0.5);
this.oilBarrels.push(label);
}
}
// Create interactive zone covering all oil barrels
const zoneWidth = Math.min(barrelCount, barrelsPerRow) * horizontalSpacing + barrelWidth;
const zoneHeight = Math.ceil(barrelCount / barrelsPerRow) * verticalSpacing + barrelHeight;
const zoneX = baseX + ((Math.min(barrelCount, barrelsPerRow) - 1) * horizontalSpacing) / 2;
const zoneY = baseY - ((Math.ceil(barrelCount / barrelsPerRow) - 1) * verticalSpacing) / 2;
const interactiveZone = this.add.rectangle(zoneX, zoneY, zoneWidth, zoneHeight, 0x000000, 0);
interactiveZone.setInteractive({ useHandCursor: true });
interactiveZone.on('pointerdown', () => {
this.showMessage(`Whale oil: ${barrelCount} barrels (${this.inventory.whaleOil} units). Your precious cargo!`);
});
this.oilBarrels.push(interactiveZone);
}
clearBarrels() {
// Destroy all fuel barrels
this.fuelBarrels.forEach(barrel => barrel.destroy());
this.fuelBarrels = [];
// Destroy all oil barrels
this.oilBarrels.forEach(barrel => barrel.destroy());
this.oilBarrels = [];
}
createWheel() {
// Ship's wheel
const wheel = this.add.circle(550, 200, 40, 0x8B4513);
wheel.setInteractive({ useHandCursor: true });
wheel.setStrokeStyle(4, 0x654321);
// Wheel spokes
for (let i = 0; i < 8; i++) {
const angle = (i * 45) * Math.PI / 180;
const x1 = 550 + Math.cos(angle) * 15;
const y1 = 200 + Math.sin(angle) * 15;
const x2 = 550 + Math.cos(angle) * 35;
const y2 = 200 + Math.sin(angle) * 35;
this.add.line(0, 0, x1, y1, x2, y2, 0x654321).setLineWidth(3);
}
wheel.on('pointerdown', () => {
// Open the map scene
this.scene.start('MapScene', { inventory: this.inventory });
});
}
createInventoryDisplay() {
// Inventory panel
const panel = this.add.rectangle(80, 80, 140, 100, 0x000000, 0.7);
panel.setStrokeStyle(2, 0xffffff);
this.inventoryText = this.add.text(20, 40, '', {
fontSize: '14px',
fill: '#fff'
});
this.updateInventoryDisplay();
}
updateInventoryDisplay() {
const lines = [
'Inventory:',
`Fuel: ${this.inventory.fuel}/100`,
`Oil: ${this.inventory.whaleOil}/50`
];
// Only show penguins if discovered (have at least one)
const discovered = this.inventory.penguins > 0;
if (discovered) {
lines.push(`Penguins: ${this.inventory.penguins}/20`);
}
this.inventoryText.setText(lines);
// Update penguin cage visibility
if (this.penguinCage) {
this.penguinCage.setVisible(discovered);
this.penguinEmoji.setVisible(discovered);
}
// Refresh barrel visualization
this.clearBarrels();
this.createFuelBarrels();
this.createOilBarrels();
}
createMessageBox() {
// Message display area
this.messageBox = this.add.rectangle(400, 500, 760, 80, 0x000000, 0.8);
this.messageBox.setStrokeStyle(2, 0xcccccc);
this.messageText = this.add.text(400, 500, 'Welcome aboard! Click around to explore the ship.', {
fontSize: '16px',
fill: '#fff',
wordWrap: { width: 740 },
align: 'center'
}).setOrigin(0.5);
}
showMessage(message) {
this.messageText.setText(message);
}
// Helper method to modify inventory (for future use)
addToInventory(item, amount) {
if (this.inventory.hasOwnProperty(item)) {
this.inventory[item] += amount;
this.updateInventoryDisplay();
}
}
}