diff --git a/CHANGELOG.md b/CHANGELOG.md index 276024b..b831616 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,11 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). ## [Unreleased] +### Fixed +- UI elements (stockpile panel, controls hint) now reposition correctly after window resize +- Centered overlay panels (build menu, villager panel) close on resize so they reopen at the correct position +- Mouse world coordinates now use `ptr.worldX`/`ptr.worldY` in BuildingSystem and FarmingSystem, fixing misalignment after resize or zoom + ### Added - Right-click context menu: suppresses browser default, shows Build and Folks actions in the game world - Initial project setup: Phaser 3 + TypeScript + Vite diff --git a/src/scenes/UIScene.ts b/src/scenes/UIScene.ts index b34f428..509dd9f 100644 --- a/src/scenes/UIScene.ts +++ b/src/scenes/UIScene.ts @@ -21,7 +21,9 @@ export class UIScene extends Phaser.Scene { private buildModeText!: Phaser.GameObjects.Text private farmToolText!: Phaser.GameObjects.Text private coordsText!: Phaser.GameObjects.Text + private controlsHintText!: Phaser.GameObjects.Text private popText!: Phaser.GameObjects.Text + private stockpileTitleText!: Phaser.GameObjects.Text private contextMenuGroup!: Phaser.GameObjects.Group private contextMenuVisible = false private inBuildMode = false @@ -80,7 +82,7 @@ export class UIScene extends Phaser.Scene { private createStockpilePanel(): void { const x = this.scale.width - 178, y = 10 this.stockpilePanel = this.add.rectangle(x, y, 168, 165, 0x000000, 0.72).setOrigin(0, 0).setScrollFactor(0).setDepth(100) - this.add.text(x + 10, y + 7, '⚡ STOCKPILE', { fontSize: '11px', color: '#aaaaaa', fontFamily: 'monospace' }).setScrollFactor(0).setDepth(101) + this.stockpileTitleText = this.add.text(x + 10, y + 7, '⚡ STOCKPILE', { fontSize: '11px', color: '#aaaaaa', fontFamily: 'monospace' }).setScrollFactor(0).setDepth(101) const items = ['wood','stone','wheat_seed','carrot_seed','wheat','carrot'] as const items.forEach((item, i) => { const t = this.add.text(x + 10, y + 26 + i * 22, `${ITEM_ICONS[item]} ${item}: 0`, { fontSize: '13px', color: '#88dd88', fontFamily: 'monospace' }).setScrollFactor(0).setDepth(101) @@ -286,7 +288,7 @@ export class UIScene extends Phaser.Scene { private createCoordsDisplay(): void { this.coordsText = this.add.text(10, this.scale.height - 24, '', { fontSize: '11px', color: '#666666', fontFamily: 'monospace' }).setScrollFactor(0).setDepth(100) - this.add.text(10, this.scale.height - 42, '[WASD] Pan [Scroll] Zoom [F] Farm [B] Build [V] Villagers', { + this.controlsHintText = this.add.text(10, this.scale.height - 42, '[WASD] Pan [Scroll] Zoom [F] Farm [B] Build [V] Villagers', { fontSize: '10px', color: '#444444', fontFamily: 'monospace', backgroundColor: '#00000066', padding: { x: 4, y: 2 } }).setScrollFactor(0).setDepth(100) } @@ -359,10 +361,33 @@ export class UIScene extends Phaser.Scene { // ─── Resize ─────────────────────────────────────────────────────────────── + /** + * Repositions all fixed UI elements after a canvas resize. + * Open overlay panels are closed so they reopen correctly centered. + */ private repositionUI(): void { const { width, height } = this.scale - this.hintText.setPosition(width/2, height - 40) - this.toastText.setPosition(width/2, 60) + + // Stockpile panel — anchored to top-right; move all elements by the delta + const newPanelX = width - 178 + const deltaX = newPanelX - this.stockpilePanel.x + if (deltaX !== 0) { + this.stockpilePanel.setX(newPanelX) + this.stockpileTitleText.setX(this.stockpileTitleText.x + deltaX) + this.stockpileTexts.forEach(t => t.setX(t.x + deltaX)) + this.popText.setX(this.popText.x + deltaX) + } + + // Bottom elements + this.hintText.setPosition(width / 2, height - 40) + this.toastText.setPosition(width / 2, 60) this.coordsText.setPosition(10, height - 24) + this.controlsHintText.setPosition(10, height - 42) + + // Close centered panels — their position is calculated on open, so they + // would be off-center if left open during a resize + if (this.buildMenuVisible) this.closeBuildMenu() + if (this.villagerPanelVisible) this.closeVillagerPanel() + if (this.contextMenuVisible) this.hideContextMenu() } } diff --git a/src/systems/BuildingSystem.ts b/src/systems/BuildingSystem.ts index df1b25e..3e52d8a 100644 --- a/src/systems/BuildingSystem.ts +++ b/src/systems/BuildingSystem.ts @@ -92,9 +92,9 @@ export class BuildingSystem { if (!this.active) return // Update ghost to follow mouse (snapped to tile grid) - const ptr = this.scene.input.activePointer - const worldX = this.scene.cameras.main.scrollX + ptr.x - const worldY = this.scene.cameras.main.scrollY + ptr.y + const ptr = this.scene.input.activePointer + const worldX = ptr.worldX + const worldY = ptr.worldY const tileX = Math.floor(worldX / TILE_SIZE) const tileY = Math.floor(worldY / TILE_SIZE) const snapX = tileX * TILE_SIZE + TILE_SIZE / 2 @@ -142,8 +142,8 @@ export class BuildingSystem { } private tryPlace(ptr: Phaser.Input.Pointer): void { - const worldX = this.scene.cameras.main.scrollX + ptr.x - const worldY = this.scene.cameras.main.scrollY + ptr.y + const worldX = ptr.worldX + const worldY = ptr.worldY const tileX = Math.floor(worldX / TILE_SIZE) const tileY = Math.floor(worldY / TILE_SIZE) diff --git a/src/systems/FarmingSystem.ts b/src/systems/FarmingSystem.ts index 79ece7b..ea30a1a 100644 --- a/src/systems/FarmingSystem.ts +++ b/src/systems/FarmingSystem.ts @@ -80,9 +80,8 @@ export class FarmingSystem { // ─── Tool actions ───────────────────────────────────────────────────────── private useToolAt(ptr: Phaser.Input.Pointer): void { - const cam = this.scene.cameras.main - const worldX = cam.scrollX + ptr.x - const worldY = cam.scrollY + ptr.y + const worldX = ptr.worldX + const worldY = ptr.worldY const tileX = Math.floor(worldX / TILE_SIZE) const tileY = Math.floor(worldY / TILE_SIZE) const state = stateManager.getState()