507 lines
14 KiB
JavaScript
507 lines
14 KiB
JavaScript
// Текстуры блоков (простые)
|
|
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); });
|
|
}
|