// Preload Scene - Nalaganje assetov class PreloadScene extends Phaser.Scene { constructor() { super({ key: 'PreloadScene' }); } preload() { console.log('⏳ PreloadScene: Loading assets...'); this.createLoadingBar(); // Load ALL custom sprites this.load.image('player_sprite', 'assets/player_sprite.png'); this.load.image('zombie_sprite', 'assets/zombie_sprite.png'); this.load.image('merchant_sprite', 'assets/merchant_sprite.png'); this.load.image('house_sprite', 'assets/house_sprite.png'); this.load.image('stone_sprite', 'assets/stone_sprite.png'); this.load.image('tree_sprite', 'assets/tree_sprite.png'); this.load.image('grass_sprite', 'assets/grass_sprite.png'); this.load.image('grass_tile', 'assets/grass_tile.png'); this.load.image('leaf_sprite', 'assets/leaf_sprite.png'); this.load.image('wheat_sprite', 'assets/wheat_sprite.png'); this.load.image('stone_texture', 'assets/stone_texture.png'); // New asset packs this.load.image('objects_pack', 'assets/objects_pack.png'); this.load.image('walls_pack', 'assets/walls_pack.png'); this.load.image('ground_tiles', 'assets/ground_tiles.png'); this.load.image('objects_pack2', 'assets/objects_pack2.png'); this.load.image('trees_vegetation', 'assets/trees_vegetation.png'); // User-uploaded pixel art assets (original) this.load.image('flowers', 'assets/flowers.png'); this.load.image('tree_green', 'assets/tree_green.png'); this.load.image('tree_blue', 'assets/tree_blue.png'); 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'); // STARDEW VALLEY FOREST TREES (NEW!) this.load.image('tree_purple', 'assets/tree_purple.png'); this.load.image('tree_apple', 'assets/tree_apple.png'); this.load.image('tree_pear', 'assets/tree_pear.png'); this.load.image('tree_cherry', 'assets/tree_cherry.png'); this.load.image('tree_sapling', 'assets/tree_green_final.png'); // Reuse green as sapling // NEW transparent tree/rock assets 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('merchant_new', 'assets/merchant_new.png'); this.load.image('elite_zombie', 'assets/elite_zombie.png'); // Fence old for abandoned houses this.load.image('fence_old', 'assets/fence_isometric.png'); // Reuse fence for old houses // AI-Generated NPC Sprites (with cache-busting) const cacheBust = Date.now(); this.load.image('cow', `assets/cow.png?v=${cacheBust}`); this.load.image('chicken', `assets/chicken.png?v=${cacheBust}`); this.load.image('troll', `assets/troll.png?v=${cacheBust}`); this.load.image('elf', `assets/elf.png?v=${cacheBust}`); this.load.image('villager', `assets/villager.png?v=${cacheBust}`); this.load.image('cow_mutant', `assets/cow_mutant.png?v=${cacheBust}`); this.load.image('hill_sprite', 'assets/hill_sprite.png'); this.load.image('fence', 'assets/fence.png'); this.load.image('gravestone', 'assets/gravestone.png'); // City content assets this.load.image('chest', 'assets/chest.png'); this.load.image('spawner', 'assets/spawner.png'); this.load.image('signpost_city', 'assets/signpost_city.png'); this.load.image('signpost_farm', 'assets/signpost_farm.png'); this.load.image('signpost_both', 'assets/signpost_both.png'); this.load.image('city_wall', 'assets/city_wall.png'); this.load.image('road_tile', 'assets/road_tile.png'); this.load.image('farm_zone', 'assets/farm_zone.png'); this.load.image('fence_full', 'assets/fence_full.png'); this.load.image('wall_damaged', 'assets/wall_damaged.png'); // Voxel stil asset-i (2.5D) this.load.image('tree_voxel_green', 'assets/tree_voxel_green.png'); this.load.image('tree_voxel_blue', 'assets/tree_voxel_blue.png'); this.load.image('tree_voxel_dead', 'assets/tree_voxel_dead.png'); this.load.image('rock_voxel', 'assets/rock_voxel.png'); // NEW ISOMETRIC 2.5D ASSETS (Stardew Valley style) // Buildings & Structures this.load.image('barn_isometric', 'assets/barn_isometric.png'); this.load.image('farmhouse_isometric', 'assets/farmhouse_isometric.png'); this.load.image('fence_isometric', 'assets/fence_isometric.png'); this.load.image('bridge_isometric', 'assets/bridge_isometric.png'); this.load.image('blacksmith_workshop', 'assets/blacksmith_workshop.png'); this.load.image('ruins_building', 'assets/ruins_building.png'); // Farm & Crops this.load.image('soil_tilled', 'assets/soil_tilled.png'); this.load.image('carrots_stages', 'assets/carrots_stages.png'); this.load.image('flowers_pink_isometric', 'assets/flowers_pink_isometric.png'); // Characters - SPRITESHEETS (6 frames @ 64x64 each) this.load.spritesheet('player_dreadlocks', 'assets/player_dreadlocks.png', { frameWidth: 64, frameHeight: 64 }); this.load.spritesheet('zombie_worker', 'assets/zombie_worker.png', { frameWidth: 64, frameHeight: 64 }); this.load.image('grave_zombie', 'assets/grave_zombie.png'); // Fence pieces (separate parts) this.load.image('fence_post', 'assets/fence_post.png'); this.load.image('fence_horizontal', 'assets/fence_horizontal.png'); this.load.image('fence_vertical', 'assets/fence_vertical.png'); this.load.image('fence_corner', 'assets/fence_corner.png'); // Water frames are generated procedurally in TerrainSystem.createWaterFrames() // No need to load external files // Wait for load completion then process transparency this.load.once('complete', () => { this.processAllTransparency(); this.createAnimations(); }); // New Processed Animations (Standardized 64x64 strips) this.load.spritesheet('player_walk', 'assets/sprites/player_walk_strip.png', { frameWidth: 64, frameHeight: 64 }); this.load.spritesheet('zombie_walk', 'assets/sprites/zombie_walk_strip.png', { frameWidth: 64, frameHeight: 64 }); } createAnimations() { if (this.anims.exists('player_walk_anim')) return; // Old animations this.anims.create({ key: 'player_walk_anim', frames: this.anims.generateFrameNumbers('player_walk', { start: 0, end: 5 }), frameRate: 12, repeat: -1 }); this.anims.create({ key: 'zombie_walk_anim', frames: this.anims.generateFrameNumbers('zombie_walk', { start: 0, end: 5 }), frameRate: 8, repeat: -1 }); // NEW: Isometric character animations (6 frames) this.anims.create({ key: 'player_dreadlocks_walk', frames: this.anims.generateFrameNumbers('player_dreadlocks', { start: 0, end: 5 }), frameRate: 10, repeat: -1 }); this.anims.create({ key: 'zombie_worker_walk', frames: this.anims.generateFrameNumbers('zombie_worker', { start: 0, end: 5 }), frameRate: 8, repeat: -1 }); console.log('🎞️ Animations created!'); } processAllTransparency() { // Process ALL sprites to remove backgrounds const spritesToProcess = [ 'player_sprite', 'zombie_sprite', 'merchant_sprite', 'house_sprite', 'stone_sprite', 'tree_sprite', 'grass_sprite', 'leaf_sprite', 'wheat_sprite', 'stone_texture', // New pixel art assets 'flowers', 'tree_green', 'tree_blue', 'tree_dead', 'rock_asset', // FINAL TREES 'tree_green_final', 'tree_blue_final', 'tree_dead_final', // STARDEW VALLEY FOREST TREES 'tree_purple', 'tree_apple', 'tree_pear', 'tree_cherry', 'tree_sapling', // NEW transparent assets 'tree_blue_new', 'tree_green_new', 'rock_1', 'rock_2', 'rock_small', 'merchant_new', 'elite_zombie', 'tree_dead_new', 'flowers_new', 'hill_sprite', 'fence', 'fence_old', 'gravestone', // City content 'chest', 'spawner', 'signpost_city', 'signpost_farm', 'signpost_both', // Voxel stil 'tree_voxel_green', 'tree_voxel_blue', 'tree_voxel_dead', 'rock_voxel', // NEW ISOMETRIC 2.5D ASSETS - Remove transparency 'barn_isometric', 'farmhouse_isometric', 'fence_isometric', 'bridge_isometric', 'blacksmith_workshop', 'ruins_building', 'soil_tilled', 'carrots_stages', 'flowers_pink_isometric', // NOTE: player_dreadlocks and zombie_worker are SPRITESHEETS - don't process! 'grave_zombie', // NEW FENCE PIECES 'fence_post', 'fence_horizontal', 'fence_vertical', 'fence_corner', // ANIMALS & NPCs 'chicken', 'cow', 'cow_mutant', 'elf', 'troll', 'villager', 'npc_merchant', 'npc_zombie', // STRUCTURES 'structure_house', 'wall_damaged', 'city_wall', // MISC OBJECTS 'wheat_sprite', 'grass_sprite', 'leaf_sprite', 'stone_sprite' ]; spritesToProcess.forEach(spriteKey => { this.processSpriteTransparency(spriteKey); }); // ULTRA AGGRESSIVE: Fence Post only if (this.textures.exists('fence_post')) { this.ultraRemoveBackground('fence_post'); } console.log('✅ All sprites transparency processed!'); } processSpriteTransparency(spriteKey) { if (!this.textures.exists(spriteKey)) return; const texture = this.textures.get(spriteKey); const source = texture.getSourceImage(); // Create canvas to process image const canvas = document.createElement('canvas'); canvas.width = source.width; canvas.height = source.height; const ctx = canvas.getContext('2d', { willReadFrequently: true }); // Draw original image ctx.drawImage(source, 0, 0); // Get image data const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); const data = imageData.data; // Remove backgrounds - ULTRA AGGRESSIVE MODE! for (let i = 0; i < data.length; i += 4) { const r = data[i]; const g = data[i + 1]; const b = data[i + 2]; const a = data[i + 3]; // Skip if already transparent if (a === 0) continue; const brightness = (r + g + b) / 3; // 1. Remove ALL grayscale colors (ANY shade of gray) const isGrayscale = Math.abs(r - g) < 20 && Math.abs(g - b) < 20 && Math.abs(r - b) < 20; if (isGrayscale && brightness > 80) { data[i + 3] = 0; // Make transparent continue; } // 2. Remove ALL light/bright backgrounds (AI-generated sprites) if (brightness > 150) { data[i + 3] = 0; // Make transparent continue; } // 3. Remove PURE WHITE if (r > 240 && g > 240 && b > 240) { data[i + 3] = 0; continue; } // 4. Remove OFF-WHITE / CREAM / BEIGE if (brightness > 200 && Math.abs(r - g) < 30 && Math.abs(g - b) < 30) { data[i + 3] = 0; continue; } // 5. Remove PASTEL colors (low saturation, high brightness) const maxRGB = Math.max(r, g, b); const minRGB = Math.min(r, g, b); const saturation = maxRGB === 0 ? 0 : (maxRGB - minRGB) / maxRGB; if (saturation < 0.3 && brightness > 120) { data[i + 3] = 0; // Remove low-saturation backgrounds continue; } // Special: Remove brown/tan backgrounds (merchant sprite) if (spriteKey === 'merchant_sprite') { // Brown detection: R > G > B, warm tones const isBrown = r > 100 && r > g && g > b && (r - b) > 40; if (isBrown) { data[i + 3] = 0; } } } // Put processed data back ctx.putImageData(imageData, 0, 0); // Create new texture from processed canvas this.textures.remove(spriteKey); this.textures.addCanvas(spriteKey, canvas); } createLoadingBar() { const width = this.cameras.main.width; const height = this.cameras.main.height; // Background for loading screen const bg = this.add.graphics(); bg.fillStyle(0x000000, 1); bg.fillRect(0, 0, width, height); // Styling const primaryColor = 0x00ff41; // Matrix Green const secondaryColor = 0xffffff; // Logo / Title const title = this.add.text(width / 2, height / 2 - 80, 'NOVA FARMA', { fontFamily: 'Courier New', fontSize: '32px', fontStyle: 'bold', fill: '#00cc00' }).setOrigin(0.5); const tipText = this.add.text(width / 2, height - 50, 'Tip: Zombies drop blueprints for new tech...', { fontFamily: 'monospace', fontSize: '14px', fill: '#888888', fontStyle: 'italic' }).setOrigin(0.5); // Progress Bar container const progressBox = this.add.graphics(); progressBox.fillStyle(0x111111, 0.8); progressBox.fillRoundedRect(width / 2 - 160, height / 2 - 15, 320, 30, 5); progressBox.lineStyle(2, 0x333333, 1); progressBox.strokeRoundedRect(width / 2 - 160, height / 2 - 15, 320, 30, 5); const progressBar = this.add.graphics(); const percentText = this.add.text(width / 2, height / 2, '0%', { font: '16px Courier New', fill: '#ffffff', fontStyle: 'bold' }).setOrigin(0.5); const assetLoadingText = this.add.text(width / 2, height / 2 + 30, 'Initializing...', { font: '12px console', fill: '#aaaaaa' }).setOrigin(0.5); this.load.on('progress', (value) => { percentText.setText(parseInt(value * 100) + '%'); progressBar.clear(); progressBar.fillStyle(primaryColor, 1); // Smooth fill const w = 310 * value; if (w > 0) { progressBar.fillRoundedRect(width / 2 - 155, height / 2 - 10, w, 20, 2); } }); this.load.on('fileprogress', (file) => { assetLoadingText.setText(`Loading: ${file.key}`); }); this.load.on('complete', () => { // Fade out animation this.tweens.add({ targets: [progressBar, progressBox, percentText, assetLoadingText, title, tipText, bg], alpha: 0, duration: 1000, onComplete: () => { progressBar.destroy(); progressBox.destroy(); percentText.destroy(); assetLoadingText.destroy(); title.destroy(); tipText.destroy(); bg.destroy(); } }); }); } create() { console.log('✅ PreloadScene: Assets loaded!'); window.gameState.currentScene = 'PreloadScene'; const width = this.cameras.main.width; const height = this.cameras.main.height; const title = this.add.text(width / 2, height / 2 - 50, 'KRVAVA ŽETEV', { fontFamily: 'Courier New', fontSize: '48px', fill: '#ff0000', fontStyle: 'bold', stroke: '#000000', strokeThickness: 6 }); title.setOrigin(0.5); const subtitle = this.add.text(width / 2, height / 2 + 10, 'Zombie Roots', { fontFamily: 'Courier New', fontSize: '24px', fill: '#00ff41' }); subtitle.setOrigin(0.5); const instruction = this.add.text(width / 2, height / 2 + 60, 'Press SPACE to start', { fontFamily: 'Courier New', fontSize: '16px', fill: '#888888' }); instruction.setOrigin(0.5); this.tweens.add({ targets: instruction, alpha: 0.3, duration: 800, yoyo: true, repeat: -1 }); const startGame = () => { console.log('🎮 Starting StoryScene...'); this.input.keyboard.off('keydown'); this.input.off('pointerdown'); this.scene.start('StoryScene'); }; this.time.delayedCall(3000, () => { startGame(); }); this.input.keyboard.on('keydown', (event) => { if (event.code === 'Space' || event.code === 'Enter') { startGame(); } }); this.input.on('pointerdown', () => { startGame(); }); } ultraRemoveBackground(spriteKey) { if (!this.textures.exists(spriteKey)) return; const texture = this.textures.get(spriteKey); const source = texture.getSourceImage(); const canvas = document.createElement('canvas'); canvas.width = source.width; canvas.height = source.height; const ctx = canvas.getContext('2d', { willReadFrequently: true }); ctx.drawImage(source, 0, 0); const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height); const data = imageData.data; // Remove EVERYTHING except brown wood colors for (let i = 0; i < data.length; i += 4) { const r = data[i]; const g = data[i + 1]; const b = data[i + 2]; // Keep only brown/wood colors: R > G > B and R is dominant const isBrown = r > g && g > b && r > 80 && r < 200; if (!isBrown) { data[i + 3] = 0; // Make transparent } } ctx.putImageData(imageData, 0, 0); // Remove old texture and create new one from canvas this.textures.remove(spriteKey); this.textures.addCanvas(spriteKey, canvas); console.log(`🔥 ULTRA removed background from ${spriteKey}`); } }