Files
novafarma/EMERGENCY_SYSTEMS_RECOVERY/MapRevealSystem.js
2026-01-16 02:43:46 +01:00

335 lines
10 KiB
JavaScript

/**
* 🗺️ MAP REVEAL SYSTEM
* Fog of war system that reveals map as player explores
* - Reveals tiles around player
* - Persistent (saves discovered areas)
* - Minimap integration
* - Full map view (M key)
*/
class MapRevealSystem {
constructor(scene) {
this.scene = scene;
// Revealed tiles (500x500 grid)
this.revealed = Array(500).fill(null).map(() => Array(500).fill(false));
// Reveal radius around player
this.revealRadius = 15; // tiles
// Map UI elements
this.mapOpen = false;
this.mapContainer = null;
// Minimap
this.minimap = null;
this.minimapSize = 200;
this.minimapScale = 2; // pixels per tile on minimap
console.log('🗺️ MapRevealSystem initialized');
}
// Reveal tiles around player
revealArea(playerX, playerY) {
const gridX = Math.floor(playerX);
const gridY = Math.floor(playerY);
let newTilesRevealed = 0;
for (let dx = -this.revealRadius; dx <= this.revealRadius; dx++) {
for (let dy = -this.revealRadius; dy <= this.revealRadius; dy++) {
const x = gridX + dx;
const y = gridY + dy;
// Check if within world bounds
if (x < 0 || x >= 500 || y < 0 || y >= 500) continue;
// Check if within circular radius
const dist = Math.sqrt(dx * dx + dy * dy);
if (dist > this.revealRadius) continue;
// Reveal tile
if (!this.revealed[y][x]) {
this.revealed[y][x] = true;
newTilesRevealed++;
}
}
}
if (newTilesRevealed > 0) {
// Update minimap
this.updateMinimap();
}
}
// Create minimap (bottom-right corner)
createMinimap() {
if (this.minimap) return;
const size = this.minimapSize;
const x = this.scene.cameras.main.width - size - 20;
const y = this.scene.cameras.main.height - size - 20;
// Background
this.minimapBg = this.scene.add.rectangle(x, y, size, size, 0x000000, 0.7);
this.minimapBg.setOrigin(0);
this.minimapBg.setScrollFactor(0);
this.minimapBg.setDepth(9000);
// Border
this.minimapBorder = this.scene.add.rectangle(x, y, size, size);
this.minimapBorder.setOrigin(0);
this.minimapBorder.setStrokeStyle(2, 0xFFFFFF);
this.minimapBorder.setScrollFactor(0);
this.minimapBorder.setDepth(9001);
// Canvas for map rendering
this.minimapTexture = this.scene.add.renderTexture(x, y, size, size);
this.minimapTexture.setOrigin(0);
this.minimapTexture.setScrollFactor(0);
this.minimapTexture.setDepth(9002);
// Label
this.minimapLabel = this.scene.add.text(x + size / 2, y - 15, 'Map (M)', {
fontSize: '14px',
color: '#ffffff',
backgroundColor: '#000000',
padding: { x: 5, y: 2 }
});
this.minimapLabel.setOrigin(0.5);
this.minimapLabel.setScrollFactor(0);
this.minimapLabel.setDepth(9003);
this.minimap = {
bg: this.minimapBg,
border: this.minimapBorder,
texture: this.minimapTexture,
label: this.minimapLabel,
x, y, size
};
this.updateMinimap();
}
// Update minimap rendering
updateMinimap() {
if (!this.minimap) return;
const player = this.scene.player;
if (!player) return;
const playerX = Math.floor(player.gridX);
const playerY = Math.floor(player.gridY);
// Clear
this.minimap.texture.clear();
// Calculate view area (centered on player)
const viewSize = Math.floor(this.minimap.size / this.minimapScale);
const startX = Math.max(0, playerX - viewSize / 2);
const startY = Math.max(0, playerY - viewSize / 2);
const endX = Math.min(500, startX + viewSize);
const endY = Math.min(500, startY + viewSize);
// Draw revealed tiles
for (let y = startY; y < endY; y++) {
for (let x = startX; x < endX; x++) {
if (!this.revealed[y] || !this.revealed[y][x]) continue;
const screenX = (x - startX) * this.minimapScale;
const screenY = (y - startY) * this.minimapScale;
// Get biome color
const biome = this.scene.biomeSystem ? this.scene.biomeSystem.getBiomeAt(x, y) : 'Grassland';
const color = this.getBiomeMinimapColor(biome);
this.minimap.texture.fill(color, 1, screenX, screenY, this.minimapScale, this.minimapScale);
}
}
// Draw player position
const playerScreenX = (playerX - startX) * this.minimapScale;
const playerScreenY = (playerY - startY) * this.minimapScale;
this.minimap.texture.fill(0xFFFF00, 1, playerScreenX - 2, playerScreenY - 2, 4, 4);
}
// Get minimap color for biome
getBiomeMinimapColor(biome) {
const colors = {
'Grassland': 0x3CB371,
'Forest': 0x2d5016,
'Desert': 0xd4c4a1,
'Mountain': 0x808080,
'Swamp': 0x3d5a3d
};
return colors[biome] || 0x3CB371;
}
// Toggle full map view (M key)
toggleFullMap() {
if (this.mapOpen) {
this.closeFullMap();
} else {
this.openFullMap();
}
}
// Open full map
openFullMap() {
if (this.mapOpen) return;
this.mapOpen = true;
// Semi-transparent background
this.fullMapBg = this.scene.add.rectangle(
this.scene.cameras.main.centerX,
this.scene.cameras.main.centerY,
this.scene.cameras.main.width,
this.scene.cameras.main.height,
0x000000,
0.9
);
this.fullMapBg.setScrollFactor(0);
this.fullMapBg.setDepth(15000);
// Map title
this.fullMapTitle = this.scene.add.text(
this.scene.cameras.main.centerX,
50,
'World Map (Press M to close)',
{
fontSize: '32px',
color: '#FFD700',
backgroundColor: '#000000',
padding: { x: 20, y: 10 }
}
);
this.fullMapTitle.setOrigin(0.5);
this.fullMapTitle.setScrollFactor(0);
this.fullMapTitle.setDepth(15001);
// Render full map
const mapSize = 600;
const mapX = this.scene.cameras.main.centerX - mapSize / 2;
const mapY = this.scene.cameras.main.centerY - mapSize / 2;
this.fullMapTexture = this.scene.add.renderTexture(mapX, mapY, mapSize, mapSize);
this.fullMapTexture.setScrollFactor(0);
this.fullMapTexture.setDepth(15002);
// Draw entire world
const scale = mapSize / 500;
for (let y = 0; y < 500; y += 5) {
for (let x = 0; x < 500; x += 5) {
if (!this.revealed[y] || !this.revealed[y][x]) continue;
const biome = this.scene.biomeSystem ? this.scene.biomeSystem.getBiomeAt(x, y) : 'Grassland';
const color = this.getBiomeMinimapColor(biome);
this.fullMapTexture.fill(color, 1, x * scale, y * scale, scale * 5, scale * 5);
}
}
// Player position
if (this.scene.player) {
const px = Math.floor(this.scene.player.gridX) * scale;
const py = Math.floor(this.scene.player.gridY) * scale;
this.fullMapTexture.fill(0xFFFF00, 1, px - 3, py - 3, 6, 6);
}
// Stats
const exploredTiles = this.revealed.flat().filter(r => r).length;
const totalTiles = 500 * 500;
const percent = ((exploredTiles / totalTiles) * 100).toFixed(1);
this.fullMapStats = this.scene.add.text(
this.scene.cameras.main.centerX,
mapY + mapSize + 30,
`Explored: ${exploredTiles} / ${totalTiles} tiles (${percent}%)`,
{
fontSize: '20px',
color: '#ffffff',
backgroundColor: '#000000',
padding: { x: 15, y: 8 }
}
);
this.fullMapStats.setOrigin(0.5);
this.fullMapStats.setScrollFactor(0);
this.fullMapStats.setDepth(15003);
}
// Close full map
closeFullMap() {
if (!this.mapOpen) return;
this.mapOpen = false;
if (this.fullMapBg) {
this.fullMapBg.destroy();
this.fullMapTitle.destroy();
this.fullMapTexture.destroy();
this.fullMapStats.destroy();
}
}
// Update (called every frame)
update() {
if (this.scene.player) {
this.revealArea(this.scene.player.gridX, this.scene.player.gridY);
}
}
// Get exploration statistics
getStats() {
const exploredTiles = this.revealed.flat().filter(r => r).length;
const totalTiles = 500 * 500;
const percent = ((exploredTiles / totalTiles) * 100).toFixed(2);
return {
explored: exploredTiles,
total: totalTiles,
percent: parseFloat(percent)
};
}
// Export/Import for save system
exportData() {
// Convert 2D array to compressed format
const compressed = [];
for (let y = 0; y < 500; y++) {
for (let x = 0; x < 500; x++) {
if (this.revealed[y][x]) {
compressed.push(`${x},${y}`);
}
}
}
return { revealed: compressed };
}
importData(data) {
if (!data || !data.revealed) return;
// Clear current
this.revealed = Array(500).fill(null).map(() => Array(500).fill(false));
// Decompress
for (const key of data.revealed) {
const [x, y] = key.split(',').map(Number);
if (x >= 0 && x < 500 && y >= 0 && y < 500) {
this.revealed[y][x] = true;
}
}
}
destroy() {
this.closeFullMap();
if (this.minimap) {
this.minimap.bg.destroy();
this.minimap.border.destroy();
this.minimap.texture.destroy();
this.minimap.label.destroy();
this.minimap = null;
}
}
}