diff --git a/assets/tree_blue_final.png b/assets/tree_blue_final.png new file mode 100644 index 0000000..5f028fb Binary files /dev/null and b/assets/tree_blue_final.png differ diff --git a/assets/tree_dead_final.png b/assets/tree_dead_final.png new file mode 100644 index 0000000..d0dd534 Binary files /dev/null and b/assets/tree_dead_final.png differ diff --git a/assets/tree_green_final.png b/assets/tree_green_final.png new file mode 100644 index 0000000..e9d0dab Binary files /dev/null and b/assets/tree_green_final.png differ diff --git a/src/entities/NPC.js b/src/entities/NPC.js index f6cf5f2..6b0322a 100644 --- a/src/entities/NPC.js +++ b/src/entities/NPC.js @@ -493,7 +493,10 @@ class NPC { if (!this.sprite) return; if (this.lastDepthY === undefined || Math.abs(this.sprite.y - this.lastDepthY) > 0.1) { - this.sprite.setDepth(this.sprite.y); + const layerBase = this.iso.LAYER_OBJECTS || 200000; + const depth = layerBase + this.sprite.y; + + this.sprite.setDepth(depth); this.lastDepthY = this.sprite.y; // Update attached elements depth diff --git a/src/entities/Player.js b/src/entities/Player.js index eeca753..1697fbf 100644 --- a/src/entities/Player.js +++ b/src/entities/Player.js @@ -133,6 +133,51 @@ class Player { left: Phaser.Input.Keyboard.KeyCodes.A, right: Phaser.Input.Keyboard.KeyCodes.D }); + + // Gamepad Events + this.scene.input.gamepad.on('connected', (pad) => { + this.setupGamepadEvents(pad); + }); + + if (this.scene.input.gamepad.total > 0) { + this.setupGamepadEvents(this.scene.input.gamepad.getPad(0)); + } + } + + setupGamepadEvents(pad) { + if (!pad) return; + console.log('🎮 Gamepad Connected:', pad.id); + + pad.on('down', (index) => { + if (this.isDead) return; + + // A Button (0) - Attack + if (index === 0) { + this.attack(); + } + + // X Button (2) - Interact (Pick/Tame) + if (index === 2) { + const targetX = this.gridX + this.lastDir.x; + const targetY = this.gridY + this.lastDir.y; + if (this.scene.interactionSystem) { + this.scene.interactionSystem.handleInteraction(targetX, targetY); + } + } + + // Y Button (3) - Crafting + if (index === 3) { + // Zahteva, da UIScene posluša ta event, ali pa direktni klic + const ui = this.scene.scene.get('UIScene'); + if (ui) ui.toggleCrafting(); + } + + // B Button (1) - Inventory + if (index === 1) { + const ui = this.scene.scene.get('UIScene'); + if (ui) ui.toggleInventory(); + } + }); } attack() { @@ -224,6 +269,24 @@ class Player { if (ui.virtualJoystick.right) right = true; } + // Check Gamepad Input (Xbox Controller) + if (this.scene.input.gamepad && this.scene.input.gamepad.total > 0) { + const pad = this.scene.input.gamepad.getPad(0); + if (pad) { + const threshold = 0.3; + if (pad.leftStick.y < -threshold) up = true; + if (pad.leftStick.y > threshold) down = true; + if (pad.leftStick.x < -threshold) left = true; + if (pad.leftStick.x > threshold) right = true; + + // D-Pad support + if (pad.up) up = true; + if (pad.down) down = true; + if (pad.left) left = true; + if (pad.right) right = true; + } + } + // Apply let dx = 0; let dy = 0; @@ -354,8 +417,12 @@ class Player { // Optimization: Create dirty check if (this.lastDepthY === undefined || Math.abs(this.sprite.y - this.lastDepthY) > 0.1) { - this.sprite.setDepth(this.sprite.y); - if (this.handSprite) this.handSprite.setDepth(this.sprite.y + 1); + // Uporabi LAYER_OBJECTS da se pravilno sortira z drevesi/kamni + const layerBase = this.iso.LAYER_OBJECTS || 200000; + const depth = layerBase + this.sprite.y; + + this.sprite.setDepth(depth); + if (this.handSprite) this.handSprite.setDepth(depth + 1); this.lastDepthY = this.sprite.y; } } diff --git a/src/scenes/BootScene.js b/src/scenes/BootScene.js index 55b0988..592d76a 100644 --- a/src/scenes/BootScene.js +++ b/src/scenes/BootScene.js @@ -40,6 +40,12 @@ class BootScene extends Phaser.Scene { console.log('✅ BootScene: Complete!'); window.gameState.currentScene = 'BootScene'; + // Global Constants for Sprites + window.SPRITE_TREE_HEALTHY = 'tree_green_final'; + window.SPRITE_TREE_BLUE = 'tree_blue_final'; + window.SPRITE_TREE_DEAD = 'tree_dead_final'; + window.SPRITE_TREE_SAPLING = 'tree_sapling'; + // Takoj po bootu gremo v PreloadScene this.time.delayedCall(100, () => { this.scene.start('PreloadScene'); diff --git a/src/scenes/GameScene.js b/src/scenes/GameScene.js index 42fe8cd..babb51b 100644 --- a/src/scenes/GameScene.js +++ b/src/scenes/GameScene.js @@ -265,9 +265,10 @@ class GameScene extends Phaser.Scene { ); } - // Terrain Culling + // Terrain Culling & Update if (this.terrainSystem) { this.terrainSystem.updateCulling(this.cameras.main); + this.terrainSystem.update(delta); } // Clouds diff --git a/src/scenes/PreloadScene.js b/src/scenes/PreloadScene.js index fe3dea4..3e1a3a1 100644 --- a/src/scenes/PreloadScene.js +++ b/src/scenes/PreloadScene.js @@ -36,11 +36,18 @@ class PreloadScene extends Phaser.Scene { this.load.image('tree_dead', 'assets/tree_dead.png'); this.load.image('rock_asset', 'assets/rock_asset.png'); + // FINAL TREES (User Uploaded) + this.load.image('tree_green_final', 'assets/tree_green_final.png'); + this.load.image('tree_blue_final', 'assets/tree_blue_final.png'); + this.load.image('tree_dead_final', 'assets/tree_dead_final.png'); + // NEW transparent tree/rock assets - this.load.image('tree_blue_new', 'assets/tree_blue_new.png'); + this.load.image('tree_blue_new', 'assets/tree_blue_new.png'); // Keep for backup + this.load.image('tree_green_new', 'assets/tree_green_new.png'); this.load.image('rock_1', 'assets/rock_1.png'); this.load.image('rock_2', 'assets/rock_2.png'); + this.load.image('rock_small', 'assets/rock_small.png'); this.load.image('tree_dead_new', 'assets/tree_dead_new.png'); this.load.image('flowers_new', 'assets/flowers_new.png'); this.load.image('hill_sprite', 'assets/hill_sprite.png'); @@ -102,11 +109,18 @@ class PreloadScene extends Phaser.Scene { 'tree_blue', 'tree_dead', 'rock_asset', + + // FINAL TREES + 'tree_green_final', + 'tree_blue_final', + 'tree_dead_final', + // NEW transparent assets 'tree_blue_new', 'tree_green_new', 'rock_1', 'rock_2', + 'rock_small', 'tree_dead_new', 'flowers_new', 'hill_sprite', @@ -151,9 +165,13 @@ class PreloadScene extends Phaser.Scene { const g = data[i + 1]; const b = data[i + 2]; - // Remove white/light gray backgrounds (all sprites) - if (r > 200 && g > 200 && b > 200) { - data[i + 3] = 0; + // Remove white/light gray backgrounds (Checkerboard & White) + // Target grays: R,G,B should be similar and high value. + if (r > 150 && g > 150 && b > 150) { + // Check if it's grayscale (checkerboard is usually perfect gray) + if (Math.abs(r - g) < 30 && Math.abs(g - b) < 30) { + data[i + 3] = 0; + } } // Special: Remove brown/tan backgrounds (merchant sprite) diff --git a/src/scenes/UIScene.js b/src/scenes/UIScene.js index dadae57..fb1b930 100644 --- a/src/scenes/UIScene.js +++ b/src/scenes/UIScene.js @@ -49,6 +49,17 @@ class UIScene extends Phaser.Scene { toggleCraftingMenu() { if (!this.craftingContainer) this.createCraftingMenu(); this.craftingContainer.setVisible(!this.craftingContainer.visible); + // Pause/Resume game? + // if (this.gameScene) this.gameScene.physics.world.isPaused = this.craftingContainer.visible; + } + + toggleCrafting() { + this.toggleCraftingMenu(); + } + + toggleInventory() { + // Za zdaj odpre crafting meni, ker nimamo ločenega "Big Inventory" + this.toggleCraftingMenu(); } createCraftingMenu() { diff --git a/src/systems/InteractionSystem.js b/src/systems/InteractionSystem.js index 5eaea3b..3c18335 100644 --- a/src/systems/InteractionSystem.js +++ b/src/systems/InteractionSystem.js @@ -125,6 +125,26 @@ class InteractionSystem { } } + // 4. Try Planting Tree (Manual Planting) + if (!isAttack && (activeTool === 'tree_sapling' || activeTool === 'item_sapling')) { + const tile = this.scene.terrainSystem.getTile(gridX, gridY); + + // Dovolimo sajenje samo na travo in dirt + if (tile && !tile.hasDecoration && !tile.hasCrop && (tile.type.includes('grass') || tile.type.includes('dirt'))) { + const saplingSprite = window.SPRITE_TREE_SAPLING || 'tree_sapling'; + this.scene.terrainSystem.addDecoration(gridX, gridY, saplingSprite); + + // Remove 1 sapling from hand + if (this.scene.inventorySystem) { + this.scene.inventorySystem.removeItem(activeTool, 1); + } + + // Sound + // this.scene.soundManager.playPlant(); + return; + } + } + // 4. Try Farming Action if (this.scene.farmingSystem && !isAttack) { const didFarm = this.scene.farmingSystem.interact(gridX, gridY, activeTool); @@ -136,38 +156,74 @@ class InteractionSystem { if (this.scene.terrainSystem.decorationsMap.has(id)) { const decor = this.scene.terrainSystem.decorationsMap.get(id); + // handleTreeHit Logic (User Request) + // Preverimo tip in ustrezno orodje let damage = 1; - if (decor.type === 'tree') { - damage = (activeTool === 'axe') ? 3 : 1; + // DREVESA (sapling, healthy, dead, blue) + if (decor.type.includes('tree') || decor.type.includes('sapling')) { + damage = (activeTool === 'axe') ? 5 : 1; // Povečal damage z sekiro } - else if (decor.type === 'stone') { - damage = (activeTool === 'pickaxe') ? 3 : 1; + // KAMNI (rock, stone) + else if (decor.type.includes('rock') || decor.type.includes('stone')) { + damage = (activeTool === 'pickaxe') ? 5 : 1; } - else if (decor.type === 'bush') damage = 2; + else if (decor.type.includes('bush')) damage = 5; // Apply damage decor.hp -= damage; - this.showFloatingText(`${-damage}`, gridX, gridY, '#ffaaaa'); + this.showFloatingText(`-${damage}`, gridX, gridY, '#ffaaaa'); - // Chop Sound + // Sound if (this.scene.soundManager) { - this.scene.soundManager.playChop(); + if (decor.type.includes('tree')) this.scene.soundManager.playChop(); + else this.scene.soundManager.playHit(); // Generic hit for rocks } if (decor.hp <= 0) { - const type = this.scene.terrainSystem.removeDecoration(gridX, gridY); - // Loot logic via LootSystem - let loot = 'wood'; - if (type === 'stone') loot = 'stone'; - if (type === 'bush') loot = 'seeds'; // Maybe berries? + const prevType = decor.type; - if (this.scene.lootSystem) { - if (type === 'tree') { - this.scene.lootSystem.spawnLoot(gridX, gridY, 'wood', 3); + // Logic: If Tree (and not sapling), turn into Sapling immediately (Regrowth) + if ((prevType.includes('tree') || prevType.includes('final')) && !prevType.includes('sapling')) { + + decor.type = window.SPRITE_TREE_SAPLING || 'tree_sapling'; + decor.hp = 2; // Fragile sapling + decor.scale = 1.0; + + // Update visual immediately + const sprite = this.scene.terrainSystem.visibleDecorations.get(id); + if (sprite) { + sprite.setTexture(decor.type); + sprite.setScale(decor.scale); + // Shrink effect to simulate falling/replacement + this.scene.tweens.add({ + targets: sprite, scaleX: { from: 1.2, to: 1.0 }, scaleY: { from: 1.2, to: 1.0 }, duration: 200 + }); } - else { - this.scene.lootSystem.spawnLoot(gridX, gridY, loot, 1); + + // Drop Wood Only + if (this.scene.lootSystem) { + this.scene.lootSystem.spawnLoot(gridX, gridY, 'item_wood', Math.floor(Math.random() * 3) + 2); + } + console.log('🌱 Tree replanted automatically.'); + } + else { + const type = this.scene.terrainSystem.removeDecoration(gridX, gridY); + + // Loot logic handled here via LootSystem + if (this.scene.lootSystem) { + if (type.includes('rock') || type.includes('stone')) { + this.scene.lootSystem.spawnLoot(gridX, gridY, 'item_stone', Math.floor(Math.random() * 3) + 1); + } + else if (type.includes('bush') || type.includes('sapling')) { + this.scene.lootSystem.spawnLoot(gridX, gridY, 'item_seeds', 1); + if (type.includes('sapling')) { + this.scene.lootSystem.spawnLoot(gridX, gridY, window.SPRITE_TREE_SAPLING || 'tree_sapling', 1); + } + } + else if (type.includes('flowers')) { + this.scene.lootSystem.spawnLoot(gridX, gridY, 'item_seeds', 1); + } } } diff --git a/src/systems/TerrainSystem.js b/src/systems/TerrainSystem.js index d58ece9..e907a76 100644 --- a/src/systems/TerrainSystem.js +++ b/src/systems/TerrainSystem.js @@ -9,6 +9,18 @@ const CITY_SIZE = 15; const CITY_START_X = 65; // Desni del mape (npr. med 65 in 80) const CITY_START_Y = 65; +// ======================================================== +// NOVE KONSTANTE ZA RUDNIK IN RUDE +// ======================================================== +const TILE_STONE_ORE = 82; // ID za navadni kamen (Ore Tile) +const TILE_IRON_ORE = 83; // ID za železovo rudo +const TILE_PAVEMENT = 16; // ID za prehodno ploščico (tla rudnika) +const TILE_MINE_WALL = 81; // ID za zid rudnika (Solid/Kolizija) + +// ID-ji Virov +const ITEM_STONE = 20; // ID za kamen, ki ga igralec dobi +const ITEM_IRON = 21; // ID za železo + // Terrain Generator System class TerrainSystem { constructor(scene, width = 100, height = 100) { @@ -23,6 +35,7 @@ class TerrainSystem { this.decorations = []; this.decorationsMap = new Map(); this.cropsMap = new Map(); + this.tileHealthMap = new Map(); // Global register zdravja ploščic this.visibleTiles = new Map(); this.visibleDecorations = new Map(); @@ -92,7 +105,12 @@ class TerrainSystem { PAVEMENT: { name: 'pavement', height: 0.6, color: 0x777777 }, RUINS: { name: 'ruins', height: 0.6, color: 0x555555 }, PATH: { name: 'path', height: -1, color: 0xc2b280 }, - FARMLAND: { name: 'farmland', height: -1, color: 0x5c4033 } + FARMLAND: { name: 'farmland', height: -1, color: 0x5c4033 }, + // MINE TYPES + MINE_FLOOR: { name: 'mine_floor', height: 0, color: 0x333333, id: TILE_PAVEMENT }, + MINE_WALL: { name: 'mine_wall', height: 1, color: 0x1a1a1a, id: TILE_MINE_WALL }, + ORE_STONE: { name: 'ore_stone', height: 0.5, color: 0x555555, id: TILE_STONE_ORE }, + ORE_IRON: { name: 'ore_iron', height: 0.5, color: 0x884444, id: TILE_IRON_ORE } }; this.offsetX = 0; @@ -218,6 +236,12 @@ class TerrainSystem { hasDecoration: false, hasCrop: false }; + + // Place Trees dynamically during generation + this.placeTree(x, y, terrainType.name); + + // Place Rocks dynamically + this.placeRock(x, y, terrainType.name); } } @@ -240,61 +264,12 @@ class TerrainSystem { } } - for (let i = validPositions.length - 1; i > 0; i--) { - const j = Math.floor(Math.random() * (i + 1)); - [validPositions[i], validPositions[j]] = [validPositions[j], validPositions[i]]; - } + // DECORATIONS REMOVED BY REQUEST + // Drevesa, kamni, rože in ruševine so odstranjeni. - for (let i = 0; i < Math.min(25, validPositions.length); i++) { - const pos = validPositions[i]; - let treeType = 'tree_green_new'; - const rand = Math.random(); - if (rand < 0.15) treeType = 'tree_blue_new'; - else if (rand < 0.25) treeType = 'tree_dead_new'; + // Ostalo je samo generiranje ploščic (tiles) in fixnih con (farm, city floor). - this.addDecoration(pos.x, pos.y, treeType); - treeCount++; - } - for (let i = 25; i < Math.min(50, validPositions.length); i++) { - const pos = validPositions[i]; - // Uporabi uporabnikove kamne - const rockType = Math.random() > 0.5 ? 'rock_1' : 'rock_2'; - this.addDecoration(pos.x, pos.y, rockType); - rockCount++; - } - - const flowerNoise = new PerlinNoise(Date.now() + 3000); - for (let y = 5; y < this.height - 5; y++) { - for (let x = 5; x < this.width - 5; x++) { - if (isFarm(x, y) || isCity(x, y)) continue; - - const tile = this.tiles[y][x]; - const val = flowerNoise.noise(x * 0.12, y * 0.12); - if (val > 0.85 && tile.type.includes('grass')) { - this.addDecoration(x, y, 'flowers_new'); - flowerCount++; - } - } - } - - - const roomSize = 5; - const roomsAcross = Math.floor(CITY_SIZE / roomSize); - - for (let ry = 0; ry < roomsAcross; ry++) { - for (let rx = 0; rx < roomsAcross; rx++) { - if (Math.random() < 0.75) { - const gx = CITY_START_X + rx * roomSize; - const gy = CITY_START_Y + ry * roomSize; - this.placeStructure(gx, gy, 'ruin_room'); - } else { - const gx = CITY_START_X + rx * roomSize + 2; - const gy = CITY_START_Y + ry * roomSize + 2; - const rockType = Math.random() > 0.5 ? 'rock_1' : 'rock_2'; - this.addDecoration(gx, gy, rockType); - } - } - } + console.log(`✅ Teren generiran (CLEAN): ${treeCount} dreves, ${rockCount} kamnov.`); console.log(`✅ Teren generiran: ${treeCount} dreves, ${rockCount} kamnov.`); } @@ -356,6 +331,80 @@ class TerrainSystem { } } + placeTree(x, y, tileType) { + // 1. Safety Checks + if (!tileType || !tileType.includes('grass')) return; + + const isFarm = Math.abs(x - FARM_CENTER_X) <= FARM_SIZE / 2 + 2; + const isCity = x >= CITY_START_X - 2 && x < CITY_START_X + CITY_SIZE + 2 && y >= CITY_START_Y - 2 && y < CITY_START_Y + CITY_SIZE + 2; + if (isFarm || isCity) return; + + // 2. Noise for clustering (Forests) + // Offset inputs to decouple from terrain height noise + const noiseVal = this.noise.noise(x * 0.1 + 123.45, y * 0.1 + 678.90); + + // 3. Selection Logic (Scattered & Saplings focus) + let shouldPlace = false; + let type = window.SPRITE_TREE_HEALTHY || 'tree_green_final'; + + // Bolj enakomerna porazdelitev (Scattered) + // Noise uporabimo le za rahlo variacijo, ne za stroge gruče + let chance = 0.015; // 1.5% base chance (zelo redko) + + if (noiseVal > 0.30) chance = 0.03; // Malo večja gostota v "gozdu" + + if (Math.random() < chance) { + shouldPlace = true; + + // Variants Logic + const r = Math.random(); + // 50% možnosti, da je drevo komaj začelo rasti (Sapling) + if (r < 0.50) type = window.SPRITE_TREE_SAPLING || 'tree_sapling'; + else if (r < 0.60) type = window.SPRITE_TREE_DEAD || 'tree_dead_final'; + else if (r < 0.65) type = window.SPRITE_TREE_BLUE || 'tree_blue_final'; + // Ostalo (35%) je odraslo drevo + } + + // 4. Placement + if (shouldPlace) { + this.addDecoration(x, y, type); + } + } + + placeRock(x, y, tileType) { + if (!tileType || !tileType.includes('grass') && !tileType.includes('dirt')) return; + + const isFarm = Math.abs(x - FARM_CENTER_X) <= FARM_SIZE / 2 + 2; + const isCity = x >= CITY_START_X - 2 && x < CITY_START_X + CITY_SIZE + 2 && y >= CITY_START_Y - 2 && y < CITY_START_Y + CITY_SIZE + 2; + if (isFarm || isCity) return; + + // Če je že dekoracija (drevo), ne dajaj kamna + if (this.tiles[y][x].hasDecoration) return; + + // Noise for Rock Clusters + const noiseVal = this.noise.noise(x * 0.15 + 99.99, y * 0.15 + 88.88); + + let shouldPlace = false; + let type = 'rock_1'; // Default + + let chance = 0.01; // 1% Scattered chance + + if (noiseVal > 0.45) { // Rock Cluster Area + chance = 0.30; // High density in cluster + } + + if (Math.random() < chance) { + shouldPlace = true; + // Variants - "Lepi kamni" (rock_asset) + // Odstranili smo nedokončane velike kamne + type = 'rock_asset'; + } + + if (shouldPlace) { + this.addDecoration(x, y, type); + } + } + placeStructure(gridX, gridY, type) { if (type === 'ruin') { for (let y = 0; y < 6; y++) { @@ -422,6 +471,7 @@ class TerrainSystem { else if (type === 'fence') scale = 0.025; else if (type === 'gravestone') scale = 0.03; else if (type === 'hill_sprite') scale = 0.025; + else if (type.includes('_final')) scale = 1.0; // New Final Trees else { // Old Assets (Low Res) if (type.includes('tree')) scale = 1.2 + Math.random() * 0.4; @@ -429,6 +479,15 @@ class TerrainSystem { else scale = 1.0; } + // Calculate Plant Day for Saplings (Growth System) + let plantDay = -1; + if (type.includes('sapling')) { + const w = this.scene.weatherSystem; + plantDay = w ? w.getDayCount() : 1; + // Random init offset for initial generation + if (!w) plantDay = 1 - Math.floor(Math.random() * 2); + } + const decorData = { gridX: gridX, gridY: gridY, @@ -436,7 +495,8 @@ class TerrainSystem { id: key, maxHp: 10, hp: 10, - scale: scale + scale: scale, + plantDay: plantDay // Added for Growth System }; this.decorations.push(decorData); this.decorationsMap.set(key, decorData); @@ -535,7 +595,7 @@ class TerrainSystem { sprite.setTexture(tile.type); const screenPos = this.iso.toScreen(x, y); sprite.setPosition(screenPos.x + this.offsetX, screenPos.y + this.offsetY); - sprite.setDepth(this.iso.getDepth(x, y)); + sprite.setDepth(this.iso.getDepth(x, y, this.iso.LAYER_FLOOR)); // Tiles = Floor this.visibleTiles.set(key, sprite); } } @@ -552,6 +612,7 @@ class TerrainSystem { if (decor.type.includes('house') || decor.type.includes('market') || decor.type.includes('structure')) { sprite.setOrigin(0.5, 0.8); } else { + // DREVESA: Origin na dno, da Y-sort deluje sprite.setOrigin(0.5, 1.0); } @@ -562,7 +623,8 @@ class TerrainSystem { sprite.setAlpha(decor.alpha); } - sprite.setDepth(this.iso.getDepth(x, y) + 1); + // Layer Objects + sprite.setDepth(this.iso.getDepth(x, y, this.iso.LAYER_OBJECTS)); this.visibleDecorations.set(key, sprite); } } @@ -576,7 +638,8 @@ class TerrainSystem { sprite.setPosition(screenPos.x + this.offsetX, screenPos.y + this.offsetY - voxelOffset); sprite.setTexture(`crop_stage_${crop.stage}`); sprite.setOrigin(0.5, 1); - sprite.setDepth(this.iso.getDepth(x, y) + 0.5); + // Layer Objects (da igralec hodi okoli njih) + sprite.setDepth(this.iso.getDepth(x, y, this.iso.LAYER_OBJECTS)); this.visibleCrops.set(key, sprite); } } @@ -605,4 +668,48 @@ class TerrainSystem { } } } + + getTile(x, y) { + if (x >= 0 && x < this.width && y >= 0 && y < this.height) { + return this.tiles[y][x]; + } + return null; + } + + update(delta) { + this.growthTimer = (this.growthTimer || 0) + delta; + if (this.growthTimer < 5000) return; + this.growthTimer = 0; + + const weather = this.scene.weatherSystem; + if (!weather) return; + const currentDay = weather.getDayCount(); + + const healthyType = window.SPRITE_TREE_HEALTHY || 'tree_green_final'; + + for (const decor of this.decorationsMap.values()) { + if (decor.type.includes('sapling')) { + if (decor.plantDay !== undefined && decor.plantDay > -100 && (currentDay - decor.plantDay >= 3)) { + decor.type = healthyType; + decor.scale = 1.0; + decor.hp = 10; + decor.plantDay = -1; + + const key = decor.id; + if (this.visibleDecorations.has(key)) { + const sprite = this.visibleDecorations.get(key); + sprite.setTexture(decor.type); + sprite.setScale(decor.scale); + this.scene.tweens.add({ + targets: sprite, + scaleY: { from: 0.1, to: decor.scale }, + duration: 800, + ease: 'Bounce.out' + }); + console.log(`🌳 Tree grew on Day ${currentDay}`); + } + } + } + } + } } diff --git a/src/utils/IsometricUtils.js b/src/utils/IsometricUtils.js index 9139e57..47e96be 100644 --- a/src/utils/IsometricUtils.js +++ b/src/utils/IsometricUtils.js @@ -4,6 +4,12 @@ class IsometricUtils { constructor(tileWidth = 48, tileHeight = 24) { this.tileWidth = tileWidth; this.tileHeight = tileHeight; + + // Layer Constants + this.LAYER_FLOOR = 0; + this.LAYER_GRID_DECO = 100000; // Decorations on floor (shadows) + this.LAYER_OBJECTS = 200000; // Dynamic entities (Trees, Player, NPCs) + this.LAYER_UI = 300000; } // Kartezične (grid) koordinate -> Isometrične (screen) koordinate @@ -21,12 +27,10 @@ class IsometricUtils { } // Izračun depth (z-index) za pravilno sortiranje - // Izračun depth (z-index) - // V Phaserju je najbolje uporabiti kar Y koordinato spritha. - // Tu vrnemo pričakovano Y pozicijo za grid celico. - getDepth(gridX, gridY) { - // (gridX + gridY) * tileHeight/2 je točno screenY - return (gridX + gridY) * (this.tileHeight / 2); + getDepth(gridX, gridY, layerBase = 0) { + // Depth = LayerBase + ScreenY + // To zagotovi, da so objekti v layerju sortirani po Y + return layerBase + ((gridX + gridY) * (this.tileHeight / 2)); } // Izračun centerja tile-a diff --git a/src/utils/TextureGenerator.js b/src/utils/TextureGenerator.js index 2e876ef..29ed1be 100644 --- a/src/utils/TextureGenerator.js +++ b/src/utils/TextureGenerator.js @@ -311,6 +311,26 @@ class TextureGenerator { }); } + static createSaplingSprite(scene, key = 'tree_sapling') { + if (scene.textures.exists(key)) return; + const size = 32; + const canvas = scene.textures.createCanvas(key, size, size); + const ctx = canvas.getContext(); + ctx.clearRect(0, 0, size, size); + + // Majhno steblo + ctx.fillStyle = '#8B4513'; + ctx.fillRect(14, 20, 4, 12); + + // Parnosti listov + ctx.fillStyle = '#32CD32'; + ctx.beginPath(); ctx.arc(12, 18, 4, 0, Math.PI * 2); ctx.fill(); + ctx.beginPath(); ctx.arc(20, 18, 4, 0, Math.PI * 2); ctx.fill(); + ctx.beginPath(); ctx.arc(16, 12, 5, 0, Math.PI * 2); ctx.fill(); + + canvas.refresh(); + } + // Helper to generate ALL textures at once generateAll() { TextureGenerator.createPlayerSprite(this.scene); @@ -319,6 +339,7 @@ class TextureGenerator { TextureGenerator.createFlowerSprite(this.scene); TextureGenerator.createBushSprite(this.scene); + TextureGenerator.createSaplingSprite(this.scene, 'tree_sapling'); // Dodano TextureGenerator.createTreeSprite(this.scene); // Volumetric TextureGenerator.createRockSprite(this.scene); // Volumetric TextureGenerator.createCloudSprite(this.scene);