grechka-game/srcv3/render/textures.js

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); });
}