feat: tile hulls
This commit is contained in:
parent
64ece0cb86
commit
cd875f8025
|
@ -1,7 +1,7 @@
|
|||
import gather from '@/util/gather.js';
|
||||
|
||||
const Gathered = gather(
|
||||
import.meta.glob('./*.js', {eager: true, import: 'default'}),
|
||||
import.meta.glob(['./*.js', '!./*.test.js'], {eager: true, import: 'default'}),
|
||||
);
|
||||
|
||||
const Components = {};
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
import Component from '@/ecs/component.js';
|
||||
import {floodwalk2D, ortho, removeCollinear} from '@/util/math.js';
|
||||
|
||||
import vector2d from './helpers/vector-2d';
|
||||
|
||||
|
@ -14,6 +15,67 @@ class LayerProxy {
|
|||
get 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() {
|
||||
return this.instance.layers[this.index];
|
||||
}
|
||||
|
|
45
app/ecs-components/tile-layers.test.js
Normal file
45
app/ecs-components/tile-layers.test.js
Normal 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},
|
||||
]
|
||||
]);
|
||||
});
|
Loading…
Reference in New Issue
Block a user