// Текстуры блоков (простые) import { BLOCKS } from '../data/blocks.js'; export const tex = {}; // --- Item/tool sprite generator ---\n export const itemTex = {}; function drawArrow(ctx, color) { ctx.fillStyle = '#8B4513'; ctx.fillRect(8, 14, 16, 3); ctx.fillStyle = color; ctx.beginPath(); ctx.moveTo(24, 15); ctx.lineTo(18, 10); ctx.lineTo(18, 20); ctx.closePath(); ctx.fill(); ctx.fillStyle = '#e74c3c'; ctx.beginPath(); ctx.moveTo(8, 15); ctx.lineTo(4, 10); ctx.lineTo(10, 14); ctx.closePath(); ctx.fill(); ctx.beginPath(); ctx.moveTo(8, 16); ctx.lineTo(4, 21); ctx.lineTo(10, 17); ctx.closePath(); ctx.fill(); } function drawPickaxe(ctx, headColor, handleColor) { ctx.fillStyle = handleColor || '#8B4513'; ctx.save(); ctx.translate(16, 16); ctx.rotate(Math.PI / 4); ctx.fillRect(-2, 0, 4, 18); ctx.fillStyle = headColor; ctx.fillRect(-8, -3, 16, 5); ctx.fillRect(-8, -3, 3, 8); ctx.fillRect(5, -3, 3, 8); ctx.restore(); } function drawAxe(ctx, headColor, handleColor) { ctx.fillStyle = handleColor || '#8B4513'; ctx.save(); ctx.translate(16, 16); ctx.rotate(Math.PI / 4); ctx.fillRect(-2, 0, 4, 18); ctx.fillStyle = headColor; ctx.fillRect(-2, -8, 10, 8); ctx.fillRect(-2, -8, 4, 12); ctx.restore(); } function drawShovel(ctx, headColor, handleColor) { ctx.fillStyle = handleColor || '#8B4513'; ctx.save(); ctx.translate(16, 16); ctx.rotate(Math.PI / 4); ctx.fillRect(-2, 0, 4, 18); ctx.fillStyle = headColor; ctx.fillRect(-6, -8, 12, 8); ctx.fillRect(-4, -12, 8, 4); ctx.restore(); } function drawSword(ctx, bladeColor, guardColor) { ctx.fillStyle = '#8B4513'; ctx.fillRect(14, 18, 4, 10); ctx.fillStyle = guardColor || '#f1c40f'; ctx.fillRect(10, 16, 12, 3); ctx.fillStyle = bladeColor; ctx.beginPath(); ctx.moveTo(16, 2); ctx.lineTo(12, 16); ctx.lineTo(20, 16); ctx.closePath(); ctx.fill(); } function drawBow(ctx) { ctx.strokeStyle = '#8B4513'; ctx.lineWidth = 3; ctx.beginPath(); ctx.arc(12, 16, 12, -Math.PI * 0.7, Math.PI * 0.7); ctx.stroke(); ctx.strokeStyle = '#ddd'; ctx.lineWidth = 1; ctx.beginPath(); ctx.moveTo(12, 4); ctx.lineTo(12, 28); ctx.stroke(); } function drawIngot(ctx, color) { ctx.fillStyle = color; ctx.beginPath(); ctx.moveTo(6, 12); ctx.lineTo(26, 12); ctx.lineTo(24, 24); ctx.lineTo(8, 24); ctx.closePath(); ctx.fill(); ctx.fillStyle = 'rgba(255,255,255,0.3)'; ctx.fillRect(8, 8, 16, 4); } function drawMeat(ctx, cooked) { ctx.fillStyle = cooked ? '#8B4513' : '#e74c3c'; ctx.beginPath(); ctx.ellipse(16, 18, 10, 8, 0, 0, Math.PI * 2); ctx.fill(); ctx.fillStyle = '#f5f5dc'; ctx.fillRect(8, 6, 3, 12); ctx.fillRect(14, 4, 3, 8); } function makeItemTex(id) { const c = document.createElement('canvas'); c.width = 32; c.height = 32; const g = c.getContext('2d'); const tierColors = { wood: { head: '#a0522d', blade: '#a0522d' }, stone: { head: '#7f8c8d', blade: '#95a5a6' }, iron: { head: '#bdc3c7', blade: '#ecf0f1' }, }; switch (id) { case 'arrow': drawArrow(g, '#7f8c8d'); break; case 'bow': drawBow(g); break; case 'wood_pickaxe': drawPickaxe(g, tierColors.wood.head, tierColors.wood.blade); break; case 'stone_pickaxe': drawPickaxe(g, tierColors.stone.head); break; case 'iron_pickaxe': drawPickaxe(g, tierColors.iron.head); break; case 'wood_axe': drawAxe(g, tierColors.wood.head); break; case 'stone_axe': drawAxe(g, tierColors.stone.head); break; case 'iron_axe': drawAxe(g, tierColors.iron.head); break; case 'wood_shovel': drawShovel(g, tierColors.wood.head); break; case 'stone_shovel': drawShovel(g, tierColors.stone.head); break; case 'iron_shovel': drawShovel(g, tierColors.iron.head); break; case 'wood_sword': drawSword(g, tierColors.wood.blade, '#a0522d'); break; case 'stone_sword': drawSword(g, tierColors.stone.blade, '#7f8c8d'); break; case 'iron_sword': drawSword(g, tierColors.iron.blade, '#bdc3c7'); break; case 'iron_ingot': drawIngot(g, '#bdc3c7'); break; case 'gold_ingot': drawIngot(g, '#f1c40f'); break; case 'copper_ingot': drawIngot(g, '#e67e22'); break; case 'meat': drawMeat(g, false); break; case 'cooked': drawMeat(g, true); break; case 'wheat': g.fillStyle = '#f1c40f'; g.fillRect(12, 8, 3, 18); g.fillRect(8, 6, 10, 4); break; case 'bread': g.fillStyle = '#d4a030'; g.fillRect(6, 12, 20, 12); g.fillStyle = '#c08820'; g.fillRect(6, 12, 20, 3); break; case 'carrot': g.fillStyle = '#e67e22'; g.fillRect(14, 10, 4, 18); g.fillStyle = '#27ae60'; g.fillRect(12, 6, 8, 5); break; case 'potato': g.fillStyle = '#d4a050'; g.beginPath(); g.ellipse(16, 16, 8, 6, 0, 0, Math.PI * 2); g.fill(); g.fillStyle = '#b88a40'; g.fillRect(10, 14, 2, 1); g.fillRect(20, 16, 2, 1); break; case 'baked_potato': g.fillStyle = '#c08820'; g.beginPath(); g.ellipse(16, 16, 8, 6, 0, 0, Math.PI * 2); g.fill(); g.fillStyle = '#f5e6cc'; g.fillRect(12, 12, 8, 6); break; case 'mushroom_stew': g.fillStyle = '#8B4513'; g.fillRect(10, 16, 12, 12); g.fillStyle = '#e74c3c'; g.beginPath(); g.ellipse(16, 14, 8, 5, 0, Math.PI, 0); g.fill(); break; case 'scorpion_stinger': g.fillStyle = '#d35400'; g.beginPath(); g.moveTo(16, 4); g.lineTo(10, 28); g.lineTo(22, 28); g.closePath(); g.fill(); break; case 'polar_fur': g.fillStyle = '#ecf0f1'; g.fillRect(6, 6, 20, 20); g.fillStyle = '#bdc3c7'; g.fillRect(12, 12, 8, 8); break; case 'slime_ball': g.fillStyle = 'rgba(46,204,113,0.8)'; g.beginPath(); g.arc(16, 16, 10, 0, Math.PI * 2); g.fill(); g.fillStyle = '#fff'; g.fillRect(10, 10, 4, 4); g.fillRect(18, 10, 4, 4); break; case 'eagle_feather': g.fillStyle = '#8B4513'; g.fillRect(14, 4, 4, 24); g.fillStyle = '#ecf0f1'; g.fillRect(10, 6, 12, 10); break; case 'chicken_meat': drawMeat(g, false); g.fillStyle = '#fff'; g.fillRect(12, 8, 4, 4); break; case 'feather': g.fillStyle = '#ecf0f1'; g.fillRect(14, 6, 4, 20); g.fillStyle = '#bbb'; g.fillRect(12, 8, 8, 8); break; case 'bone': g.fillStyle = '#f5f5dc'; g.fillRect(12, 10, 8, 14); g.fillRect(8, 8, 4, 4); g.fillRect(20, 8, 4, 4); g.fillRect(8, 22, 4, 4); g.fillRect(20, 22, 4, 4); break; case 'gunpowder': g.fillStyle = '#555'; g.fillRect(8, 10, 6, 6); g.fillRect(18, 14, 6, 6); g.fillRect(12, 20, 6, 6); break; case 'gold_armor': g.fillStyle = '#f1c40f'; g.fillRect(6, 6, 20, 20); g.fillStyle = '#f39c12'; g.fillRect(10, 4, 12, 6); g.fillRect(4, 10, 6, 16); g.fillRect(22, 10, 6, 16); break; case 'wheat_seeds': g.fillStyle = '#7dcea0'; g.fillRect(14, 16, 4, 10); g.fillStyle = '#a8e6a0'; g.fillRect(10, 8, 4, 4); g.fillRect(18, 6, 4, 4); g.fillRect(14, 4, 4, 4); break; default: g.fillStyle = '#7f8c8d'; g.fillRect(4, 4, 24, 24); g.fillStyle = 'rgba(255,255,255,0.2)'; g.fillRect(4, 4, 24, 4); } return c; } export function makeTex(type) { const t = BLOCKS[type]; const c = document.createElement('canvas'); c.width = 32; c.height = 32; const g = c.getContext('2d'); if (type === 'tnt') { g.fillStyle = '#c0392b'; g.fillRect(0, 0, 32, 32); g.fillStyle = '#fff'; g.fillRect(0, 12, 32, 8); g.fillStyle = '#000'; g.font = 'bold 10px sans-serif'; g.fillText('TNT', 6, 20); return c; } if (type === 'campfire') { g.fillStyle = '#5d4037'; g.fillRect(4, 26, 24, 6); g.fillStyle = '#3e2723'; g.fillRect(7, 23, 18, 4); return c; } if (type === 'torch') { g.fillStyle = '#6d4c41'; g.fillRect(14, 10, 4, 18); g.fillStyle = '#f39c12'; g.fillRect(12, 6, 8, 8); return c; } if (type === 'glass') { g.fillStyle = 'rgba(200,240,255,0.25)'; g.fillRect(0, 0, 32, 32); g.strokeStyle = 'rgba(255,255,255,0.65)'; g.strokeRect(2, 2, 28, 28); g.beginPath(); g.moveTo(5, 27); g.lineTo(27, 5); g.stroke(); return c; } if (type === 'water') { g.fillStyle = t.c; g.fillRect(0, 0, 32, 32); g.fillStyle = 'rgba(255,255,255,0.08)'; g.fillRect(0, 6, 32, 2); return c; } if (type === 'bed') { g.fillStyle = '#e91e63'; g.fillRect(0, 0, 32, 32); g.fillStyle = '#f8bbd0'; g.fillRect(2, 2, 14, 14); g.fillStyle = '#c2185b'; g.fillRect(16, 4, 14, 24); g.fillStyle = '#e91e63'; g.fillRect(18, 6, 10, 20); return c; } if (type === 'flower') { g.fillStyle = '#2ecc71'; g.fillRect(14, 14, 4, 18); g.fillStyle = t.c; g.beginPath(); g.arc(16, 12, 6, 0, 6.28); g.fill(); return c; } if (type === 'boat') { g.fillStyle = '#8B4513'; g.fillRect(2, 12, 28, 8); g.fillStyle = '#A0522D'; g.fillRect(0, 10, 32, 12); g.fillStyle = '#DEB887'; g.fillRect(4, 14, 24, 4); g.fillStyle = '#654321'; g.fillRect(2, 20, 28, 4); return c; } if (type === 'ladder') { g.fillStyle = '#8B4513'; g.fillRect(4, 0, 4, 32); g.fillRect(24, 0, 4, 32); g.fillStyle = '#A0522D'; g.fillRect(4, 4, 24, 3); g.fillRect(4, 12, 24, 3); g.fillRect(4, 20, 24, 3); g.fillRect(4, 28, 24, 3); return c; } // === BIOME BLOCK TEXTURES === if (type === 'snow') { g.fillStyle = '#ecf0f1'; g.fillRect(0, 0, 32, 32); g.fillStyle = '#dfe6e9'; for (let i = 0; i < 4; i++) g.fillRect((Math.random()*26)|0, (Math.random()*26)|0, 5, 3); return c; } if (type === 'ice') { g.fillStyle = '#74b9ff'; g.fillRect(0, 0, 32, 32); g.strokeStyle = 'rgba(255,255,255,0.4)'; g.beginPath(); g.moveTo(4,10); g.lineTo(20,16); g.lineTo(10,28); g.stroke(); g.beginPath(); g.moveTo(18,4); g.lineTo(28,12); g.stroke(); return c; } if (type === 'cactus') { g.fillStyle = '#27ae60'; g.fillRect(6, 2, 20, 28); g.fillStyle = '#2ecc71'; g.fillRect(2, 8, 6, 4); g.fillRect(24, 14, 6, 4); g.fillStyle = '#1e8449'; g.fillRect(12, 0, 2, 30); g.fillRect(18, 0, 2, 30); return c; } if (type === 'mushroom') { g.fillStyle = '#f5e6cc'; g.fillRect(14, 20, 4, 12); g.fillStyle = '#e74c3c'; g.beginPath(); g.arc(16, 14, 10, Math.PI, 0); g.fill(); g.fillStyle = '#fff'; g.fillRect(10, 10, 3, 3); g.fillRect(17, 8, 4, 3); return c; } if (type === 'moss') { g.fillStyle = '#0a6640'; g.fillRect(0, 0, 32, 32); g.fillStyle = '#1e8449'; for (let i = 0; i < 6; i++) g.fillRect((Math.random()*26)|0, (Math.random()*26)|0, 4, 3); return c; } if (type === 'swamp_water') { g.fillStyle = 'rgba(100,120,40,0.6)'; g.fillRect(0, 0, 32, 32); g.fillStyle = 'rgba(80,100,20,0.3)'; g.fillRect(0, 10, 32, 2); g.fillRect(0, 22, 32, 2); return c; } if (type === 'farmland') { g.fillStyle = '#8B6914'; g.fillRect(0, 0, 32, 32); g.fillStyle = '#7a5c10'; for (let i = 0; i < 4; i++) g.fillRect(0, 6+i*8, 32, 2); g.fillStyle = '#6B4E0A'; g.fillRect(8, 2, 2, 28); g.fillRect(18, 2, 2, 28); return c; } if (type === 'dead_bush') { g.fillStyle = '#b2bec3'; g.fillRect(12, 16, 2, 16); g.fillRect(8, 14, 8, 2); g.fillRect(16, 12, 8, 2); g.fillRect(6, 18, 4, 2); return c; } if (type === 'spruce_leaves') { g.fillStyle = '#0a6640'; g.fillRect(0, 0, 32, 32); g.fillStyle = '#0d7a4d'; for (let i = 0; i < 5; i++) g.fillRect((Math.random()*24)|0, (Math.random()*24)|0, 6, 4); return c; } // CROP STAGES if (type.startsWith('wheat_stage') || type.startsWith('carrot_stage') || type.startsWith('potato_stage')) { const st = parseInt(type.charAt(type.length-1)); const colors = type.startsWith('wheat') ? ['#a8e6a0','#7dcea0','#b8d730','#f1c40f'] : type.startsWith('carrot') ? ['#a8e6a0','#f0c27a','#e8a040','#e67e22'] : ['#a8e6a0','#c8b888','#bfaa78','#dfe6e9']; g.fillStyle = '#5d4037'; g.fillRect(15, 18, 2, 14); if (st >= 1) { g.fillStyle = colors[st]; g.fillRect(10, 8 + (3-st)*3, 12, 10); } else { g.fillStyle = '#a8e6a0'; g.fillRect(14, 22, 4, 4); } return c; } g.fillStyle = t.c || '#000'; g.fillRect(0, 0, 32, 32); g.fillStyle = 'rgba(0,0,0,0.10)'; for (let i = 0; i < 6; i++) g.fillRect((Math.random() * 28) | 0, (Math.random() * 28) | 0, 4, 4); if (type.endsWith('_ore') || type === 'coal') { g.fillStyle = 'rgba(0,0,0,0.35)'; for (let i = 0; i < 4; i++) g.fillRect((Math.random() * 24) | 0, (Math.random() * 24) | 0, 6, 6); } return c; } export function initTextures() { Object.keys(BLOCKS).forEach(k => tex[k] = makeTex(k)); // Item/tool sprites const itemIds = [ 'arrow','bow', 'wood_pickaxe','stone_pickaxe','iron_pickaxe', 'wood_axe','stone_axe','iron_axe', 'wood_shovel','stone_shovel','iron_shovel', 'wood_sword','stone_sword','iron_sword', 'iron_ingot','gold_ingot','copper_ingot', 'meat','cooked', 'wheat','bread','carrot','potato','baked_potato','mushroom_stew','wheat_seeds', 'chicken_meat','feather','bone','gunpowder', 'scorpion_stinger','polar_fur','slime_ball','eagle_feather', 'gold_armor', ]; itemIds.forEach(id => { itemTex[id] = makeItemTex(id); }); }