From ff462fb53cd7da8a5c632bdc718b64623e809af2 Mon Sep 17 00:00:00 2001 From: Peter Stockings Date: Sun, 4 Jan 2026 09:53:07 +1100 Subject: [PATCH] Add minimap --- src/scenes/DungeonRenderer.ts | 121 ++++++++++++++++++++++++++++++++++ 1 file changed, 121 insertions(+) diff --git a/src/scenes/DungeonRenderer.ts b/src/scenes/DungeonRenderer.ts index 92dd203..08e7008 100644 --- a/src/scenes/DungeonRenderer.ts +++ b/src/scenes/DungeonRenderer.ts @@ -17,9 +17,31 @@ export class DungeonRenderer { // State refs private world!: World; + // Minimap + private minimapGfx!: Phaser.GameObjects.Graphics; + private minimapContainer!: Phaser.GameObjects.Container; + private minimapBg!: Phaser.GameObjects.Graphics; + private minimapScale = 2; // pixels per tile + private minimapPadding = 8; + constructor(scene: Phaser.Scene) { this.scene = scene; this.gfx = this.scene.add.graphics(); + + // Initialize minimap + this.initMinimap(); + } + + private initMinimap() { + this.minimapContainer = this.scene.add.container(0, 0); + this.minimapContainer.setScrollFactor(0); // Fixed to camera + this.minimapContainer.setDepth(100); + + this.minimapBg = this.scene.add.graphics(); + this.minimapGfx = this.scene.add.graphics(); + + this.minimapContainer.add(this.minimapBg); + this.minimapContainer.add(this.minimapGfx); } initializeLevel(world: World) { @@ -32,6 +54,21 @@ export class DungeonRenderer { if (!inBounds(this.world, x, y)) return false; return !isWall(this.world, x, y); }); + + // Position minimap + this.positionMinimap(); + } + + private positionMinimap() { + const cam = this.scene.cameras.main; + const minimapWidth = this.world.width * this.minimapScale + this.minimapPadding * 2; + const minimapHeight = this.world.height * this.minimapScale + this.minimapPadding * 2; + + // Position in bottom right corner (accounting for zoom) + const x = cam.width / cam.zoom - minimapWidth - 10; + const y = cam.height / cam.zoom - minimapHeight - 10; + + this.minimapContainer.setPosition(x, y); } computeFov(playerId: EntityId) { @@ -135,6 +172,90 @@ export class DungeonRenderer { this.gfx.fillStyle(color, 1); this.gfx.fillRect(a.pos.x * TILE_SIZE + 4, a.pos.y * TILE_SIZE + 4, TILE_SIZE - 8, TILE_SIZE - 8); } + + // Render minimap + this.renderMinimap(); + } + + private renderMinimap() { + this.minimapBg.clear(); + this.minimapGfx.clear(); + + if (!this.world) return; + + const minimapWidth = this.world.width * this.minimapScale + this.minimapPadding * 2; + const minimapHeight = this.world.height * this.minimapScale + this.minimapPadding * 2; + + // Background + this.minimapBg.fillStyle(0x000000, 0.7); + this.minimapBg.fillRect(0, 0, minimapWidth, minimapHeight); + + // Border + this.minimapBg.lineStyle(1, 0x666666, 1); + this.minimapBg.strokeRect(0, 0, minimapWidth, minimapHeight); + + // Draw only seen tiles + for (let y = 0; y < this.world.height; y++) { + for (let x = 0; x < this.world.width; x++) { + const i = idx(this.world, x, y); + const isSeen = this.seen[i] === 1; + + if (!isSeen) continue; + + const wall = isWall(this.world, x, y); + const color = wall ? 0x666666 : 0x333333; + + this.minimapGfx.fillStyle(color, 1); + this.minimapGfx.fillRect( + this.minimapPadding + x * this.minimapScale, + this.minimapPadding + y * this.minimapScale, + this.minimapScale, + this.minimapScale + ); + } + } + + // Draw exit if seen + const ex = this.world.exit.x; + const ey = this.world.exit.y; + const exitIdx = idx(this.world, ex, ey); + if (this.seen[exitIdx] === 1) { + this.minimapGfx.fillStyle(0xffd166, 1); + this.minimapGfx.fillRect( + this.minimapPadding + ex * this.minimapScale, + this.minimapPadding + ey * this.minimapScale, + this.minimapScale, + this.minimapScale + ); + } + + // Draw player + const player = [...this.world.actors.values()].find(a => a.isPlayer); + if (player) { + this.minimapGfx.fillStyle(0x66ff66, 1); + this.minimapGfx.fillRect( + this.minimapPadding + player.pos.x * this.minimapScale, + this.minimapPadding + player.pos.y * this.minimapScale, + this.minimapScale, + this.minimapScale + ); + } + + // Draw visible enemies + for (const a of this.world.actors.values()) { + if (a.isPlayer) continue; + const i = idx(this.world, a.pos.x, a.pos.y); + const isVis = this.visible[i] === 1; + if (!isVis) continue; + + this.minimapGfx.fillStyle(0xff6666, 1); + this.minimapGfx.fillRect( + this.minimapPadding + a.pos.x * this.minimapScale, + this.minimapPadding + a.pos.y * this.minimapScale, + this.minimapScale, + this.minimapScale + ); + } } showDamage(x: number, y: number, amount: number) {