grechka-game/srcv3/world/occ3d.js

69 lines
3.4 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// ==================== ОККЛЮЗИЯ 3D — плотная сетка ====================
// Границы мира фиксированы генератором: WORLD_DEPTH = 48 по X и Z (то есть
// gx,gz из -48..48), а по Y генерация идёт от BEDROCK_GY-1 = 44 вниз до 0.
// 97 * 45 * 97 = 423 855 клеток — 414 КБ в Uint8Array.
//
// Зачем: isHiddenAt проверяла 6 соседей через getBlock, а тот строил строку
// "gx,gy,gz" и искал в Map. На 68k кандидатов это ~409k строковых
// конкатенаций — профиль показал 129 мс из 153 мс всего перестроения мешей.
// Здесь 6 чтений массива вместо 6 строковых lookup'ов.
//
// ВАЖНО: сетку обязаны обновлять все, кто меняет мир — setBlock/removeBlock
// в world-storage3d.js. Иначе окклюзия разойдётся с реальными блоками и
// внутренние грани начнут просвечивать (или исчезнут видимые блоки).
import { BLOCKS } from '../data/blocks.js';
export const OCC_X = 2 * 48 + 1; // 97
export const OCC_Z = 2 * 48 + 1;
export const OCC_Y = 45; // gy 0..44
export const OCC_MIN = -48, OCC_MAX = 48, OCC_MAX_GY = 44;
// Значения ячеек
export const OCC_EMPTY = 0; // блока нет
export const OCC_PRESENT = 1; // блок есть, но он прозрачный/жидкий/декор
export const OCC_OPAQUE = 2; // непрозрачный блок — закрывает соседей
const occGrid = new Uint8Array(OCC_X * OCC_Y * OCC_Z);
// Раскладка: (gy*OCC_Z + (gz-OCC_MIN))*OCC_X + (gx-OCC_MIN)
// => шаг по gx = 1, по gz = OCC_X, по gy = OCC_X*OCC_Z
export const OCC_STEP_X = 1;
export const OCC_STEP_Z = OCC_X;
export const OCC_STEP_Y = OCC_X * OCC_Z;
export function occIndex(gx, gy, gz) {
if (gx < OCC_MIN || gx > OCC_MAX || gz < OCC_MIN || gz > OCC_MAX ||
gy < 0 || gy > OCC_MAX_GY) return -1;
return (gy * OCC_Z + (gz - OCC_MIN)) * OCC_X + (gx - OCC_MIN);
}
// Плотность блока для оклюзии
export function occDensity(t) {
const def = BLOCKS[t];
if (!def) return OCC_EMPTY;
const opaque = !!def.solid && !def.fluid && !def.decor && !def.climbable &&
def.alpha === undefined;
return opaque ? OCC_OPAQUE : OCC_PRESENT;
}
export function occSet(gx, gy, gz, density) {
const i = occIndex(gx, gy, gz);
if (i >= 0) occGrid[i] = density;
}
// Пересобрать сетку целиком из массива блоков. Нужна при загрузке сейва и
// после полной генерации — там setBlock вызывается с bumpWorld=false, но
// запись в сетку всё равно идёт, так что это страховка на случай, когда
// массив блоков был подменён снаружи.
export function occRebuildFrom(blocksArr) {
occGrid.fill(OCC_EMPTY);
for (let i = 0; i < blocksArr.length; i++) {
const b = blocksArr[i];
if (b.dead) continue;
const idx = occIndex(b.gx, b.gy, b.gz || 0);
if (idx >= 0) occGrid[idx] = occDensity(b.t);
}
}
export function occClear() { occGrid.fill(OCC_EMPTY); }