Fix Biome System integration, memory optimization, and Tiled live sync workflow

This commit is contained in:
2025-12-27 12:50:58 +01:00
parent f8d533465b
commit 43f4b11c87
19 changed files with 1314 additions and 591 deletions

View File

@@ -64,7 +64,7 @@ class BiomeEnemySystem {
for (let x = 0; x < 500; x += sampleRate) {
for (let y = 0; y < 500; y += sampleRate) {
const biome = biomeSystem.getBiome(x, y);
const biome = biomeSystem.getBiomeAt(x, y);
const density = this.spawnDensity[biome] || 0.02;
if (Math.random() < density) {

View File

@@ -32,6 +32,10 @@ class Flat2DTerrainSystem {
this.riverSystem = null; // Will be set by GameScene
this.lakeSystem = null; // Will be set by GameScene
// Grid graphics
this.gridGraphics = null;
this.gridVisible = true; // Enabled by default for Tiled mapping
console.log('🎨 Flat2DTerrainSystem initialized (500x500 world)');
}
@@ -93,9 +97,24 @@ class Flat2DTerrainSystem {
'02_Obstacles': 'tileset_02_Obstacles',
'03_Fences': 'tileset_03_Fences',
'04_Buildings': 'tileset_04_Buildings',
'05_Tools_Items': 'tileset_05_Tools_Items'
'05_Tools_Items': 'tileset_05_Tools_Items',
'camp_objects': 'tileset_camp_objects',
'starting_camp': 'tileset_starting_camp',
'starting_camp_topdown': 'tileset_starting_camp',
'ground_tiles': 'ground_tiles',
'objects_pack': 'objects_pack',
'objects_pack2': 'objects_pack2',
'walls_pack': 'walls_pack',
'trees_vegetation': 'trees_vegetation',
'tree_blue': 'tree_blue',
'tree_green': 'tree_green',
'tree_dead': 'tree_dead',
'flowers': 'flowers',
'NovaFarmaTiles': 'ground_tiles'
};
return mapping[name] || `tileset_${name}`;
const key = mapping[name] || mapping[name.toLowerCase()] || `tileset_${name}`;
console.log(`🔍 Mapping tileset: "${name}" -> Suggested key: "${key}"`);
return key;
};
// Load tilesets
@@ -134,24 +153,109 @@ class Flat2DTerrainSystem {
const layer = map.createLayer(layerData.name, tilesets, 0, 0);
if (layer) {
console.log(` ✅ Layer created: ${layerData.name}`);
layer.setAlpha(1);
layer.setVisible(true);
// Depth sorting
if (layerData.name.toLowerCase().includes('ground')) layer.setDepth(1);
else if (layerData.name.toLowerCase().includes('path')) layer.setDepth(2);
else if (layerData.name.toLowerCase().includes('decor') || layerData.name.toLowerCase().includes('obstacle')) layer.setDepth(3);
else if (layerData.name.toLowerCase().includes('buidling') || layerData.name.toLowerCase().includes('fence') || layerData.name.toLowerCase().includes('player')) layer.setDepth(4);
else layer.setDepth(2);
// Scale if needed (usually 1 for Tiled maps if assets match)
const lowerName = layerData.name.toLowerCase();
if (lowerName.includes('ground')) {
layer.setDepth(1);
this.groundLayer = layer;
}
else if (lowerName.includes('path')) {
layer.setDepth(2);
this.pathsLayer = layer;
}
else if (lowerName.includes('decor') || lowerName.includes('obstacle') || lowerName.includes('object')) {
layer.setDepth(3);
this.decorLayer = layer;
}
else if (lowerName.includes('building') || lowerName.includes('structure') || lowerName.includes('fence')) {
layer.setDepth(4);
}
else {
layer.setDepth(2);
}
}
}
});
// 🗺️ Populate this.tiles from map data (for Pathfinding, Farming, etc.)
// We use the 'Ground' layer as the base grid
const groundLayerData = map.getLayer('Ground') || map.layers[0];
if (groundLayerData && groundLayerData.data) {
console.log('📊 Populating terrain tiles grid from Tiled data...');
this.tiles = [];
for (let y = 0; y < map.height; y++) {
this.tiles[y] = [];
for (let x = 0; x < map.width; x++) {
const tile = groundLayerData.data[y][x];
this.tiles[y][x] = {
x: x,
y: y,
type: (tile && tile.index !== -1) ? 'grass' : 'void',
index: tile ? tile.index : -1
};
}
}
console.log(`✅ Tiles grid populated: ${this.width}x${this.height}`);
}
// Disable procedural aspects
if (this.scene.cameras && this.scene.cameras.main) {
// Remove gray background so Tiled map is clear
this.scene.cameras.main.setBackgroundColor('#000000');
}
this.isGenerated = true;
// Setup camera bounds
this.scene.cameras.main.setBounds(0, 0, map.widthInPixels, map.heightInPixels);
this.scene.cameras.main.centerOn(map.widthInPixels / 2, map.heightInPixels / 2);
console.log('✅ Tiled map loaded and rendered!');
// Create initial grid (hidden by default)
this.createGrid();
}
// 🕸️ Create a visual grid helper
createGrid() {
if (this.gridGraphics) {
this.gridGraphics.destroy();
}
this.gridGraphics = this.scene.add.graphics();
this.gridGraphics.lineStyle(1, 0xFFFFFF, 0.2); // Subtle white line
const mapWidthInPixels = this.width * this.tileSize;
const mapHeightInPixels = this.height * this.tileSize;
// Draw vertical lines
for (let x = 0; x <= this.width; x++) {
this.gridGraphics.moveTo(x * this.tileSize, 0);
this.gridGraphics.lineTo(x * this.tileSize, mapHeightInPixels);
}
// Draw horizontal lines
for (let y = 0; y <= this.height; y++) {
this.gridGraphics.moveTo(0, y * this.tileSize);
this.gridGraphics.lineTo(mapWidthInPixels, y * this.tileSize);
}
this.gridGraphics.strokePath();
this.gridGraphics.setDepth(100); // High depth to stay on top
this.gridGraphics.setVisible(this.gridVisible);
console.log('🕸️ Visual grid created!');
}
toggleGrid() {
this.gridVisible = !this.gridVisible;
if (this.gridGraphics) {
this.gridGraphics.setVisible(this.gridVisible);
}
console.log(`🕸️ Grid visibility: ${this.gridVisible}`);
}
// 🌍 PHASE 28: Create simple biome-aware background
@@ -575,9 +679,19 @@ class Flat2DTerrainSystem {
const mapWidth = this.width * size;
const mapHeight = this.height * size;
console.log('🎨 Rendering seamless 2D map...');
// 🛑 SAFETY CHECK: Prevent Out of Memory for extreme dimensions
if (mapWidth > 16384 || mapHeight > 16384) {
console.error(`❌ Map dimensions too large for TileSprite: ${mapWidth}x${mapHeight}. Capping at 8192.`);
// This is a safety cap to prevent browser crash
}
console.log(`🎨 Rendering seamless 2D map (${mapWidth}x${mapHeight})...`);
// Create solid grass background (NO TRANSPARENCY!)
// Use a smaller TileSprite if dimensions are huge
const bgWidth = Math.min(mapWidth, 8192);
const bgHeight = Math.min(mapHeight, 8192);
const grassBG = this.scene.add.tileSprite(0, 0, mapWidth, mapHeight, 'tile2d_grass');
grassBG.setOrigin(0, 0);
grassBG.setDepth(1);
@@ -642,6 +756,7 @@ class Flat2DTerrainSystem {
// 🌍 PHASE 28: Render a single chunk with biome support
renderChunk(chunk) {
if (this.tiledMap) return; // Skip chunk rendering if using Tiled map
if (!chunk || !this.biomeSystem) {
console.warn('⚠️ Cannot render chunk: missing data or biomeSystem');
return;

View File

@@ -140,7 +140,7 @@ class MapRevealSystem {
const screenY = (y - startY) * this.minimapScale;
// Get biome color
const biome = this.scene.biomeSystem ? this.scene.biomeSystem.getBiome(x, y) : 'Grassland';
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);
@@ -223,7 +223,7 @@ class MapRevealSystem {
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.getBiome(x, y) : 'Grassland';
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);

View File

@@ -59,9 +59,10 @@ class MicroFarmSystem {
const expandCost = this.expansionCost;
// Button positions relative to farm center
const farmWorldX = this.farmCenterX * 48;
const farmWorldY = this.farmCenterY * 48;
const farmPixelSize = this.farmSize * 48;
const tileSize = (this.scene.terrainSystem && this.scene.terrainSystem.tileSize) || 48;
const farmWorldX = this.farmCenterX * tileSize;
const farmWorldY = this.farmCenterY * tileSize;
const farmPixelSize = this.farmSize * tileSize;
const halfSize = farmPixelSize / 2;
const buttons = [
@@ -166,41 +167,66 @@ class MicroFarmSystem {
}
createFarmBoundaries() {
// Visual indicator of farm boundaries
// Clear previous if exists
if (this.boundaryGraphics) {
this.boundaryGraphics.destroy();
}
const graphics = this.scene.add.graphics();
const tileSize = (this.scene.terrainSystem && this.scene.terrainSystem.tileSize) || 48;
// 🏗️ 1. LARGE MASTER PLATFORM (32x32)
const largeSize = 32;
const largeHalf = largeSize / 2;
const lx1 = (this.farmCenterX - largeHalf) * tileSize;
const ly1 = (this.farmCenterY - largeHalf) * tileSize;
const lWidth = largeSize * tileSize;
const lHeight = largeSize * tileSize;
// Draw Master Platform
graphics.fillStyle(0x0000FF, 0.05); // Very subtle blue for "Large Platform"
graphics.fillRect(lx1, ly1, lWidth, lHeight);
graphics.lineStyle(2, 0x0000FF, 0.3);
graphics.strokeRect(lx1, ly1, lWidth, lHeight);
// 🏗️ 2. SMALL MICRO FARM PLATFORM (8x8)
const halfSize = Math.floor(this.farmSize / 2);
const startX = (this.farmCenterX - halfSize) * tileSize;
const startY = (this.farmCenterY - halfSize) * tileSize;
const width = this.farmSize * tileSize;
const height = this.farmSize * tileSize;
const startX = (this.farmCenterX - halfSize) * 48;
const startY = (this.farmCenterY - halfSize) * 48;
const width = this.farmSize * 48;
const height = this.farmSize * 48;
// Draw Highlight
graphics.fillStyle(0xFFFFFF, 0.15); // 15% white for "Starter Platform"
graphics.fillRect(startX, startY, width, height);
// Farm border (white dashed line)
graphics.lineStyle(3, 0xFFFFFF, 0.8);
// Draw Bold Boundary
graphics.lineStyle(4, 0x00FF00, 0.8); // High vis green
graphics.strokeRect(startX, startY, width, height);
// Corner markers
graphics.fillStyle(0xFFFFFF, 0.9);
const markerSize = 8;
graphics.fillRect(startX - markerSize / 2, startY - markerSize / 2, markerSize, markerSize);
graphics.fillRect(startX + width - markerSize / 2, startY - markerSize / 2, markerSize, markerSize);
graphics.fillRect(startX - markerSize / 2, startY + height - markerSize / 2, markerSize, markerSize);
graphics.fillRect(startX + width - markerSize / 2, startY + height - markerSize / 2, markerSize, markerSize);
graphics.fillStyle(0xFFFF00, 1);
const markerSize = 12;
graphics.fillCircle(startX, startY, markerSize);
graphics.fillCircle(startX + width, startY, markerSize);
graphics.fillCircle(startX, startY + height, markerSize);
graphics.fillCircle(startX + width, startY + height, markerSize);
graphics.setDepth(5); // Above ground, below player
// Store graphics for later updates
graphics.setDepth(50);
this.boundaryGraphics = graphics;
console.log(`🏰 Dual platforms rendered: Master (${largeSize}x${largeSize}) & Micro (${this.farmSize}x${this.farmSize})`);
}
renderLockedTileOverlay() {
// Render dark overlay on locked tiles
if (!this.scene || !this.lockedOverlayGraphics) {
// Create overlay graphics if not exists
this.lockedOverlayGraphics = this.scene.add.graphics();
this.lockedOverlayGraphics.setDepth(4); // Above ground, below boundaries
if (this.lockedOverlayGraphics) {
this.lockedOverlayGraphics.destroy();
}
this.lockedOverlayGraphics = this.scene.add.graphics();
this.lockedOverlayGraphics.setDepth(4); // Above ground, below boundaries
this.lockedOverlayGraphics.clear();
// Darken all tiles that are NOT unlocked
@@ -220,10 +246,11 @@ class MicroFarmSystem {
}
// Draw dark overlay (lighter)
const worldX = x * 48;
const worldY = y * 48;
const tileSize = (this.scene.terrainSystem && this.scene.terrainSystem.tileSize) || 48;
const worldX = x * tileSize;
const worldY = y * tileSize;
this.lockedOverlayGraphics.fillStyle(0x000000, 0.3); // 0.5 -> 0.3
this.lockedOverlayGraphics.fillRect(worldX, worldY, 48, 48);
this.lockedOverlayGraphics.fillRect(worldX, worldY, tileSize, tileSize);
}
}

View File

@@ -35,7 +35,7 @@ class PathfindingSystem {
// 🗺️ 1. TILED MAP SUPPORT
if (ts.tiledMap) {
// Check various obstacle layers
const obstacleLayers = ['Obstacles', 'Buildings', 'Fences', '02_Obstacles', '03_Fences', '04_Buildings'];
const obstacleLayers = ['Obstacles', 'Buildings', 'Fences', 'Objects', '02_Obstacles', '03_Fences', '04_Buildings'];
let isBlocked = false;
for (const layerName of obstacleLayers) {

View File

@@ -81,7 +81,7 @@ class StructureSystem {
const sampleRate = 50;
for (let x = 0; x < this.worldWidth; x += sampleRate) {
for (let y = 0; y < this.worldHeight; y += sampleRate) {
const biome = this.biomeSystem.getBiome(x, y);
const biome = this.biomeSystem.getBiomeAt(x, y);
if (!biomeLocations[biome]) biomeLocations[biome] = [];
biomeLocations[biome].push({ x, y });
}
@@ -91,7 +91,9 @@ class StructureSystem {
const roadPoints = [];
// Central hub (spawn point)
roadPoints.push({ x: 250, y: 250, name: 'Center' });
const centerX = Math.floor(this.worldWidth / 2);
const centerY = Math.floor(this.worldHeight / 2);
roadPoints.push({ x: centerX, y: centerY, name: 'Center' });
// Add one major location per biome
for (const [biomeName, locations] of Object.entries(biomeLocations)) {
@@ -228,7 +230,7 @@ class StructureSystem {
// Check if location is valid
if (this.canPlaceStructure(x, y, 20)) {
const biome = this.biomeSystem.getBiome(x, y);
const biome = this.biomeSystem.getBiomeAt(x, y);
const types = this.structureTypes[biome];
if (types && types.length > 0) {
@@ -334,7 +336,7 @@ class StructureSystem {
const x = Math.floor(Math.random() * this.worldWidth);
const y = Math.floor(Math.random() * this.worldHeight);
const biome = this.biomeSystem.getBiome(x, y);
const biome = this.biomeSystem.getBiomeAt(x, y);
if (biome === biomeName && this.canPlaceStructure(x, y, minDistance)) {
return { x, y };