feat: real (Matter.js) physics :)

This commit is contained in:
cha0s 2019-03-24 03:24:35 -05:00
parent ea9c116c7f
commit 7d2037d870
7 changed files with 136 additions and 9 deletions

View File

@ -50,7 +50,7 @@ class MobileBase extends Trait {
return;
}
if (this.entity.is('physical')) {
this.entity.applyImpulse(this.requestedMovement);
this.entity.applyImpulse(this.requestedMovement, elapsed);
}
else {
const requestedMovement = Vector.scale(

View File

@ -80,9 +80,9 @@ export class Physical extends decorate(Trait) {
}
},
applyImpulse: (impulse) => {
applyImpulse: (impulse, elapsed) => {
if (this._world) {
this._body.applyImpulse(impulse);
this._body.applyImpulse(impulse, elapsed);
}
},

View File

@ -31,8 +31,11 @@ export class Body extends decorate(AbstractBody) {
this.force = Vector.add(this.force, vector);
}
applyImpulse(vector) {
this.impulse = Vector.add(this.impulse, vector);
applyImpulse(vector, elapsed) {
this.impulse = Vector.add(
this.impulse,
Vector.scale(vector, elapsed)
);
}
}

View File

@ -76,7 +76,7 @@ export class World extends AbstractWorld {
for (const entity of this.entities.values()) {
const body = entity.body;
const translation = Vector.add(
Vector.scale(body.impulse, elapsed),
body.impulse,
body.force,
);
body.position = Vector.add(body.position, translation);
@ -155,7 +155,7 @@ export class World extends AbstractWorld {
const contacts = body.contacts;
if (contacts.size > 0) {
const translation = Vector.add(
Vector.scale(body.impulse, elapsed),
body.impulse,
body.force,
);
body.position = Vector.sub(body.position, translation);

View File

@ -0,0 +1,74 @@
import {Composite, Bodies, Body as MatterBody} from 'matter-js';
import {Vector} from '@avocado/math';
import {ShapeList, PolygonShape, RectangleShape} from '@avocado/physics';
import {AbstractBody} from '../abstract/body';
import { Rectangle } from '../../math';
export class Body extends AbstractBody {
constructor(shape) {
super(shape);
this.matterBody = this.constructor.bodyFromShape(shape);
}
applyForce(force) {
MatterBody.applyForce(
this.matterBody,
this.matterBody.position,
{
x: force[0],
y: force[1],
}
);
}
applyImpulse(impulse, elapsed) {
impulse = Vector.scale(impulse, elapsed);
MatterBody.translate(this.matterBody, {
x: impulse[0],
y: impulse[1],
});
}
static bodyFromShape(shape) {
if (shape instanceof RectangleShape) {
return Bodies.rectangle(
shape.x,
shape.y,
shape.width,
shape.height,
);
}
else if (shape instanceof PolygonShape) {
const vectors = [];
for (const vertice of shape) {
vectors.push({
x: vertice[0],
y: vertice[1],
});
}
return Bodies.fromVertices(
shape.x,
shape.y,
vectors,
);
}
}
get position() {
return [
this.matterBody.position.x,
this.matterBody.position.y,
];
}
set position(position) {
MatterBody.setPosition(this.matterBody, {
x: position[0],
y: position[1],
});
}
}

View File

@ -0,0 +1,47 @@
import {Engine, World as MatterWorld} from 'matter-js';
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.lastElapsed = undefined;
}
addBody(body) {
MatterWorld.add(this.engine.world, body.matterBody);
}
createBody(shape) {
return new Body(shape);
}
removeBody(body) {
super.removeBody(body);
MatterWorld.remove(this.engine.world, body);
}
tick(elapsed) {
// Milliseconds.
elapsed = elapsed * 1000;
const correction = this.lastElapsed ? elapsed / this.lastElapsed : 1;
// Update simulation.
Engine.update(this.engine, elapsed, correction)
this.lastElapsed = elapsed;
// Propagate.
super.tick(elapsed);
}
}

View File

@ -1,7 +1,10 @@
{
"name": "@avocado/physics",
"version": "1.0.0",
"version": "1.0.1",
"main": "index.js",
"author": "cha0s",
"license": "MIT"
"license": "MIT",
"dependencies": {
"matter-js": "0.14.2"
}
}