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

@@ -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);
}

View File

@@ -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/';

View File

@@ -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);