// Texture Generator // Proceduralno generiranje tekstur in sprite-ov class TextureGenerator { // Generiraj player sprite (32x32px pixel art) static createPlayerSprite(scene, key = 'player') { if (scene.textures.exists(key)) return; const canvas = scene.textures.createCanvas(key, 32, 32); const ctx = canvas.getContext(); ctx.clearRect(0, 0, 32, 32); // Body ctx.fillStyle = '#A0522D'; // Sienna skin ctx.fillRect(10, 8, 12, 12); // Head ctx.fillStyle = '#2F4F4F'; // DarkSlateGray shirt ctx.fillRect(8, 20, 16, 12); // Eyes ctx.fillStyle = '#FFFFFF'; ctx.fillRect(12, 12, 2, 2); ctx.fillRect(18, 12, 2, 2); ctx.fillStyle = '#000000'; ctx.fillRect(13, 12, 1, 1); ctx.fillRect(19, 12, 1, 1); // Hair ctx.fillStyle = '#000000'; ctx.fillRect(10, 6, 12, 4); ctx.fillRect(8, 8, 2, 6); ctx.fillRect(22, 8, 2, 6); canvas.refresh(); } // Generiraj walking animacijo static createPlayerWalkSprite(scene, key = 'player_walk') { if (scene.textures.exists(key)) return; const canvas = scene.textures.createCanvas(key, 128, 32); const ctx = canvas.getContext(); // Simple placeholders for 4 frames for (let i = 0; i < 4; i++) { ctx.fillStyle = '#2F4F4F'; ctx.fillRect(i * 32 + 8, 6, 16, 26); } canvas.refresh(); } // Generiraj NPC sprite static createNPCSprite(scene, key = 'npc', type = 'zombie') { if (scene.textures.exists(key)) return; const canvas = scene.textures.createCanvas(key, 32, 32); const ctx = canvas.getContext(); ctx.clearRect(0, 0, 32, 32); // Elite Zombie: Red body, glowing pink eyes if (type === 'elite_zombie') { ctx.fillStyle = '#8B0000'; // DarkRed ctx.fillRect(8, 6, 16, 26); // Glowing Eyes ctx.fillStyle = '#FF1493'; // Deep Pink (glow) ctx.fillRect(10, 10, 4, 4); ctx.fillRect(20, 10, 4, 4); } else { ctx.fillStyle = (type === 'zombie') ? '#556B2F' : '#DEB887'; ctx.fillRect(8, 6, 16, 26); // Eyes (Red for zombie) ctx.fillStyle = (type === 'zombie') ? '#FF0000' : '#000000'; ctx.fillRect(10, 10, 4, 4); ctx.fillRect(20, 10, 4, 4); } canvas.refresh(); } static createMerchantSprite(scene, key = 'merchant_texture') { if (scene.textures.exists(key)) return; console.log('🧙‍♂️ Creating Merchant Sprite Texture...'); try { const canvas = scene.textures.createCanvas(key, 32, 32); const ctx = canvas.getContext(); ctx.clearRect(0, 0, 32, 32); // Body (BRIGHT GOLD robe - zelo viden!) ctx.fillStyle = '#FFD700'; // Gold ctx.fillRect(8, 6, 16, 26); // Head ctx.fillStyle = '#FFE4C4'; // Bisque skin ctx.fillRect(10, 4, 12, 12); // Hat (Red Merchants Hat) ctx.fillStyle = '#8B0000'; // DarkRed ctx.fillRect(8, 2, 16, 4); ctx.fillRect(10, 0, 12, 2); // Hat Top // Backpack (Brown - visible on sides) ctx.fillStyle = '#8B4513'; ctx.fillRect(4, 10, 4, 14); // Left side pack ctx.fillRect(24, 10, 4, 14); // Right side pack // Straps ctx.fillStyle = '#A0522D'; ctx.fillRect(8, 10, 16, 2); // Eyes ctx.fillStyle = '#000000'; ctx.fillRect(13, 8, 2, 2); ctx.fillRect(17, 8, 2, 2); // Beard (White) ctx.fillStyle = '#F5F5F5'; ctx.fillRect(10, 12, 12, 4); ctx.fillRect(12, 16, 8, 2); canvas.refresh(); console.log('✅ Merchant Sprite Created!'); } catch (error) { console.error('❌ ERROR creating merchant sprite:', error); } } static createCloudSprite(scene, key = 'cloud') { if (scene.textures.exists(key)) return; const canvas = scene.textures.createCanvas(key, 64, 32); const ctx = canvas.getContext(); ctx.clearRect(0, 0, 64, 32); ctx.fillStyle = 'rgba(255,255,255,0.6)'; ctx.beginPath(); ctx.arc(20, 20, 15, 0, Math.PI * 2); ctx.fill(); ctx.beginPath(); ctx.arc(35, 15, 18, 0, Math.PI * 2); ctx.fill(); ctx.beginPath(); ctx.arc(50, 20, 12, 0, Math.PI * 2); ctx.fill(); canvas.refresh(); } static createCropSprite(scene, key, stage = 4) { if (scene.textures.exists(key)) scene.textures.remove(key); // FORCE REFRESH to see updates const canvas = scene.textures.createCanvas(key, 32, 32); const ctx = canvas.getContext(); ctx.clearRect(0, 0, 32, 32); // Improved Wheat Visuals const startY = 32; // 1. Stems (Green -> Yellowish) ctx.fillStyle = (stage < 3) ? '#32CD32' : '#DAA520'; const h = stage * 6; // Draw distinct stalks ctx.fillRect(10, startY - h, 2, h); // Left stalk ctx.fillRect(16, startY - h, 2, h); // Center stalk ctx.fillRect(22, startY - h, 2, h); // Right stalk // 2. Heads (Wheat ears) - Stage 3 & 4 if (stage >= 3) { ctx.fillStyle = '#FFD700'; // Gold // Left head ctx.beginPath(); ctx.ellipse(11, startY - h, 3, 5, -0.2, 0, Math.PI * 2); ctx.fill(); // Center head ctx.beginPath(); ctx.ellipse(17, startY - h - 2, 3, 6, 0, 0, Math.PI * 2); ctx.fill(); // Right head ctx.beginPath(); ctx.ellipse(23, startY - h, 3, 5, 0.2, 0, Math.PI * 2); ctx.fill(); } // 3. Withered if (stage === 5) { ctx.fillStyle = '#8B4513'; ctx.fillRect(10, 24, 14, 8); // Dead pile } canvas.refresh(); } static createStructureSprite(scene, key, type) { if (scene.textures.exists(key)) return; const width = (type === 'house' || type === 'ruin') ? 64 : 32; const height = (type === 'house' || type === 'ruin') ? 64 : 32; const canvas = scene.textures.createCanvas(key, width, height); const ctx = canvas.getContext(); ctx.clearRect(0, 0, width, height); if (type === 'ruin') { // Isometric Ruin / Rocks for user ctx.fillStyle = '#696969'; // DimGray // Big Rock 1 ctx.beginPath(); ctx.arc(20, 50, 14, 0, Math.PI * 2); ctx.fill(); // Big Rock 2 ctx.beginPath(); ctx.arc(45, 55, 12, 0, Math.PI * 2); ctx.fill(); // Details ctx.fillStyle = '#555555'; ctx.beginPath(); ctx.arc(25, 45, 6, 0, Math.PI * 2); ctx.fill(); } else { // Generic box for others ctx.fillStyle = '#8B4513'; ctx.fillRect(0, 0, width, height); } canvas.refresh(); } // ========== 3D VOLUMETRIC GENERATORS (RESTORED) ========== // Generiraj 3D volumetric tree (Minecraft-style) static createTreeSprite(scene, key = 'tree') { if (scene.textures.exists(key)) return; const size = 64; const height = 96; // Taller for 3D effect const canvas = scene.textures.createCanvas(key, size, height); const ctx = canvas.getContext(); ctx.clearRect(0, 0, size, height); // Helper to draw isometric-ish cube face const drawCube = (x, y, w, h, d, colorTop, colorSide, colorFront) => { // Front face ctx.fillStyle = colorFront; ctx.fillRect(x, y + d, w, h); // Top face (fake perspective) ctx.fillStyle = colorTop; ctx.beginPath(); ctx.moveTo(x, y + d); ctx.lineTo(x + d, y); ctx.lineTo(x + w + d, y); ctx.lineTo(x + w, y + d); ctx.closePath(); ctx.fill(); // Side face ctx.fillStyle = colorSide; ctx.beginPath(); ctx.moveTo(x + w, y + d); ctx.lineTo(x + w + d, y); ctx.lineTo(x + w + d, y + h); ctx.lineTo(x + w, y + h + d); ctx.closePath(); ctx.fill(); }; // Trunk const trunkColor = '#8B4513'; const trunkTop = '#A0522D'; const trunkDark = '#663300'; drawCube(24, 60, 16, 24, 8, trunkTop, trunkDark, trunkColor); // Leaves chunks (Minecraft style) const leafColor = '#228B22'; // ForestGreen const leafTop = '#32CD32'; // LimeGreen const leafDark = '#006400'; // DarkGreen // Bottom layer drawCube(12, 30, 40, 20, 10, leafTop, leafDark, leafColor); // Top layer drawCube(20, 10, 24, 20, 8, leafTop, leafDark, leafColor); canvas.refresh(); } // Generiraj 3D volumetric Rock (Gray Cubes) static createRockSprite(scene, key = 'rock') { if (scene.textures.exists(key)) return; const size = 48; const canvas = scene.textures.createCanvas(key, size, size); const ctx = canvas.getContext(); ctx.clearRect(0, 0, size, size); // Simple Voxel Draw const drawVoxel = (x, y, c) => { ctx.fillStyle = c; ctx.fillRect(x, y, 10, 10); ctx.fillStyle = '#444444'; // Side ctx.fillRect(x + 10, y, 4, 10); ctx.fillStyle = '#333333'; // Bottom ctx.fillRect(x, y + 10, 10, 4); }; const gray = '#808080'; drawVoxel(10, 25, gray); drawVoxel(20, 20, gray); drawVoxel(15, 15, gray); canvas.refresh(); } // Generiraj 3D flower (simple volumetric) static createFlowerSprite(scene, key = 'flower') { 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); ctx.fillStyle = '#228B22'; // Stem ctx.fillRect(15, 10, 2, 10); ctx.fillStyle = '#FF69B4'; // Flower ctx.fillRect(12, 8, 8, 8); canvas.refresh(); } static createBushSprite(scene, key = 'bush') { 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); ctx.fillStyle = '#228B22'; ctx.beginPath(); ctx.arc(16, 16, 12, 0, Math.PI * 2); ctx.fill(); ctx.fillStyle = 'red'; // Berries ctx.beginPath(); ctx.arc(12, 12, 2, 0, Math.PI * 2); ctx.fill(); ctx.beginPath(); ctx.arc(20, 18, 2, 0, Math.PI * 2); ctx.fill(); canvas.refresh(); } static createGravestoneSprite(scene, key = 'gravestone') { if (scene.textures.exists(key)) return; const canvas = scene.textures.createCanvas(key, 32, 32); const ctx = canvas.getContext(); ctx.clearRect(0, 0, 32, 32); ctx.fillStyle = '#808080'; ctx.fillRect(8, 8, 16, 24); ctx.beginPath(); ctx.arc(16, 8, 8, Math.PI, 0); ctx.fill(); canvas.refresh(); } static createChestSprite(scene, key = 'chest') { if (scene.textures.exists(key)) return; const canvas = scene.textures.createCanvas(key, 32, 32); const ctx = canvas.getContext(); ctx.clearRect(0, 0, 32, 32); // Chest body (brown) ctx.fillStyle = '#8B4513'; // SaddleBrown ctx.fillRect(6, 12, 20, 16); // Lock (gold) ctx.fillStyle = '#FFD700'; ctx.fillRect(14, 18, 4, 6); // Lid ctx.fillStyle = '#A0522D'; ctx.fillRect(6, 8, 20, 4); canvas.refresh(); } static createSpawnerSprite(scene, key = 'spawner') { if (scene.textures.exists(key)) return; const canvas = scene.textures.createCanvas(key, 32, 32); const ctx = canvas.getContext(); ctx.clearRect(0, 0, 32, 32); // Dark portal/spawner ctx.fillStyle = '#2F4F4F'; // DarkSlateGray ctx.fillRect(8, 8, 16, 16); // Red glow ctx.fillStyle = '#8B0000'; ctx.fillRect(10, 10, 12, 12); // Center black hole ctx.fillStyle = '#000000'; ctx.beginPath(); ctx.arc(16, 16, 4, 0, Math.PI * 2); ctx.fill(); canvas.refresh(); } static createSignpostSprite(scene, key = 'signpost', text = '→') { if (scene.textures.exists(key)) return; const canvas = scene.textures.createCanvas(key, 32, 32); const ctx = canvas.getContext(); ctx.clearRect(0, 0, 32, 32); // Wooden post (brown) ctx.fillStyle = '#8B4513'; ctx.fillRect(14, 8, 4, 24); // Sign board ctx.fillStyle = '#D2691E'; ctx.fillRect(6, 10, 20, 12); // Border ctx.strokeStyle = '#000'; ctx.lineWidth = 1; ctx.strokeRect(6, 10, 20, 12); // Text ctx.fillStyle = '#000'; ctx.font = 'bold 14px Courier'; ctx.textAlign = 'center'; ctx.fillText(text, 16, 19); canvas.refresh(); } static createToolSprites(scene) { // --- 3D VOXEL TOOLS --- const refresh = (key) => { if (scene.textures.exists(key)) scene.textures.remove(key); const c = scene.textures.createCanvas(key, 32, 32); const ctx = c.getContext(); ctx.clearRect(0, 0, 32, 32); return { c, ctx }; }; // Helper: Draw 3D Pixel/Block const drawBlock = (ctx, x, y, color) => { ctx.fillStyle = color; ctx.fillRect(x, y, 2, 2); // Front ctx.fillStyle = 'rgba(0,0,0,0.3)'; // Side shadow ctx.fillRect(x + 2, y, 1, 2); ctx.fillRect(x, y + 2, 3, 1); }; // 1. AXE (3D) { const { c, ctx } = refresh('item_axe'); // Handle for (let i = 0; i < 8; i++) drawBlock(ctx, 12 + i, 20 - i * 2, '#8B4513'); // Head for (let x = 0; x < 3; x++) { for (let y = 0; y < 4; y++) { drawBlock(ctx, 18 + x * 2, 6 + y * 2, '#708090'); // Gray Metal } } drawBlock(ctx, 24, 8, '#C0C0C0'); // Edge drawBlock(ctx, 24, 10, '#C0C0C0'); c.refresh(); } // 2. PICKAXE (3D) { const { c, ctx } = refresh('item_pickaxe'); // Handle for (let i = 0; i < 8; i++) drawBlock(ctx, 14, 8 + i * 2, '#8B4513'); // Head (Arc) drawBlock(ctx, 6, 10, '#696969'); drawBlock(ctx, 8, 8, '#696969'); drawBlock(ctx, 10, 6, '#696969'); drawBlock(ctx, 12, 6, '#696969'); drawBlock(ctx, 14, 6, '#696969'); // Center drawBlock(ctx, 16, 6, '#696969'); drawBlock(ctx, 18, 6, '#696969'); drawBlock(ctx, 20, 8, '#696969'); drawBlock(ctx, 22, 10, '#696969'); c.refresh(); } // 3. HOE (3D) { const { c, ctx } = refresh('item_hoe'); // Handle for (let i = 0; i < 9; i++) drawBlock(ctx, 14 + i, 4 + i * 2, '#8B4513'); // Head drawBlock(ctx, 12, 4, '#778899'); drawBlock(ctx, 14, 4, '#778899'); drawBlock(ctx, 16, 6, '#778899'); drawBlock(ctx, 16, 8, '#778899'); // Blade c.refresh(); } // 4. SWORD (3D) { const { c, ctx } = refresh('item_sword'); // Handle drawBlock(ctx, 14, 24, '#8B4513'); drawBlock(ctx, 14, 26, '#8B4513'); // Guard drawBlock(ctx, 10, 22, '#FFD700'); drawBlock(ctx, 12, 22, '#FFD700'); drawBlock(ctx, 14, 22, '#FFD700'); drawBlock(ctx, 16, 22, '#FFD700'); drawBlock(ctx, 18, 22, '#FFD700'); // Blade for (let i = 0; i < 8; i++) drawBlock(ctx, 14, 6 + i * 2, '#C0C0C0'); c.refresh(); } // 5. WATERING CAN (3D) { const { c, ctx } = refresh('item_watering_can'); // Body 3x3 blocks for (let x = 0; x < 4; x++) for (let y = 0; y < 3; y++) drawBlock(ctx, 10 + x * 2, 14 + y * 2, '#A9A9A9'); // Spout drawBlock(ctx, 18, 12, '#A9A9A9'); drawBlock(ctx, 20, 10, '#A9A9A9'); // Handle drawBlock(ctx, 8, 12, '#696969'); drawBlock(ctx, 8, 10, '#696969'); drawBlock(ctx, 10, 8, '#696969'); c.refresh(); } } static createItemSprites(scene) { // Placeholder item generation const items = [ { name: 'wood', color: '#8B4513' }, // Rjava { name: 'stone', color: '#808080' }, // Siva { name: 'seeds', color: '#90EE90' }, // Svetlo zelena { name: 'wheat', color: '#FFD700' }, // Zlata { name: 'corn', color: '#FFD700' }, // Zlata (Corn) { name: 'seeds_corn', color: '#B22222' },// FireBrick seeds { name: 'item_bone', color: '#F5F5DC' }, // Beige { name: 'item_scrap', color: '#B87333' }, // Copper/Bronze (kovinski kos) { name: 'item_chip', color: '#00CED1' } // DarkTurquoise (elektronski chip) ]; items.forEach(item => { const it = typeof item === 'string' ? item : item.name; const color = typeof item === 'string' ? 'gold' : item.color; const k = (it.startsWith('item_')) ? it : 'item_' + it; if (scene.textures.exists(k)) scene.textures.remove(k); // FORCE REFRESH const c = scene.textures.createCanvas(k, 32, 32); const x = c.getContext(); x.clearRect(0, 0, 32, 32); // SPECIAL ICONS if (it === 'corn') { // Corn Cob x.fillStyle = '#228B22'; // Husk x.beginPath(); x.ellipse(16, 16, 6, 12, 0, 0, Math.PI * 2); x.fill(); x.fillStyle = '#FFD700'; // Kernels x.beginPath(); x.ellipse(16, 16, 3, 8, 0, 0, Math.PI * 2); x.fill(); } else if (it === 'wheat') { // Wheat Sheaf x.strokeStyle = '#FFD700'; x.lineWidth = 2; x.beginPath(); x.moveTo(12, 28); x.lineTo(20, 4); // Stalk 1 x.moveTo(16, 28); x.lineTo(16, 4); // Stalk 2 x.moveTo(20, 28); x.lineTo(12, 4); // Stalk 3 x.stroke(); // Tie x.fillStyle = '#DAA520'; x.fillRect(13, 22, 6, 3); } else if (it.includes('seeds')) { // Seed Bag x.fillStyle = '#DEB887'; // Burlywood bag x.beginPath(); x.moveTo(10, 8); x.lineTo(22, 8); // Top x.lineTo(26, 26); x.lineTo(6, 26); // Bottom x.fill(); // Label/Dots x.fillStyle = color; x.beginPath(); x.arc(16, 18, 4, 0, Math.PI * 2); x.fill(); } else { // Default Circle x.fillStyle = color; x.beginPath(); x.arc(16, 16, 10, 0, Math.PI * 2); x.fill(); } c.refresh(); }); } 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(); } static createCornSprites(scene) { for (let i = 1; i <= 4; i++) { const key = `corn_stage_${i}`; if (scene.textures.exists(key)) continue; // Corn is taller const canvas = scene.textures.createCanvas(key, 32, 64); const ctx = canvas.getContext(); ctx.clearRect(0, 0, 32, 64); const startY = 64; // Stalk ctx.fillStyle = '#556B2F'; // DarkOliveGreen const height = 10 + (i * 10); ctx.fillRect(14, startY - height, 4, height); // Leaves ctx.fillStyle = '#32CD32'; // LimeGreen if (i >= 2) { ctx.beginPath(); ctx.ellipse(10, startY - height + 10, 8, 3, 0.5, 0, Math.PI * 2); ctx.fill(); ctx.beginPath(); ctx.ellipse(22, startY - height + 15, 8, 3, -0.5, 0, Math.PI * 2); ctx.fill(); } // Cobs (Only stage 4) if (i === 4) { ctx.fillStyle = '#FFD700'; // Gold ctx.fillRect(12, startY - height + 20, 4, 8); ctx.fillRect(18, startY - height + 25, 4, 8); } canvas.refresh(); } } // Helper to generate ALL textures at once generateAll() { TextureGenerator.createPlayerSprite(this.scene); TextureGenerator.createPlayerWalkSprite(this.scene); TextureGenerator.createNPCSprite(this.scene, 'npc', 'zombie'); TextureGenerator.createMerchantSprite(this.scene, 'merchant_texture'); TextureGenerator.createFlowerSprite(this.scene); TextureGenerator.createBushSprite(this.scene); TextureGenerator.createSaplingSprite(this.scene, 'tree_sapling'); TextureGenerator.createTreeSprite(this.scene); TextureGenerator.createRockSprite(this.scene); TextureGenerator.createCloudSprite(this.scene); // Crops TextureGenerator.createCropSprite(this.scene, 'crop_stage_1', 1); TextureGenerator.createCropSprite(this.scene, 'crop_stage_2', 2); TextureGenerator.createCropSprite(this.scene, 'crop_stage_3', 3); TextureGenerator.createCropSprite(this.scene, 'crop_stage_4', 4); TextureGenerator.createCornSprites(this.scene); // Added Corn TextureGenerator.createGravestoneSprite(this.scene); TextureGenerator.createToolSprites(this.scene); TextureGenerator.createItemSprites(this.scene); } constructor(scene) { this.scene = scene; } }