88 lines
2.3 KiB
JavaScript
88 lines
2.3 KiB
JavaScript
import {Body as MatterBody, Engine, Events, World as MatterWorld} from 'matter-js';
|
|
|
|
import {Vector} from '@avocado/math';
|
|
|
|
import {Body} from './body';
|
|
import {AbstractWorld} from '../abstract/world';
|
|
|
|
export class World extends AbstractWorld {
|
|
|
|
constructor() {
|
|
super();
|
|
const world = MatterWorld.create({
|
|
gravity: {
|
|
x: 0,
|
|
y: 0,
|
|
scale: 0,
|
|
},
|
|
});
|
|
this.engine = Engine.create({
|
|
world,
|
|
});
|
|
this.handleCollisions('collisionStart');
|
|
this.handleCollisions('collisionEnd');
|
|
this.elapsedRemainder = 0;
|
|
}
|
|
|
|
addBody(body) {
|
|
MatterWorld.add(this.engine.world, body.matterBody);
|
|
}
|
|
|
|
createBody(shape) {
|
|
return new Body(this, shape);
|
|
}
|
|
|
|
handleCollisions(eventName) {
|
|
Events.on(this.engine, eventName, (event) => {
|
|
event.pairs.forEach((pair) => {
|
|
const {bodyA, bodyB} = pair;
|
|
const entityA = this.entities.get(Body.lookupBody(bodyA));
|
|
const entityB = this.entities.get(Body.lookupBody(bodyB));
|
|
if (
|
|
entityA && entityA.is('collider')
|
|
&& entityB && entityB.is('collider')
|
|
) {
|
|
if (entityA.collidesWith(entityB)) {
|
|
entityA.emit(eventName, entityB);
|
|
}
|
|
if (entityB.collidesWith(entityA)) {
|
|
entityB.emit(eventName, entityA);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
}
|
|
|
|
removeBody(body) {
|
|
super.removeBody(body);
|
|
MatterWorld.remove(this.engine.world, body.matterBody);
|
|
}
|
|
|
|
tick(elapsed) {
|
|
// Update simulation.
|
|
elapsed += this.elapsedRemainder;
|
|
const stepTime = this.stepTime;
|
|
const stepTimeInMs = stepTime * 1000;
|
|
while (elapsed >= stepTime) {
|
|
// Apply impulses.
|
|
let it = this.entities.entries();
|
|
for (let value = it.next(); value.done !== true; value = it.next()) {
|
|
const body = value.value[0];
|
|
const [x, y] = Vector.scale(body.impulse, stepTime);
|
|
MatterBody.translate(body.matterBody, {x, y});
|
|
}
|
|
Engine.update(this.engine, stepTimeInMs);
|
|
elapsed -= stepTime;
|
|
}
|
|
this.elapsedRemainder = elapsed;
|
|
// Reset impulses.
|
|
const it = this.entities.entries();
|
|
for (let value = it.next(); value.done !== true; value = it.next()) {
|
|
value.value[0].impulse = [0, 0];
|
|
}
|
|
// Propagate.
|
|
super.tick(elapsed);
|
|
}
|
|
|
|
}
|