Fix Biome System integration, memory optimization, and Tiled live sync workflow
This commit is contained in:
@@ -10,7 +10,8 @@ class Player {
|
||||
this.offsetX = offsetX;
|
||||
this.offsetY = offsetY;
|
||||
|
||||
this.iso = new IsometricUtils(48, 24);
|
||||
this.tileSize = (this.scene.terrainSystem && this.scene.terrainSystem.tileSize) || 48;
|
||||
this.iso = new IsometricUtils(this.tileSize, this.tileSize / 2);
|
||||
|
||||
// 🎮 SMOOTH MOVEMENT SYSTEM (Hybrid)
|
||||
this.moveSpeed = 100; // Normal speed px/s
|
||||
@@ -116,10 +117,9 @@ class Player {
|
||||
|
||||
// Kreira sprite
|
||||
// 🎨 FLAT 2D (NEW!) - Direct screen conversion
|
||||
const tileSize = 48;
|
||||
const screenPos = {
|
||||
x: Math.round((this.gridX * tileSize) + (tileSize / 2)),
|
||||
y: Math.round((this.gridY * tileSize) + (tileSize / 2))
|
||||
x: Math.round((this.gridX * this.tileSize) + (this.tileSize / 2)),
|
||||
y: Math.round((this.gridY * this.tileSize) + (this.tileSize / 2))
|
||||
};
|
||||
this.sprite = this.scene.add.sprite(
|
||||
screenPos.x + this.offsetX,
|
||||
@@ -275,9 +275,8 @@ class Player {
|
||||
const screenPos = { x: this.sprite.x - this.offsetX, y: this.sprite.y - this.offsetY };
|
||||
|
||||
// 🎨 FLAT 2D (NEW!) - Direct grid conversion
|
||||
const tileSize = 48;
|
||||
this.gridX = Math.floor(screenPos.x / tileSize);
|
||||
this.gridY = Math.floor(screenPos.y / tileSize);
|
||||
this.gridX = Math.floor(screenPos.x / this.tileSize);
|
||||
this.gridY = Math.floor(screenPos.y / this.tileSize);
|
||||
|
||||
// Check if moving
|
||||
const speed = Math.sqrt(this.velocity.x ** 2 + this.velocity.y ** 2);
|
||||
|
||||
@@ -71,14 +71,21 @@ class GameScene extends Phaser.Scene {
|
||||
}
|
||||
|
||||
// 🎨 2D FLAT TERRAIN SYSTEM (NEW!)
|
||||
this.worldWidth = 100;
|
||||
this.worldHeight = 100;
|
||||
console.log('🎨 Initializing Flat 2D Terrain...');
|
||||
this.terrainSystem = new Flat2DTerrainSystem(this);
|
||||
|
||||
// 🏗️ PHASE 28-29 SYSTEMS INITIALIZATION
|
||||
try {
|
||||
// 🌍 PHASE 28: Initialize BiomeSystem and ChunkManager BEFORE terrain generation!
|
||||
console.log('🌍 Initializing Biome System (500x500 world)...');
|
||||
const w = this.worldWidth || 100;
|
||||
const h = this.worldHeight || 100;
|
||||
|
||||
console.log(`🌍 Initializing Biome System (${w}x${h} world)...`);
|
||||
this.biomeSystem = new BiomeSystem(this);
|
||||
this.biomeSystem.worldWidth = w;
|
||||
this.biomeSystem.worldHeight = h;
|
||||
this.biomeSystem.generateBiomeMap(); // Generate biome layout
|
||||
console.log('✅ Biome map generated!');
|
||||
|
||||
@@ -94,19 +101,19 @@ class GameScene extends Phaser.Scene {
|
||||
|
||||
// 🌊 PHASE 28 SESSION 5: RIVER SYSTEM
|
||||
console.log('🌊 Initializing River System...');
|
||||
this.riverSystem = new RiverSystem(500, 500, this.biomeSystem);
|
||||
this.riverSystem = new RiverSystem(w, h, this.biomeSystem);
|
||||
this.riverSystem.generateRivers();
|
||||
console.log('✅ River System ready!');
|
||||
|
||||
// 🏞️ PHASE 28 SESSION 5: LAKE SYSTEM
|
||||
console.log('🏞️ Initializing Lake System...');
|
||||
this.lakeSystem = new LakeSystem(500, 500, this.biomeSystem);
|
||||
this.lakeSystem = new LakeSystem(w, h, this.biomeSystem);
|
||||
this.lakeSystem.generateLakes(this.riverSystem);
|
||||
console.log('✅ Lake System ready!');
|
||||
|
||||
// 🏛️ PHASE 28 SESSION 6: STRUCTURE SYSTEM
|
||||
console.log('🏛️ Initializing Structure System...');
|
||||
this.structureSystem = new StructureSystem(500, 500, this.biomeSystem, this.riverSystem, this.lakeSystem);
|
||||
this.structureSystem = new StructureSystem(w, h, this.biomeSystem, this.riverSystem, this.lakeSystem);
|
||||
this.structureSystem.generateAll();
|
||||
const structStats = this.structureSystem.getStats();
|
||||
console.log(`✅ Structure System ready! (${structStats.structures} structures, ${structStats.landmarks} landmarks, ${structStats.roads.length} roads)`);
|
||||
@@ -157,7 +164,7 @@ class GameScene extends Phaser.Scene {
|
||||
}
|
||||
|
||||
// 🗺️ TRY TO LOAD USER'S TILED MAP FIRST
|
||||
let tiledMapLoaded = false;
|
||||
this.tiledMapLoaded = false;
|
||||
this.tiledSpawnPoint = null;
|
||||
|
||||
console.log('🔍 Checking for NovaFarma map...');
|
||||
@@ -176,7 +183,22 @@ class GameScene extends Phaser.Scene {
|
||||
if (map && map.width > 0) {
|
||||
console.log('✅ FOUND VALID USER MAP: NovaFarma.json');
|
||||
this.terrainSystem.loadFromTiled(map);
|
||||
tiledMapLoaded = true;
|
||||
this.tiledMapLoaded = true;
|
||||
|
||||
// UPDATE SYSTEM DIMENSIONS TO MATCH TILED MAP
|
||||
this.worldWidth = map.width;
|
||||
this.worldHeight = map.height;
|
||||
if (this.biomeSystem) {
|
||||
this.biomeSystem.worldWidth = map.width;
|
||||
this.biomeSystem.worldHeight = map.height;
|
||||
// Regenerate biome map for the new dimensions (optional, but consistent)
|
||||
this.biomeSystem.generateBiomeMap();
|
||||
}
|
||||
if (this.structureSystem) {
|
||||
this.structureSystem.worldWidth = map.width;
|
||||
this.structureSystem.worldHeight = map.height;
|
||||
this.structureSystem.generateAll(); // Re-generate for tiled map
|
||||
}
|
||||
|
||||
// 🕵️ FIND SPAWN POINT IN MAP
|
||||
const playerLayer = map.getLayer('Player');
|
||||
@@ -223,8 +245,10 @@ class GameScene extends Phaser.Scene {
|
||||
console.error('⚠️ CRITICAL ERROR loading NovaFarma map:', e);
|
||||
}
|
||||
|
||||
if (!tiledMapLoaded) {
|
||||
console.warn('⚠️ FALLBACK: Generating procedural terrain...');
|
||||
if (!this.tiledMapLoaded) {
|
||||
console.warn('⚠️ FALLBACK: Generating procedural terrain (100x100)...');
|
||||
this.terrainSystem.width = 100;
|
||||
this.terrainSystem.height = 100;
|
||||
await this.terrainSystem.generate();
|
||||
console.log('✅ Flat 2D terrain ready (Procedural)!');
|
||||
} else {
|
||||
@@ -240,9 +264,6 @@ class GameScene extends Phaser.Scene {
|
||||
this.buildSystem = new BuildSystem(this);
|
||||
console.log('🏗️ Build system initialized!');
|
||||
|
||||
// 🌱 Initialize Micro Farm System (PHASE 37!)
|
||||
this.microFarmSystem = new MicroFarmSystem(this);
|
||||
console.log('🌱 Micro Farm system initialized!');
|
||||
|
||||
|
||||
// ========================================================
|
||||
@@ -285,7 +306,7 @@ class GameScene extends Phaser.Scene {
|
||||
|
||||
|
||||
// Terrain offset
|
||||
if (tiledMapLoaded) {
|
||||
if (this.tiledMapLoaded) {
|
||||
// For Tiled maps, we usually start at 0,0 or map center is handled by camera
|
||||
this.terrainOffsetX = 0;
|
||||
this.terrainOffsetY = 0;
|
||||
@@ -551,30 +572,41 @@ class GameScene extends Phaser.Scene {
|
||||
console.log('👤 Initializing player...');
|
||||
const savedSpawn = localStorage.getItem('novafarma_spawn_point');
|
||||
|
||||
// 🌍 PHASE 28: Center of 500x500 world
|
||||
let playerSpawnX = 250, playerSpawnY = 250; // Default center
|
||||
// 🌍 PHASE 28: Initial spawn positioning
|
||||
let playerSpawnX, playerSpawnY;
|
||||
|
||||
if (this.tiledSpawnPoint) {
|
||||
// Use Tiled spawn point (converted to grid)
|
||||
// Note: Player class converts Grid -> Pixel (Grid * 48).
|
||||
// Tiled map gives Pixels.
|
||||
// We need to pass GRID coordinates that result in the correct Pixel.
|
||||
// TargetPixel = Grid * 48
|
||||
// Grid = TargetPixel / 48
|
||||
playerSpawnX = Math.floor(this.tiledSpawnPoint.x / 48);
|
||||
playerSpawnY = Math.floor(this.tiledSpawnPoint.y / 48);
|
||||
playerSpawnX = Math.floor(this.tiledSpawnPoint.x / this.terrainSystem.tileSize);
|
||||
playerSpawnY = Math.floor(this.tiledSpawnPoint.y / this.terrainSystem.tileSize);
|
||||
console.log(`👤 Spawning player at Tiled location: Grid(${playerSpawnX}, ${playerSpawnY}) -> Pixel(${this.tiledSpawnPoint.x}, ${this.tiledSpawnPoint.y})`);
|
||||
} else if (this.tiledMapLoaded) {
|
||||
// Default to map center for Tiled maps
|
||||
playerSpawnX = Math.floor(this.terrainSystem.width / 2);
|
||||
playerSpawnY = Math.floor(this.terrainSystem.height / 2);
|
||||
console.log(`👤 Spawning player at Tiled MAP CENTER: (${playerSpawnX}, ${playerSpawnY})`);
|
||||
} else if (savedSpawn) {
|
||||
[playerSpawnX, playerSpawnY] = savedSpawn.split(',').map(Number);
|
||||
console.log(`👤 Spawning player at saved location: (${playerSpawnX}, ${playerSpawnY})`);
|
||||
} else {
|
||||
console.log(`👤 Spawning player at world center: (${playerSpawnX}, ${playerSpawnY})`);
|
||||
playerSpawnX = 250;
|
||||
playerSpawnY = 250;
|
||||
console.log(`👤 Spawning player at default world center: (${playerSpawnX}, ${playerSpawnY})`);
|
||||
}
|
||||
|
||||
this.player = new Player(this, playerSpawnX, playerSpawnY, this.terrainOffsetX, this.terrainOffsetY);
|
||||
|
||||
// 🌍 PHASE 28: Load initial chunks around player
|
||||
if (this.chunkManager) {
|
||||
// 🌱 Initialize Micro Farm System (PHASE 37!)
|
||||
this.microFarmSystem = new MicroFarmSystem(this);
|
||||
if (playerSpawnX !== undefined && playerSpawnY !== undefined) {
|
||||
this.microFarmSystem.farmCenterX = playerSpawnX;
|
||||
this.microFarmSystem.farmCenterY = playerSpawnY;
|
||||
this.microFarmSystem.init(); // Re-initialize with correct center
|
||||
console.log(`🌱 Micro Farm system centered at (${playerSpawnX}, ${playerSpawnY})!`);
|
||||
}
|
||||
|
||||
// 🌍 PHASE 28: Load initial chunks around player (Procedural ONLY)
|
||||
if (this.chunkManager && !this.tiledMapLoaded) {
|
||||
console.log('💾 Loading initial chunks around player...');
|
||||
this.chunkManager.updateActiveChunks(playerSpawnX, playerSpawnY);
|
||||
const stats = this.chunkManager.getStats();
|
||||
@@ -1181,6 +1213,13 @@ class GameScene extends Phaser.Scene {
|
||||
if (this.buildSystem) this.buildSystem.toggleBuildMode();
|
||||
});
|
||||
|
||||
// 🕸️ Grid Toggle (G key)
|
||||
this.input.keyboard.on('keydown-G', () => {
|
||||
if (this.terrainSystem && this.terrainSystem.toggleGrid) {
|
||||
this.terrainSystem.toggleGrid();
|
||||
}
|
||||
});
|
||||
|
||||
this.input.keyboard.on('keydown-ONE', () => {
|
||||
if (this.buildSystem && this.buildSystem.buildMode) this.buildSystem.selectBuilding('fence_post');
|
||||
else if (this.scene.get('UIScene')) this.scene.get('UIScene').selectSlot(0);
|
||||
@@ -1860,8 +1899,8 @@ class GameScene extends Phaser.Scene {
|
||||
}
|
||||
}
|
||||
|
||||
// 🌍 PHASE 28: Update chunk loading based on player position
|
||||
if (this.chunkManager && this.player) {
|
||||
// 🌍 PHASE 28: Update chunk loading based on player position (ONLY for procedural maps!)
|
||||
if (this.chunkManager && this.player && !this.tiledMapLoaded) {
|
||||
const pos = this.player.getPosition();
|
||||
this.chunkManager.updateActiveChunks(pos.x, pos.y);
|
||||
}
|
||||
|
||||
@@ -30,14 +30,15 @@ class PreloadScene extends Phaser.Scene {
|
||||
this.load.image('tileset_water', 'assets/tilesets/water.png');
|
||||
this.load.image('tileset_dirt', 'assets/tilesets/dirt.png');
|
||||
this.load.image('tileset_decorations', 'assets/tilesets/decorations.png');
|
||||
this.load.image('tileset_camp_objects', 'assets/tilesets/camp_objects.png');
|
||||
this.load.image('tileset_starting_camp', 'assets/tilesets/starting_camp_topdown.png');
|
||||
|
||||
// 🗺️ TILED MAP (JSON export from Tiled Editor) - DISABLED (files removed)
|
||||
// this.load.tilemapTiledJSON('farm_map', 'assets/maps/farm_map.json');
|
||||
// this.load.tilemapTiledJSON('micro_farm_128x128', 'assets/maps/micro_farm_128x128.json'); // 🌾 Testna farma
|
||||
// this.load.tilemapTiledJSON('micro_farm_8x8', 'assets/maps/micro_farm_8x8.json'); // 🏕️ Manjša test mapa
|
||||
// 🗺️ TILED MAP (User's NovaFarma)
|
||||
// Add cache busting to force reload of new exports
|
||||
this.load.tilemapTiledJSON('NovaFarma', `assets/maps/NovaFarma.json?v=${Date.now()}`);
|
||||
// 🗺️ TILED MAP (User's NovaFarma / Testing)
|
||||
this.load.tilemapTiledJSON('NovaFarma', `assets/maps/testni_travnik.json?v=${Date.now()}`);
|
||||
|
||||
// 🎨 TILED TILESETS (Manual Loading)
|
||||
const kzPath = 'assets/narezano_in_majhno/krvava_zetev_sprites/';
|
||||
|
||||
@@ -25,6 +25,7 @@ class UIScene extends Phaser.Scene {
|
||||
this.createVirtualJoystick();
|
||||
this.createClock();
|
||||
this.createMinimap(); // NEW: Mini mapa
|
||||
this.createDevButtons(); // MacBook friendly restart
|
||||
// this.createDebugInfo(); // REMOVED - Using UnifiedStatsPanel
|
||||
|
||||
// Hide old debug panel if it exists
|
||||
@@ -647,6 +648,39 @@ class UIScene extends Phaser.Scene {
|
||||
this.clockText.setOrigin(0.5, 0.5);
|
||||
}
|
||||
|
||||
createDevButtons() {
|
||||
if (this.restartBtn) this.restartBtn.destroy();
|
||||
|
||||
// Position next to clock (top right, left of clock)
|
||||
const x = this.scale.width - 190;
|
||||
const y = 20;
|
||||
|
||||
// Small 🔄 button
|
||||
const btnBg = this.add.rectangle(x, y + 20, 30, 40, 0x000000, 0.5);
|
||||
btnBg.setStrokeStyle(2, 0xffffff, 0.8);
|
||||
btnBg.setInteractive({ useHandCursor: true });
|
||||
|
||||
const btnText = this.add.text(x, y + 20, '🔄', { fontSize: '18px' }).setOrigin(0.5);
|
||||
|
||||
btnBg.on('pointerdown', () => {
|
||||
console.log('🔄 Reloading game...');
|
||||
window.location.reload();
|
||||
});
|
||||
|
||||
// Tooltip
|
||||
const tooltip = this.add.text(x, y + 50, 'RESTART (F4)', {
|
||||
fontSize: '10px',
|
||||
backgroundColor: '#000000',
|
||||
padding: { x: 4, y: 2 }
|
||||
}).setOrigin(0.5).setVisible(false);
|
||||
|
||||
btnBg.on('pointerover', () => tooltip.setVisible(true));
|
||||
btnBg.on('pointerout', () => tooltip.setVisible(false));
|
||||
|
||||
this.restartBtn = this.add.container(0, 0, [btnBg, btnText, tooltip]);
|
||||
this.restartBtn.setDepth(2000);
|
||||
}
|
||||
|
||||
createResourcesDisplay() {
|
||||
const startX = this.scale.width - 160;
|
||||
const startY = 110; // Below gold display
|
||||
@@ -699,7 +733,8 @@ class UIScene extends Phaser.Scene {
|
||||
if (!this.resourceTexts) return;
|
||||
const text = this.resourceTexts[resource];
|
||||
if (text) {
|
||||
text.setText(`${resource.toUpperCase()}: ${amount}`);
|
||||
const displayAmount = amount !== undefined && amount !== null ? amount : 0;
|
||||
text.setText(`${resource.toUpperCase()}: ${displayAmount}`);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -736,7 +771,9 @@ class UIScene extends Phaser.Scene {
|
||||
}
|
||||
|
||||
updateAge(gen, age) {
|
||||
if (this.genText) this.genText.setText(`Gen: ${gen} | Age: ${age}`);
|
||||
const dGen = gen !== undefined ? gen : 1;
|
||||
const dAge = age !== undefined ? age : 18;
|
||||
if (this.genText) this.genText.setText(`Gen: ${dGen} | Age: ${dAge}`);
|
||||
}
|
||||
|
||||
updateGold(amount) {
|
||||
@@ -744,7 +781,8 @@ class UIScene extends Phaser.Scene {
|
||||
console.warn('goldText not ready yet, skipping update');
|
||||
return;
|
||||
}
|
||||
this.goldText.setText(`GOLD: ${amount}`);
|
||||
const displayAmount = amount !== undefined ? amount : 0;
|
||||
this.goldText.setText(`GOLD: ${displayAmount}`);
|
||||
}
|
||||
|
||||
// DEBUG INFO REMOVED - Now using UnifiedStatsPanel (TAB/F3)
|
||||
@@ -765,6 +803,16 @@ class UIScene extends Phaser.Scene {
|
||||
this.setBarValue(this.thirstBar, stats.thirst);
|
||||
}
|
||||
|
||||
// Sync XP and Level
|
||||
if (this.gameScene.player && this.XPBar && this.LevelDisplay) {
|
||||
const xp = this.gameScene.player.xp || 0;
|
||||
const maxXp = this.gameScene.player.maxXp || 100;
|
||||
const level = this.gameScene.player.level || 1;
|
||||
|
||||
this.setBarValue(this.XPBar, (xp / maxXp) * 100);
|
||||
this.LevelDisplay.setText(`${window.i18n.t('ui.lv', 'LV')}: ${level}`);
|
||||
}
|
||||
|
||||
// Update Zombie Stats Panel (starter zombie worker)
|
||||
if (this.gameScene.npcs && this.gameScene.npcs.length > 0) {
|
||||
const zombieWorker = this.gameScene.npcs.find(npc => npc.type === 'zombie' && npc.isTamed);
|
||||
@@ -1245,13 +1293,14 @@ class UIScene extends Phaser.Scene {
|
||||
|
||||
let objText = '';
|
||||
quest.objectives.forEach(obj => {
|
||||
const status = obj.done ? '✅' : '⬜';
|
||||
let desc = '';
|
||||
if (obj.type === 'collect') desc = `${obj.item}: ${obj.current}/${obj.amount}`;
|
||||
else if (obj.type === 'action') desc = `${obj.action}: ${obj.current}/${obj.amount}`;
|
||||
else if (obj.type === 'kill') desc = `Slay ${obj.target}: ${obj.current}/${obj.amount}`;
|
||||
const status = obj.done || obj.completed ? '✅' : '⬜';
|
||||
const current = obj.current !== undefined ? obj.current : 0;
|
||||
const required = obj.required || obj.amount || 1;
|
||||
|
||||
objText += `${status} ${desc}\n`;
|
||||
let desc = obj.description || obj.name || 'Objective';
|
||||
|
||||
// Format: [status] Description: 0/1
|
||||
objText += `${status} ${desc}: ${current}/${required}\n`;
|
||||
});
|
||||
|
||||
this.questObjectives.setText(objText);
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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 };
|
||||
|
||||
Reference in New Issue
Block a user