105 lines
3.6 KiB
TypeScript
105 lines
3.6 KiB
TypeScript
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);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|