/**
* Линия видимости по сетке (перенос v1, чистая математика без рендера).
* Отрезок дискретизируется шагом 0.25 юнита; колонка с непрозрачным
* препятствием (стена дома, дерево) перекрывает обзор. Правила прозрачности
* — на игре (предикат), движок знает только геометрию.
*/
/** Шаг дискретизации отрезка, юнитов (1 юнит = 1 воксель по горизонтали). */
const STEP = 0.25;
/** Виден ли `to` из `from` с учётом непрозрачных колонок (tx, tz). */
export function hasLineOfSight(
from: { x: number; z: number },
to: { x: number; z: number },
isOpaque: (tx: number, tz: number) => boolean
): boolean {
const dx = to.x - from.x;
const dz = to.z - from.z;
const len = Math.hypot(dx, dz);
if (len < 1e-6) return true;
const n = Math.ceil(len / STEP);
const ux = dx / n;
const uz = dz / n;
// Концевые точки не проверяем: сами враг/герой стоят в своих колонках.
for (let i = 1; i < n; i++) {
const x = from.x + ux * i;
const z = from.z + uz * i;
if (isOpaque(Math.floor(x), Math.floor(z))) return false;
}
return true;
}