/**
* Воксельный олень (безгласная фауна v1, воксельная версия): тихая
* серо-бурая живность у прудов. Модель строится по мировому центру (cx, cz)
* мордой вдоль +X; шаг (step) поднимает диагональные пары ног — грубый, но
* живой walk-цикл. Направление (dir) — поворот на четверти оборота вокруг Y,
* олень смотрит туда, куда идёт.
*/
import { GROUND_Y } from './areas';
/** Воксель позы: позиция в мире + цвет-строка (как у VoxelCloud). */
export interface DeerVoxel {
pos: [number, number, number];
color: string;
}
const BODY = '#6e6156'; // серо-бурый бок
const DARK = '#54493f'; // копыта, нос, тень брюха
const LIGHT = '#7d7264'; // спина, хвост
const ANTLER = '#8a7a66'; // рога (сухое дерево)
/**
* Поворот смещения на dir×90° вокруг Y: dir 0 — морда +X,
* 1 — +Z, 2 — −X, 3 — −Z (модель симметрична по бокам, зеркала не нужно).
*/
export function rotXZ(dx: number, dz: number, dir: number): [number, number] {
for (let i = 0; i < (dir & 3); i++) {
const t = dx;
dx = -dz;
dz = t;
}
return [dx, dz];
}
/**
* Олень в мировых координатах: ноги на земле (GROUND_Y), высота ~10 вокселей
* (герой — 16). step — фаза шага (0/1), поднимает диагональные пары ног;
* dir — направление взгляда (см. rotXZ).
*/
export function deerVoxels(cx: number, cz: number, step: boolean, dir = 0): DeerVoxel[] {
const out: DeerVoxel[] = [];
const put = (dx: number, dy: number, dz: number, color: string) => {
const [rx, rz] = rotXZ(dx, dz, dir);
out.push({ pos: [cx + rx, dy, cz + rz], color });
};
// Ноги: диагональные пары (перед-лево + зад-право) поднимаются на шаге.
const lift = step ? 2 : 0;
for (const [lx, lz] of [[-4, -2], [4, 2], [-4, 2], [4, -2]] as const) {
const up = (lx === -4) === (lz === -2) ? lift : 0; // диагональ шагает
for (let y = 0; y < 4; y++) put(lx, GROUND_Y + y + up, lz, DARK);
}
// Туловище: 9×2×5, спина светлее.
for (let dx = -4; dx <= 4; dx++)
for (let dz = -2; dz <= 2; dz++) {
put(dx, GROUND_Y + 4, dz, dx % 2 === 0 ? BODY : DARK);
put(dx, GROUND_Y + 5, dz, LIGHT);
}
// Шея и голова: вперед-вверх, нос темный, уши-рожки.
put(4, GROUND_Y + 6, 0, BODY);
put(5, GROUND_Y + 6, 0, BODY);
put(5, GROUND_Y + 7, 0, DARK); // нос
put(5, GROUND_Y + 8, 0, LIGHT);
put(5, GROUND_Y + 9, -1, ANTLER);
put(5, GROUND_Y + 9, 1, ANTLER);
// Хвост.
put(-5, GROUND_Y + 5, 0, LIGHT);
return out;
}