Newer
Older
rpg / v2 / packages / engine / src / world / chunk.ts
/**
 * Чанк воксельного мира — колонна 16×H×16. Чистая математика (урок №3).
 * Локальные координаты: x,z в 0..15, y в 0..H-1; значение — индекс палитры
 * (0 — пустота), как в VoxelGrid.
 */
export const CHUNK_SX = 16;
export const CHUNK_SZ = 16;

export class Chunk {
    readonly cx: number;
    readonly cz: number;
    readonly sy: number;
    readonly data: Uint8Array;

    constructor(cx: number, cz: number, sy = 64) {
        if (sy <= 0) throw new Error(`Chunk: высота ${sy} должна быть положительной`);
        this.cx = cx;
        this.cz = cz;
        this.sy = sy;
        this.data = new Uint8Array(CHUNK_SX * sy * CHUNK_SZ);
    }

    inside(lx: number, y: number, lz: number): boolean {
        return lx >= 0 && lz >= 0 && y >= 0 && lx < CHUNK_SX && lz < CHUNK_SZ && y < this.sy;
    }

    idx(lx: number, y: number, lz: number): number {
        return lx + CHUNK_SX * (y + this.sy * lz);
    }

    get(lx: number, y: number, lz: number): number {
        if (!this.inside(lx, y, lz)) return 0;
        return this.data[this.idx(lx, y, lz)];
    }

    set(lx: number, y: number, lz: number, color: number): void {
        if (!this.inside(lx, y, lz)) return;
        if (color < 0 || color > 255) throw new Error(`Chunk.set: цвет ${color} вне 0..255`);
        this.data[this.idx(lx, y, lz)] = color;
    }

    isEmpty(lx: number, y: number, lz: number): boolean {
        return this.get(lx, y, lz) === 0;
    }

    count(): number {
        let n = 0;
        for (let i = 0; i < this.data.length; i++) if (this.data[i] !== 0) n++;
        return n;
    }
}