import Phaser from "phaser"; import { type World, type CombatantActor } from "../core/types"; import { idx, isWall } from "../engine/world/world-logic"; import { GAME_CONFIG } from "../core/config/GameConfig"; export class MinimapRenderer { private scene: Phaser.Scene; private minimapGfx!: Phaser.GameObjects.Graphics; private minimapContainer!: Phaser.GameObjects.Container; private minimapBg!: Phaser.GameObjects.Rectangle; private minimapVisible = false; constructor(scene: Phaser.Scene) { this.scene = scene; this.initMinimap(); } private initMinimap() { this.minimapContainer = this.scene.add.container(0, 0); this.minimapContainer.setScrollFactor(0); this.minimapContainer.setDepth(1001); this.minimapBg = this.scene.add .rectangle(0, 0, GAME_CONFIG.ui.minimapPanelWidth, GAME_CONFIG.ui.minimapPanelHeight, 0x000000, 0.8) .setStrokeStyle(1, 0xffffff, 0.9) .setInteractive(); this.minimapGfx = this.scene.add.graphics(); this.minimapContainer.add(this.minimapBg); this.minimapContainer.add(this.minimapGfx); this.positionMinimap(); this.minimapContainer.setVisible(false); } positionMinimap() { const cam = this.scene.cameras.main; this.minimapContainer.setPosition(cam.width / 2, cam.height / 2); } toggle() { this.minimapVisible = !this.minimapVisible; this.minimapContainer.setVisible(this.minimapVisible); } isVisible(): boolean { return this.minimapVisible; } render(world: World, seen: Uint8Array, visible: Uint8Array) { this.minimapGfx.clear(); if (!world) return; const padding = GAME_CONFIG.ui.minimapPadding; const availableWidth = GAME_CONFIG.ui.minimapPanelWidth - padding * 2; const availableHeight = GAME_CONFIG.ui.minimapPanelHeight - padding * 2; const scaleX = availableWidth / world.width; const scaleY = availableHeight / world.height; const tileSize = Math.floor(Math.min(scaleX, scaleY)); const mapPixelWidth = world.width * tileSize; const mapPixelHeight = world.height * tileSize; const offsetX = -mapPixelWidth / 2; const offsetY = -mapPixelHeight / 2; for (let y = 0; y < world.height; y++) { for (let x = 0; x < world.width; x++) { const i = idx(world, x, y); if (seen[i] !== 1) continue; const wall = isWall(world, x, y); const color = wall ? 0x666666 : 0x333333; this.minimapGfx.fillStyle(color, 1); this.minimapGfx.fillRect(offsetX + x * tileSize, offsetY + y * tileSize, tileSize, tileSize); } } const ex = world.exit.x; const ey = world.exit.y; if (seen[idx(world, ex, ey)] === 1) { this.minimapGfx.fillStyle(0xffd166, 1); this.minimapGfx.fillRect(offsetX + ex * tileSize, offsetY + ey * tileSize, tileSize, tileSize); } const player = [...world.actors.values()].find(a => a.category === "combatant" && a.isPlayer) as CombatantActor; if (player) { this.minimapGfx.fillStyle(0x66ff66, 1); this.minimapGfx.fillRect(offsetX + player.pos.x * tileSize, offsetY + player.pos.y * tileSize, tileSize, tileSize); } for (const a of world.actors.values()) { if (a.category === "combatant") { if (a.isPlayer) continue; const i = idx(world, a.pos.x, a.pos.y); if (visible[i] === 1) { this.minimapGfx.fillStyle(0xff6666, 1); this.minimapGfx.fillRect(offsetX + a.pos.x * tileSize, offsetY + a.pos.y * tileSize, tileSize, tileSize); } } } } }