- Текстура studs v4 (круглые, объём+тени, сочный цвет), URL studs_v4_*. - PrimitiveManager: emissive 45% цвета + новые константы (GRID 4, UNIT 1). - BlockManager/BlockTypes: studs-block на v4-текстуре, specular убран. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
140 lines
8.6 KiB
JavaScript
140 lines
8.6 KiB
JavaScript
/**
|
||
* BlockTypes — реестр voxel-блоков для Рублокс-редактора.
|
||
*
|
||
* Используем Kenney Voxel Pack (CC0) — текстуры 32×32, лежат в
|
||
* /public/kubikon-assets/textures/.
|
||
*
|
||
* Каждый блок может иметь:
|
||
* texture — одна текстура на все 6 граней (простые кубы)
|
||
* ИЛИ
|
||
* top/side/bottom — три текстуры для верха, боков, низа (трава, тыква, бревно)
|
||
*
|
||
* BlockManager автоматически выберет правильный материал.
|
||
*/
|
||
|
||
const TEX = '/kubikon-assets/textures';
|
||
|
||
/**
|
||
* Создать описание простого куба с одной текстурой.
|
||
*/
|
||
const cube = (id, name, category, texture, opts = {}) => ({
|
||
id, name, category, texture, ...opts,
|
||
});
|
||
|
||
/**
|
||
* Создать описание мульти-материал куба (разные текстуры на гранях).
|
||
* top/side/bottom могут быть отдельными или одинаковыми (если совпадают — куб с side="top").
|
||
*/
|
||
const multiCube = (id, name, category, top, side, bottom, opts = {}) => ({
|
||
id, name, category, top, side, bottom, ...opts,
|
||
});
|
||
|
||
/**
|
||
* Полный список блоков.
|
||
* Цвет fallback в swatch — берётся из категории.
|
||
*/
|
||
export const BLOCK_TYPES = [
|
||
// === ЗЕМЛЯ ===
|
||
multiCube('grass', 'Трава', 'Земля', `${TEX}/grass_top.png`, `${TEX}/dirt_grass.png`, `${TEX}/dirt.png`),
|
||
cube('dirt', 'Земля', 'Земля', `${TEX}/dirt.png`),
|
||
cube('sand', 'Песок', 'Земля', `${TEX}/sand.png`),
|
||
cube('redsand', 'Красный песок', 'Земля', `${TEX}/redsand.png`),
|
||
cube('greysand', 'Серый песок', 'Земля', `${TEX}/greysand.png`),
|
||
cube('snow', 'Снег', 'Земля', `${TEX}/snow.png`),
|
||
multiCube('grass-snow', 'Снежная трава', 'Земля', `${TEX}/snow.png`, `${TEX}/dirt_snow.png`, `${TEX}/dirt.png`),
|
||
multiCube('grass-sand', 'Песочная трава','Земля', `${TEX}/sand.png`, `${TEX}/dirt_sand.png`, `${TEX}/dirt.png`),
|
||
cube('gravel-stone', 'Гравий', 'Земля', `${TEX}/gravel_stone.png`),
|
||
cube('gravel-dirt', 'Земляной гравий','Земля', `${TEX}/gravel_dirt.png`),
|
||
cube('ice', 'Лёд', 'Земля', `${TEX}/ice.png`, { alpha: 0.85 }),
|
||
|
||
// === КАМЕНЬ ===
|
||
// ВАЖНО: rock.png / rock_moss.png / stone_sand.png / greystone_sand.png — это
|
||
// спрайты-полублоки (камень в центре или песок сверху), не tile-able.
|
||
// На обычном кубе они выглядят как чёрный фон + камешек. Поэтому:
|
||
// - 'rock' → используем плиточную greystone.png
|
||
// - 'rock-moss' → greystone.png + лёгкий зелёный tint через emissive
|
||
// - 'stone-sand' / 'greystone-sand' оставляем без halfblock-текстур,
|
||
// используем обычные tile + цветовая схема
|
||
cube('rock', 'Камень', 'Камень', `${TEX}/greystone.png`),
|
||
cube('rock-moss', 'Замшелый камень', 'Камень', `${TEX}/greystone.png`, { emissive: [0.05, 0.18, 0.05] }),
|
||
cube('greystone', 'Серый камень', 'Камень', `${TEX}/greystone.png`),
|
||
cube('stone', 'Тёмный камень', 'Камень', `${TEX}/stone.png`),
|
||
cube('redstone', 'Редстоун', 'Камень', `${TEX}/redstone.png`),
|
||
|
||
// === РУДЫ (тёмный камень с вкраплениями) ===
|
||
cube('ore-coal', 'Уголь', 'Руда', `${TEX}/stone_coal.png`),
|
||
cube('ore-iron', 'Железная руда', 'Руда', `${TEX}/stone_iron.png`),
|
||
cube('ore-gold', 'Золотая руда', 'Руда', `${TEX}/stone_gold.png`),
|
||
cube('ore-diamond', 'Алмазная руда', 'Руда', `${TEX}/stone_diamond.png`),
|
||
cube('ore-silver', 'Серебряная руда', 'Руда', `${TEX}/stone_silver.png`),
|
||
cube('ore-browniron', 'Медная руда', 'Руда', `${TEX}/stone_browniron.png`),
|
||
cube('ore-ruby', 'Рубиновая руда', 'Руда', `${TEX}/greystone_ruby.png`),
|
||
cube('ore-emerald', 'Изумрудная руда', 'Руда', `${TEX}/redstone_emerald.png`),
|
||
|
||
// === ДЕРЕВО ===
|
||
cube('wood', 'Бревно', 'Дерево', `${TEX}/wood.png`),
|
||
cube('wood-red', 'Красное бревно', 'Дерево', `${TEX}/wood_red.png`),
|
||
|
||
// === ХЛОПОК / ШЕРСТЬ ===
|
||
cube('cotton-blue', 'Хлопок синий', 'Шерсть', `${TEX}/cotton_blue.png`),
|
||
cube('cotton-green', 'Хлопок зелёный', 'Шерсть', `${TEX}/cotton_green.png`),
|
||
cube('cotton-red', 'Хлопок красный', 'Шерсть', `${TEX}/cotton_red.png`),
|
||
cube('cotton-tan', 'Хлопок бежевый', 'Шерсть', `${TEX}/cotton_tan.png`),
|
||
|
||
// === КИРПИЧИ ===
|
||
cube('brick-red', 'Кирпич красный', 'Кирпич', `${TEX}/brick_red.png`),
|
||
cube('brick-grey', 'Кирпич серый', 'Кирпич', `${TEX}/brick_grey.png`),
|
||
|
||
// === СТЕКЛО ===
|
||
cube('glass', 'Стекло', 'Особые', `${TEX}/glass.png`, { alpha: 0.6 }),
|
||
cube('glass-frame', 'Стекло в раме', 'Особые', `${TEX}/glass_frame.png`, { alpha: 0.7 }),
|
||
|
||
// === ЛИСТВА ===
|
||
cube('leaves', 'Листва', 'Природа', `${TEX}/leaves.png`),
|
||
cube('leaves-orange', 'Жёлтая листва', 'Природа', `${TEX}/leaves_orange.png`),
|
||
cube('leaves-trans', 'Прозр. листва', 'Природа', `${TEX}/leaves_transparent.png`, { alpha: 0.9 }),
|
||
cube('leaves-orange-trans', 'Прозр.жёлт.листва', 'Природа', `${TEX}/leaves_orange_transparent.png`, { alpha: 0.9 }),
|
||
|
||
// === ЖИДКОСТИ И СПЕЦБЛОКИ ===
|
||
cube('water', 'Вода', 'Особые', `${TEX}/water.png`, { alpha: 0.75, isWater: true, animate: 'water' }),
|
||
cube('lava', 'Лава', 'Особые', `${TEX}/lava.png`, { emissive: [0.6, 0.2, 0], isLava: true, animate: 'lava' }),
|
||
|
||
// === КАКТУС / ПЕЧЬ (мульти-материал) ===
|
||
multiCube('cactus', 'Кактус', 'Природа', `${TEX}/cactus_top.png`, `${TEX}/cactus_side.png`, `${TEX}/cactus_inside.png`),
|
||
// Печь: только oven.png это «фасад» (дверца), остальное — серый камень.
|
||
// top = stone, side = oven (4 стороны с дверцей — лучше чем раньше),
|
||
// bottom = stone. В будущем для одной двери понадобится 6-face формат.
|
||
multiCube('oven', 'Печь', 'Особые', `${TEX}/stone.png`, `${TEX}/oven.png`, `${TEX}/stone.png`),
|
||
|
||
// === ОКРАШИВАЕМЫЕ (задача 09) — паритет со студией ===
|
||
cube('studs-block', 'Лего-кирпич', 'Окрашиваемые',
|
||
'/kubikon-assets/materials/studs_v4_diffuse.png',
|
||
{ colorable: true, normal: '/kubikon-assets/materials/studs_v4_normal.png', defaultColor: '#3a7aff' }),
|
||
];
|
||
|
||
/** Все доступные категории в порядке появления. */
|
||
export const BLOCK_CATEGORIES = Array.from(new Set(BLOCK_TYPES.map(b => b.category)));
|
||
|
||
/** Цвет для swatch'а в палитре, fallback по категории. */
|
||
export const CATEGORY_COLORS = {
|
||
'Земля': '#8b6f4e',
|
||
'Камень': '#7a7a7a',
|
||
'Руда': '#c9a04e',
|
||
'Дерево': '#a8743f',
|
||
'Шерсть': '#e8dcc4',
|
||
'Кирпич': '#9d4a3a',
|
||
'Особые': '#9966ff',
|
||
'Природа': '#5a8c3e',
|
||
'Окрашиваемые': '#3a7aff',
|
||
};
|
||
|
||
/** Найти описание блока по id. */
|
||
export function getBlockType(id) {
|
||
return BLOCK_TYPES.find(b => b.id === id) || BLOCK_TYPES[0];
|
||
}
|
||
|
||
/** Картинка-превью для палитры — для мульти-куба показываем верхнюю грань. */
|
||
export function blockPreview(b) {
|
||
return b.top || b.texture;
|
||
}
|