🐛 fix UI repositioning and mouse coords after window resize
This commit is contained in:
@@ -7,6 +7,11 @@ Format follows [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
|||||||
|
|
||||||
## [Unreleased]
|
## [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
|
### Added
|
||||||
- Right-click context menu: suppresses browser default, shows Build and Folks actions in the game world
|
- Right-click context menu: suppresses browser default, shows Build and Folks actions in the game world
|
||||||
- Initial project setup: Phaser 3 + TypeScript + Vite
|
- Initial project setup: Phaser 3 + TypeScript + Vite
|
||||||
|
|||||||
@@ -21,7 +21,9 @@ export class UIScene extends Phaser.Scene {
|
|||||||
private buildModeText!: Phaser.GameObjects.Text
|
private buildModeText!: Phaser.GameObjects.Text
|
||||||
private farmToolText!: Phaser.GameObjects.Text
|
private farmToolText!: Phaser.GameObjects.Text
|
||||||
private coordsText!: Phaser.GameObjects.Text
|
private coordsText!: Phaser.GameObjects.Text
|
||||||
|
private controlsHintText!: Phaser.GameObjects.Text
|
||||||
private popText!: Phaser.GameObjects.Text
|
private popText!: Phaser.GameObjects.Text
|
||||||
|
private stockpileTitleText!: Phaser.GameObjects.Text
|
||||||
private contextMenuGroup!: Phaser.GameObjects.Group
|
private contextMenuGroup!: Phaser.GameObjects.Group
|
||||||
private contextMenuVisible = false
|
private contextMenuVisible = false
|
||||||
private inBuildMode = false
|
private inBuildMode = false
|
||||||
@@ -80,7 +82,7 @@ export class UIScene extends Phaser.Scene {
|
|||||||
private createStockpilePanel(): void {
|
private createStockpilePanel(): void {
|
||||||
const x = this.scale.width - 178, y = 10
|
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.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
|
const items = ['wood','stone','wheat_seed','carrot_seed','wheat','carrot'] as const
|
||||||
items.forEach((item, i) => {
|
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)
|
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 {
|
private createCoordsDisplay(): void {
|
||||||
this.coordsText = this.add.text(10, this.scale.height - 24, '', { fontSize: '11px', color: '#666666', fontFamily: 'monospace' }).setScrollFactor(0).setDepth(100)
|
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 }
|
fontSize: '10px', color: '#444444', fontFamily: 'monospace', backgroundColor: '#00000066', padding: { x: 4, y: 2 }
|
||||||
}).setScrollFactor(0).setDepth(100)
|
}).setScrollFactor(0).setDepth(100)
|
||||||
}
|
}
|
||||||
@@ -359,10 +361,33 @@ export class UIScene extends Phaser.Scene {
|
|||||||
|
|
||||||
// ─── Resize ───────────────────────────────────────────────────────────────
|
// ─── Resize ───────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Repositions all fixed UI elements after a canvas resize.
|
||||||
|
* Open overlay panels are closed so they reopen correctly centered.
|
||||||
|
*/
|
||||||
private repositionUI(): void {
|
private repositionUI(): void {
|
||||||
const { width, height } = this.scale
|
const { width, height } = this.scale
|
||||||
|
|
||||||
|
// 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.hintText.setPosition(width / 2, height - 40)
|
||||||
this.toastText.setPosition(width / 2, 60)
|
this.toastText.setPosition(width / 2, 60)
|
||||||
this.coordsText.setPosition(10, height - 24)
|
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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -93,8 +93,8 @@ export class BuildingSystem {
|
|||||||
|
|
||||||
// Update ghost to follow mouse (snapped to tile grid)
|
// Update ghost to follow mouse (snapped to tile grid)
|
||||||
const ptr = this.scene.input.activePointer
|
const ptr = this.scene.input.activePointer
|
||||||
const worldX = this.scene.cameras.main.scrollX + ptr.x
|
const worldX = ptr.worldX
|
||||||
const worldY = this.scene.cameras.main.scrollY + ptr.y
|
const worldY = ptr.worldY
|
||||||
const tileX = Math.floor(worldX / TILE_SIZE)
|
const tileX = Math.floor(worldX / TILE_SIZE)
|
||||||
const tileY = Math.floor(worldY / TILE_SIZE)
|
const tileY = Math.floor(worldY / TILE_SIZE)
|
||||||
const snapX = tileX * TILE_SIZE + TILE_SIZE / 2
|
const snapX = tileX * TILE_SIZE + TILE_SIZE / 2
|
||||||
@@ -142,8 +142,8 @@ export class BuildingSystem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private tryPlace(ptr: Phaser.Input.Pointer): void {
|
private tryPlace(ptr: Phaser.Input.Pointer): void {
|
||||||
const worldX = this.scene.cameras.main.scrollX + ptr.x
|
const worldX = ptr.worldX
|
||||||
const worldY = this.scene.cameras.main.scrollY + ptr.y
|
const worldY = ptr.worldY
|
||||||
const tileX = Math.floor(worldX / TILE_SIZE)
|
const tileX = Math.floor(worldX / TILE_SIZE)
|
||||||
const tileY = Math.floor(worldY / TILE_SIZE)
|
const tileY = Math.floor(worldY / TILE_SIZE)
|
||||||
|
|
||||||
|
|||||||
@@ -80,9 +80,8 @@ export class FarmingSystem {
|
|||||||
// ─── Tool actions ─────────────────────────────────────────────────────────
|
// ─── Tool actions ─────────────────────────────────────────────────────────
|
||||||
|
|
||||||
private useToolAt(ptr: Phaser.Input.Pointer): void {
|
private useToolAt(ptr: Phaser.Input.Pointer): void {
|
||||||
const cam = this.scene.cameras.main
|
const worldX = ptr.worldX
|
||||||
const worldX = cam.scrollX + ptr.x
|
const worldY = ptr.worldY
|
||||||
const worldY = cam.scrollY + ptr.y
|
|
||||||
const tileX = Math.floor(worldX / TILE_SIZE)
|
const tileX = Math.floor(worldX / TILE_SIZE)
|
||||||
const tileY = Math.floor(worldY / TILE_SIZE)
|
const tileY = Math.floor(worldY / TILE_SIZE)
|
||||||
const state = stateManager.getState()
|
const state = stateManager.getState()
|
||||||
|
|||||||
Reference in New Issue
Block a user