feat: tile hulls

This commit is contained in:
cha0s 2024-07-07 17:31:27 -05:00
parent 64ece0cb86
commit cd875f8025
3 changed files with 108 additions and 1 deletions

View File

@ -1,7 +1,7 @@
import gather from '@/util/gather.js'; import gather from '@/util/gather.js';
const Gathered = gather( const Gathered = gather(
import.meta.glob('./*.js', {eager: true, import: 'default'}), import.meta.glob(['./*.js', '!./*.test.js'], {eager: true, import: 'default'}),
); );
const Components = {}; const Components = {};

View File

@ -1,4 +1,5 @@
import Component from '@/ecs/component.js'; import Component from '@/ecs/component.js';
import {floodwalk2D, ortho, removeCollinear} from '@/util/math.js';
import vector2d from './helpers/vector-2d'; import vector2d from './helpers/vector-2d';
@ -14,6 +15,67 @@ class LayerProxy {
get data() { get data() {
return this.layer.data; return this.layer.data;
} }
get hulls() {
const {data, area, tileSize} = this;
const hulls = [];
const seen = {};
const n = data.length;
const {x: w, y: h} = area;
let x = 0;
let y = 0;
for (let i = 0; i < n; ++i) {
if (data[i]) {
if (!seen[i]) {
const indices = floodwalk2D(new Set([data[i]]), data, {x, y, w, h});
if (indices.size > 0) {
const pointHash = Object.create(null);
const points = [];
const seePoint = ({x, y}) => {
if (pointHash[y]?.[x]) {
return false;
}
if (!pointHash[y]) {
pointHash[y] = Object.create({});
}
return pointHash[y][x] = true;
};
for (const index of indices) {
seen[index] = true;
const op = {
x: tileSize.x * (index % area.x),
y: tileSize.y * (Math.floor(index / area.x)),
};
let p;
const tsq = {x: tileSize.x / 4, y: tileSize.y / 4};
p = {x: op.x + tsq.x, y: op.y + tsq.y};
if (seePoint(p)) {
points.push(p);
}
p = {x: op.x + tileSize.x - tsq.x, y: op.y + tsq.y};
if (seePoint(p)) {
points.push(p);
}
p = {x: op.x + tileSize.x - tsq.x, y: op.y + tileSize.y - tsq.y};
if (seePoint(p)) {
points.push(p);
}
p = {x: op.x + tsq.x, y: op.y + tileSize.y - tsq.y};
if (seePoint(p)) {
points.push(p);
}
}
hulls.push(removeCollinear(ortho(points, {x: tileSize.x / 2, y: tileSize.y / 2})));
}
}
}
x += 1;
if (x === w) {
x -= w;
y += 1;
}
}
return hulls;
}
get layer() { get layer() {
return this.instance.layers[this.index]; return this.instance.layers[this.index];
} }

View File

@ -0,0 +1,45 @@
import {expect, test} from 'vitest';
import Ecs from '@/ecs/ecs.js';
import TileLayers from './tile-layers.js';
test('creates hulls', async () => {
const Component = new TileLayers(new Ecs());
const data = Array(64).fill(0);
data[9] = 1;
data[10] = 1;
data[17] = 1;
data[18] = 1;
const layers = await Component.create(1, {
layers: [
{
area: {x: 8, y: 8},
data,
source: '',
tileSize: {x: 16, y: 16},
}
],
});
expect(layers.layer(0).hulls)
.to.deep.equal([
[
{x: 20, y: 20},
{x: 44, y: 20},
{x: 44, y: 44},
{x: 20, y: 44},
]
]);
data[11] = 1;
expect(layers.layer(0).hulls)
.to.deep.equal([
[
{x: 20, y: 20},
{x: 60, y: 20},
{x: 60, y: 28},
{x: 44, y: 28},
{x: 44, y: 44},
{x: 20, y: 44},
]
]);
});