Newer
Older
rpg / v2 / packages / engine / src / combat / los.ts
/**
 * Линия видимости по сетке (перенос 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;
}