refactor: much improved collision
This commit is contained in:
parent
3d862d39d5
commit
b96566d0a0
|
@ -21,12 +21,24 @@ export default async function createHomestead(Ecs) {
|
|||
await ecs.create({
|
||||
Collider: {
|
||||
bodies: [
|
||||
[
|
||||
{x: -36, y: -16},
|
||||
{x: -21, y: -16},
|
||||
{x: -36, y: -1},
|
||||
{x: -21, y: -1},
|
||||
],
|
||||
{
|
||||
points: [
|
||||
{x: -36, y: 8},
|
||||
{x: -21, y: 8},
|
||||
{x: -36, y: 17},
|
||||
{x: -21, y: 17},
|
||||
],
|
||||
tags: ['door'],
|
||||
},
|
||||
{
|
||||
impassable: 1,
|
||||
points: [
|
||||
{x: -52, y: -16},
|
||||
{x: 48, y: -16},
|
||||
{x: -52, y: 15},
|
||||
{x: 48, y: 15},
|
||||
],
|
||||
},
|
||||
],
|
||||
collisionStartScript: '/assets/shit-shack/collision-start.js',
|
||||
},
|
||||
|
|
|
@ -20,12 +20,14 @@ export default async function createHouse(Ecs) {
|
|||
await ecs.create({
|
||||
Collider: {
|
||||
bodies: [
|
||||
[
|
||||
{x: -8, y: -8},
|
||||
{x: 7, y: -8},
|
||||
{x: 7, y: 7},
|
||||
{x: -8, y: 7},
|
||||
],
|
||||
{
|
||||
points: [
|
||||
{x: -8, y: -8},
|
||||
{x: 7, y: -8},
|
||||
{x: 7, y: 7},
|
||||
{x: -8, y: 7},
|
||||
],
|
||||
},
|
||||
],
|
||||
collisionStartScript: '/assets/house/collision-start.js',
|
||||
},
|
||||
|
|
|
@ -3,12 +3,14 @@ export default async function createPlayer(id) {
|
|||
Camera: {},
|
||||
Collider: {
|
||||
bodies: [
|
||||
[
|
||||
{x: -8, y: -8},
|
||||
{x: 7, y: -8},
|
||||
{x: -8, y: 7},
|
||||
{x: 7, y: 7},
|
||||
],
|
||||
{
|
||||
points: [
|
||||
{x: -8, y: -8},
|
||||
{x: 7, y: -8},
|
||||
{x: 7, y: 7},
|
||||
{x: -8, y: 7},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
Controlled: {},
|
||||
|
|
|
@ -11,17 +11,20 @@ export default class Collider extends Component {
|
|||
isCollidingWith(other) {
|
||||
const {aabb, aabbs} = this;
|
||||
const {aabb: otherAabb, aabbs: otherAabbs} = other;
|
||||
const intersections = [];
|
||||
if (!intersects(aabb, otherAabb)) {
|
||||
return false;
|
||||
return intersections;
|
||||
}
|
||||
for (const aabb of aabbs) {
|
||||
for (const otherAabb of otherAabbs) {
|
||||
for (const i in aabbs) {
|
||||
const aabb = aabbs[i];
|
||||
for (const j in otherAabbs) {
|
||||
const otherAabb = otherAabbs[j];
|
||||
if (intersects(aabb, otherAabb)) {
|
||||
return true;
|
||||
intersections.push([this.bodies[i], other.bodies[j]]);
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
return intersections;
|
||||
}
|
||||
isWithin(query) {
|
||||
const {aabb, aabbs} = this;
|
||||
|
@ -40,9 +43,9 @@ export default class Collider extends Component {
|
|||
this.aabb = {x0: Infinity, x1: -Infinity, y0: Infinity, y1: -Infinity};
|
||||
this.aabbs = [];
|
||||
const {bodies} = this;
|
||||
for (const points of bodies) {
|
||||
for (const body of bodies) {
|
||||
let x0 = Infinity, x1 = -Infinity, y0 = Infinity, y1 = -Infinity;
|
||||
for (const point of points) {
|
||||
for (const point of body.points) {
|
||||
const x = point.x + px;
|
||||
const y = point.y + py;
|
||||
if (x < x0) x0 = x;
|
||||
|
@ -88,8 +91,18 @@ export default class Collider extends Component {
|
|||
bodies: {
|
||||
type: 'array',
|
||||
subtype: {
|
||||
type: 'array',
|
||||
subtype: vector2d('int16'),
|
||||
type: 'object',
|
||||
properties: {
|
||||
impassable: {type: 'uint8'},
|
||||
points: {
|
||||
type: 'array',
|
||||
subtype: vector2d('int16'),
|
||||
},
|
||||
tags: {
|
||||
type: 'array',
|
||||
subtype: {type: 'string'},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
collisionEndScript: {type: 'string'},
|
||||
|
|
|
@ -2,20 +2,34 @@ import Component from '@/ecs/component.js';
|
|||
|
||||
export default class Position extends Component {
|
||||
instanceFromSchema() {
|
||||
const Instance = super.instanceFromSchema();
|
||||
const Component = this;
|
||||
Object.defineProperty(Instance.prototype, 'tile', {
|
||||
get: function () {
|
||||
const {TileLayers} = Component.ecs.get(1);
|
||||
const {Position: {x, y}} = Component.ecs.get(this.entity);
|
||||
const {ecs} = this;
|
||||
return class PositionInstance extends super.instanceFromSchema() {
|
||||
lastX;
|
||||
lastY;
|
||||
get x() {
|
||||
return super.x;
|
||||
}
|
||||
set x(x) {
|
||||
this.lastX = super.x;
|
||||
super.x = x;
|
||||
}
|
||||
get y() {
|
||||
return super.y;
|
||||
}
|
||||
set y(y) {
|
||||
this.lastY = super.y;
|
||||
super.y = y;
|
||||
}
|
||||
get tile() {
|
||||
const {TileLayers} = ecs.get(1);
|
||||
const {Position: {x, y}} = ecs.get(this.entity);
|
||||
const {tileSize} = TileLayers.layers[0];
|
||||
return {
|
||||
x: (x - (x % tileSize.x)) / tileSize.x,
|
||||
y: (y - (y % tileSize.y)) / tileSize.y,
|
||||
}
|
||||
},
|
||||
});
|
||||
return Instance;
|
||||
}
|
||||
};
|
||||
}
|
||||
static properties = {
|
||||
x: {type: 'float32'},
|
||||
|
|
|
@ -61,19 +61,30 @@ export default class Colliders extends System {
|
|||
continue;
|
||||
}
|
||||
delete other.Collider.collidingWith[entity.id];
|
||||
if (entity.Collider.isCollidingWith(other.Collider)) {
|
||||
const intersections = entity.Collider.isCollidingWith(other.Collider);
|
||||
if (intersections.length > 0) {
|
||||
entity.Collider.collidingWith[other.id] = true;
|
||||
other.Collider.collidingWith[entity.id] = true;
|
||||
if (!wasCollidingWith[other.id]) {
|
||||
if (entity.Collider.collisionStartScriptInstance) {
|
||||
entity.Collider.collisionStartScriptInstance.context.intersections = intersections;
|
||||
entity.Collider.collisionStartScriptInstance.context.other = other;
|
||||
Ticking.addTickingPromise(entity.Collider.collisionStartScriptInstance.tickingPromise());
|
||||
}
|
||||
if (other.Collider.collisionStartScriptInstance) {
|
||||
other.Collider.collisionStartScriptInstance.context.intersections = intersections
|
||||
.map(([l, r]) => [r, l]);
|
||||
other.Collider.collisionStartScriptInstance.context.other = entity;
|
||||
Ticking.addTickingPromise(other.Collider.collisionStartScriptInstance.tickingPromise());
|
||||
}
|
||||
}
|
||||
for (const [, {impassable}] of intersections) {
|
||||
if (impassable) {
|
||||
entity.Position.x = entity.Position.lastX
|
||||
entity.Position.y = entity.Position.lastY
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const otherId in wasCollidingWith) {
|
||||
|
@ -93,24 +104,9 @@ export default class Colliders extends System {
|
|||
}
|
||||
|
||||
within(query) {
|
||||
const {x0, x1, y0, y1} = query;
|
||||
const [cx0, cy0] = this.hash.chunkIndex(x0, y0);
|
||||
const [cx1, cy1] = this.hash.chunkIndex(x1, y1);
|
||||
const seen = {};
|
||||
const within = new Set();
|
||||
for (let cy = cy0; cy <= cy1; ++cy) {
|
||||
for (let cx = cx0; cx <= cx1; ++cx) {
|
||||
for (const id of this.hash.chunks[cx][cy]) {
|
||||
if (seen[id]) {
|
||||
continue;
|
||||
}
|
||||
seen[id] = true;
|
||||
const entity = this.ecs.get(id);
|
||||
if (entity.Collider.isWithin(query)) {
|
||||
within.add(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const id of this.hash.within(query)) {
|
||||
within.add(this.ecs.get(id));
|
||||
}
|
||||
return within;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import {System} from '@/ecs/index.js';
|
||||
import {intersects} from '@/util/math.js';
|
||||
import SpatialHash from '@/util/spatial-hash.js';
|
||||
|
||||
export default class VisibleAabbs extends System {
|
||||
|
@ -33,6 +32,7 @@ export default class VisibleAabbs extends System {
|
|||
|
||||
updateHash(entity) {
|
||||
if (!entity.VisibleAabb) {
|
||||
this.hash.remove(entity.id);
|
||||
return;
|
||||
}
|
||||
this.hash.update(entity.VisibleAabb, entity.id);
|
||||
|
@ -63,24 +63,9 @@ export default class VisibleAabbs extends System {
|
|||
}
|
||||
|
||||
within(query) {
|
||||
const {x0, x1, y0, y1} = query;
|
||||
const [cx0, cy0] = this.hash.chunkIndex(x0, y0);
|
||||
const [cx1, cy1] = this.hash.chunkIndex(x1, y1);
|
||||
const seen = {};
|
||||
const within = new Set();
|
||||
for (let cy = cy0; cy <= cy1; ++cy) {
|
||||
for (let cx = cx0; cx <= cx1; ++cx) {
|
||||
for (const id of this.hash.chunks[cx][cy]) {
|
||||
if (seen[id]) {
|
||||
continue;
|
||||
}
|
||||
seen[id] = true;
|
||||
const entity = this.ecs.get(id);
|
||||
if (intersects(query, entity.VisibleAabb)) {
|
||||
within.add(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const id of this.hash.within(query)) {
|
||||
within.add(this.ecs.get(id));
|
||||
}
|
||||
return within;
|
||||
}
|
||||
|
|
|
@ -7,18 +7,18 @@ import {useMainEntity} from '@/context/main-entity.js';
|
|||
import Emitter from './emitter.jsx';
|
||||
import Sprite from './sprite.jsx';
|
||||
|
||||
function Aabb({color, x0, y0, x1, y1}) {
|
||||
function Aabb({color, width = 0.5, x0, y0, x1, y1, ...rest}) {
|
||||
const draw = useCallback((g) => {
|
||||
g.clear();
|
||||
g.lineStyle(0.5, color);
|
||||
g.lineStyle(width, color);
|
||||
g.moveTo(x0, y0);
|
||||
g.lineTo(x1, y0);
|
||||
g.lineTo(x1, y1);
|
||||
g.lineTo(x0, y1);
|
||||
g.lineTo(x1 + 1, y0);
|
||||
g.lineTo(x1 + 1, y1 + 1);
|
||||
g.lineTo(x0, y1 + 1);
|
||||
g.lineTo(x0, y0);
|
||||
}, [color, x0, x1, y0, y1]);
|
||||
}, [color, width, x0, x1, y0, y1]);
|
||||
return (
|
||||
<Graphics draw={draw} x={0.5} y = {0.5} />
|
||||
<Graphics draw={draw} x={0.5} y={0.5} {...rest} />
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -51,6 +51,9 @@ function Entity({entity, ...rest}) {
|
|||
if (!entity) {
|
||||
return false;
|
||||
}
|
||||
if (debug) {
|
||||
entity.Collider.recalculateAabbs();
|
||||
}
|
||||
return (
|
||||
<Container
|
||||
zIndex={entity.Position?.y || 0}
|
||||
|
@ -72,20 +75,25 @@ function Entity({entity, ...rest}) {
|
|||
{debug && (
|
||||
<Aabb
|
||||
color={0xff00ff}
|
||||
x0={entity.VisibleAabb.x0}
|
||||
x1={entity.VisibleAabb.x1}
|
||||
y0={entity.VisibleAabb.y0}
|
||||
y1={entity.VisibleAabb.y1}
|
||||
{...entity.VisibleAabb}
|
||||
/>
|
||||
)}
|
||||
{debug && entity.Collider && (
|
||||
<Aabb
|
||||
color={0xffff00}
|
||||
x0={entity.Collider.aabb.x0}
|
||||
x1={entity.Collider.aabb.x1}
|
||||
y0={entity.Collider.aabb.y0}
|
||||
y1={entity.Collider.aabb.y1}
|
||||
/>
|
||||
<>
|
||||
<Aabb
|
||||
color={0xffffff}
|
||||
width={0.5}
|
||||
{...entity.Collider.aabb}
|
||||
/>
|
||||
{entity.Collider.aabbs.map((aabb, i) => (
|
||||
<Aabb
|
||||
color={0xffff00}
|
||||
width={0.25}
|
||||
key={i}
|
||||
{...aabb}
|
||||
/>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
{debug && mainEntity == entity.id && (
|
||||
<Aabb
|
||||
|
|
|
@ -1,3 +1,7 @@
|
|||
export function clamp(n, min, max) {
|
||||
return Math.max(min, Math.min(max, n));
|
||||
}
|
||||
|
||||
export function distance({x: lx, y: ly}, {x: rx, y: ry}) {
|
||||
const xd = lx - rx;
|
||||
const yd = ly - ry;
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
import {clamp, intersects} from '@/util/math.js';
|
||||
|
||||
export default class SpatialHash {
|
||||
|
||||
constructor({x, y}) {
|
||||
|
@ -8,43 +10,74 @@ export default class SpatialHash {
|
|||
.map(() => (
|
||||
Array(Math.ceil(this.area.y / this.chunkSize.y))
|
||||
.fill(0)
|
||||
.map(() => [])
|
||||
.map(() => new Map())
|
||||
));
|
||||
this.data = {};
|
||||
}
|
||||
|
||||
clamp(x, y) {
|
||||
return [
|
||||
Math.max(0, Math.min(x, this.area.x - 1)),
|
||||
Math.max(0, Math.min(y, this.area.y - 1))
|
||||
];
|
||||
this.data = new Map();
|
||||
}
|
||||
|
||||
chunkIndex(x, y) {
|
||||
const [cx, cy] = this.clamp(x, y);
|
||||
return [
|
||||
Math.floor(cx / this.chunkSize.x),
|
||||
Math.floor(cy / this.chunkSize.y),
|
||||
];
|
||||
return {
|
||||
x: clamp(Math.floor(x / this.chunkSize.x), 0, this.chunks.length - 1),
|
||||
y: clamp(Math.floor(y / this.chunkSize.y), 0, this.chunks[0].length - 1),
|
||||
};
|
||||
}
|
||||
|
||||
remove(datum) {
|
||||
if (datum in this.data) {
|
||||
for (const [cx, cy] of this.data[datum]) {
|
||||
const chunk = this.chunks[cx][cy];
|
||||
chunk.splice(chunk.indexOf(datum), 1);
|
||||
}
|
||||
if (!this.data.has(datum)) {
|
||||
return;
|
||||
}
|
||||
this.data[datum] = [];
|
||||
for (const {x, y} of this.data.get(datum).chunks) {
|
||||
this.chunks[x][y].delete(datum);
|
||||
}
|
||||
this.data.delete(datum);
|
||||
}
|
||||
|
||||
update({x0, x1, y0, y1}, datum) {
|
||||
this.remove(datum);
|
||||
for (const [x, y] of [[x0, y0], [x0, y1], [x1, y0], [x1, y1]]) {
|
||||
const [cx, cy] = this.chunkIndex(x, y);
|
||||
this.data[datum].push([cx, cy]);
|
||||
this.chunks[cx][cy].push(datum);
|
||||
const [sx0, sx1] = x0 < x1 ? [x0, x1] : [x1, x0];
|
||||
const [sy0, sy1] = y0 < y1 ? [y0, y1] : [y1, y0];
|
||||
const {x: cx0, y: cy0} = this.chunkIndex(sx0, sy0);
|
||||
const {x: cx1, y: cy1} = this.chunkIndex(sx1, sy1);
|
||||
const chunks = [];
|
||||
for (let iy = cy0; iy <= cy1; ++iy) {
|
||||
for (let ix = cx0; ix <= cx1; ++ix) {
|
||||
const chunk = this.chunks[ix][iy];
|
||||
if (!chunk.has(datum)) {
|
||||
chunk.set(datum, true);
|
||||
}
|
||||
chunks.push({x: ix, y: iy});
|
||||
}
|
||||
}
|
||||
this.data.set(
|
||||
datum,
|
||||
{
|
||||
bounds: {x0: sx0, x1: sx1, y0: sy0, y1: sy1},
|
||||
chunks,
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
within(query) {
|
||||
const {x0, x1, y0, y1} = query;
|
||||
const [sx0, sx1] = x0 < x1 ? [x0, x1] : [x1, x0];
|
||||
const [sy0, sy1] = y0 < y1 ? [y0, y1] : [y1, y0];
|
||||
const {x: cx0, y: cy0} = this.chunkIndex(sx0, sy0);
|
||||
const {x: cx1, y: cy1} = this.chunkIndex(sx1, sy1);
|
||||
const candidates = new Set();
|
||||
const within = new Set();
|
||||
for (let cy = cy0; cy <= cy1; ++cy) {
|
||||
for (let cx = cx0; cx <= cx1; ++cx) {
|
||||
for (const [datum] of this.chunks[cx][cy]) {
|
||||
candidates.add(datum);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (const datum of candidates) {
|
||||
if (intersects(this.data.get(datum).bounds, query)) {
|
||||
within.add(datum);
|
||||
}
|
||||
}
|
||||
return within;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
125
app/util/spatial-hash.test.js
Normal file
125
app/util/spatial-hash.test.js
Normal file
|
@ -0,0 +1,125 @@
|
|||
import {expect, test} from 'vitest';
|
||||
|
||||
import SpatialHash from './spatial-hash.js';
|
||||
|
||||
test('creates chunks', async () => {
|
||||
const hash = new SpatialHash({x: 128, y: 128});
|
||||
expect(hash.chunks.length)
|
||||
.to.equal(2);
|
||||
expect(hash.chunks[0].length)
|
||||
.to.equal(2);
|
||||
expect(hash.chunks[1].length)
|
||||
.to.equal(2);
|
||||
});
|
||||
|
||||
test('clamps to actual chunks', async () => {
|
||||
const hash = new SpatialHash({x: 640, y: 640});
|
||||
expect(hash.chunkIndex(0, 0))
|
||||
.to.deep.equal({x: 0, y: 0});
|
||||
expect(hash.chunkIndex(320, 320))
|
||||
.to.deep.equal({x: 5, y: 5});
|
||||
expect(hash.chunkIndex(1280, 1280))
|
||||
.to.deep.equal({x: 9, y: 9});
|
||||
});
|
||||
|
||||
test('updates with data', async () => {
|
||||
const hash = new SpatialHash({x: 640, y: 640});
|
||||
hash.update({x0: 32, x1: 96, y0: 32, y1: 96}, 'foobar');
|
||||
expect(hash.data.get('foobar'))
|
||||
.to.deep.equal({
|
||||
bounds: {x0: 32, x1: 96, y0: 32, y1: 96},
|
||||
chunks: [
|
||||
{x: 0, y: 0},
|
||||
{x: 1, y: 0},
|
||||
{x: 0, y: 1},
|
||||
{x: 1, y: 1},
|
||||
],
|
||||
});
|
||||
expect(Array.from(hash.chunks[0][0]))
|
||||
.to.deep.equal([['foobar', true]]);
|
||||
expect(Array.from(hash.chunks[1][0]))
|
||||
.to.deep.equal([['foobar', true]]);
|
||||
expect(Array.from(hash.chunks[1][1]))
|
||||
.to.deep.equal([['foobar', true]]);
|
||||
expect(Array.from(hash.chunks[0][1]))
|
||||
.to.deep.equal([['foobar', true]]);
|
||||
hash.update({x0: 48, x1: 32, y0: 32, y1: 96}, 'foobar');
|
||||
expect(hash.data.get('foobar'))
|
||||
.to.deep.equal({
|
||||
bounds: {x0: 32, x1: 48, y0: 32, y1: 96},
|
||||
chunks: [
|
||||
{x: 0, y: 0},
|
||||
{x: 0, y: 1},
|
||||
],
|
||||
});
|
||||
expect(Array.from(hash.chunks[0][0]))
|
||||
.to.deep.equal([['foobar', true]]);
|
||||
expect(Array.from(hash.chunks[1][0]))
|
||||
.to.deep.equal([]);
|
||||
expect(Array.from(hash.chunks[1][1]))
|
||||
.to.deep.equal([]);
|
||||
expect(Array.from(hash.chunks[0][1]))
|
||||
.to.deep.equal([['foobar', true]]);
|
||||
hash.update({x0: 32, x1: 160, y0: 32, y1: 160}, 'foobar');
|
||||
expect(hash.data.get('foobar'))
|
||||
.to.deep.equal({
|
||||
bounds: {x0: 32, x1: 160, y0: 32, y1: 160},
|
||||
chunks: [
|
||||
{x: 0, y: 0},
|
||||
{x: 1, y: 0},
|
||||
{x: 2, y: 0},
|
||||
{x: 0, y: 1},
|
||||
{x: 1, y: 1},
|
||||
{x: 2, y: 1},
|
||||
{x: 0, y: 2},
|
||||
{x: 1, y: 2},
|
||||
{x: 2, y: 2},
|
||||
],
|
||||
});
|
||||
expect(Array.from(hash.chunks[0][0]))
|
||||
.to.deep.equal([['foobar', true]]);
|
||||
expect(Array.from(hash.chunks[1][0]))
|
||||
.to.deep.equal([['foobar', true]]);
|
||||
expect(Array.from(hash.chunks[2][0]))
|
||||
.to.deep.equal([['foobar', true]]);
|
||||
expect(Array.from(hash.chunks[3][0]))
|
||||
.to.deep.equal([]);
|
||||
expect(Array.from(hash.chunks[0][1]))
|
||||
.to.deep.equal([['foobar', true]]);
|
||||
expect(Array.from(hash.chunks[1][1]))
|
||||
.to.deep.equal([['foobar', true]]);
|
||||
expect(Array.from(hash.chunks[2][1]))
|
||||
.to.deep.equal([['foobar', true]]);
|
||||
expect(Array.from(hash.chunks[3][1]))
|
||||
.to.deep.equal([]);
|
||||
expect(Array.from(hash.chunks[0][2]))
|
||||
.to.deep.equal([['foobar', true]]);
|
||||
expect(Array.from(hash.chunks[1][2]))
|
||||
.to.deep.equal([['foobar', true]]);
|
||||
expect(Array.from(hash.chunks[2][2]))
|
||||
.to.deep.equal([['foobar', true]]);
|
||||
expect(Array.from(hash.chunks[3][2]))
|
||||
.to.deep.equal([]);
|
||||
expect(Array.from(hash.chunks[3][3]))
|
||||
.to.deep.equal([]);
|
||||
expect(Array.from(hash.chunks[3][3]))
|
||||
.to.deep.equal([]);
|
||||
expect(Array.from(hash.chunks[3][3]))
|
||||
.to.deep.equal([]);
|
||||
expect(Array.from(hash.chunks[3][3]))
|
||||
.to.deep.equal([]);
|
||||
});
|
||||
|
||||
test('queries for data', async () => {
|
||||
const hash = new SpatialHash({x: 640, y: 640});
|
||||
hash.update({x0: 32, x1: 96, y0: 32, y1: 96}, 'foobar');
|
||||
expect(Array.from(hash.within({x0: 0, x1: 16, y0: 0, y1: 16})))
|
||||
.to.deep.equal([]);
|
||||
expect(Array.from(hash.within({x0: 0, x1: 48, y0: 0, y1: 48})))
|
||||
.to.deep.equal(['foobar']);
|
||||
expect(Array.from(hash.within({x0: 48, x1: 64, y0: 48, y1: 64})))
|
||||
.to.deep.equal(['foobar']);
|
||||
hash.update({x0: 32, x1: 160, y0: 32, y1: 160}, 'foobar');
|
||||
expect(Array.from(hash.within({x0: 80, x1: 90, y0: 80, y1: 90})))
|
||||
.to.deep.equal(['foobar']);
|
||||
});
|
|
@ -4,7 +4,7 @@ ecs.switchEcs(
|
|||
{
|
||||
Position: {
|
||||
x: 74,
|
||||
y: 108,
|
||||
y: 128,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
|
|
@ -1,10 +1,17 @@
|
|||
ecs.switchEcs(
|
||||
other,
|
||||
entity.Ecs.path,
|
||||
{
|
||||
Position: {
|
||||
x: 72,
|
||||
y: 304,
|
||||
},
|
||||
},
|
||||
);
|
||||
for (let i = 0; i < intersections.length; ++i) {
|
||||
if (intersections[i][0].tags) {
|
||||
if (intersections[i][0].tags.includes('door')) {
|
||||
ecs.switchEcs(
|
||||
other,
|
||||
entity.Ecs.path,
|
||||
{
|
||||
Position: {
|
||||
x: 72,
|
||||
y: 304,
|
||||
},
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -11,12 +11,14 @@ if (projected?.length > 0) {
|
|||
const plant = {
|
||||
Collider: {
|
||||
bodies: [
|
||||
[
|
||||
{x: -8, y: -8},
|
||||
{x: 7, y: -8},
|
||||
{x: -8, y: 7},
|
||||
{x: 7, y: 7},
|
||||
],
|
||||
{
|
||||
points: [
|
||||
{x: -8, y: -8},
|
||||
{x: 7, y: -8},
|
||||
{x: -8, y: 7},
|
||||
{x: 7, y: 7},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
Interactive: {
|
||||
|
|
Loading…
Reference in New Issue
Block a user