diff --git a/packages/entity/traits/mobile.js b/packages/entity/traits/mobile.js index 9bd2037..a01f46d 100644 --- a/packages/entity/traits/mobile.js +++ b/packages/entity/traits/mobile.js @@ -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( diff --git a/packages/entity/traits/physical.js b/packages/entity/traits/physical.js index e102ce6..077fd6a 100644 --- a/packages/entity/traits/physical.js +++ b/packages/entity/traits/physical.js @@ -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); } }, diff --git a/packages/physics/dummy/body.js b/packages/physics/dummy/body.js index 0c811c8..87f7a60 100644 --- a/packages/physics/dummy/body.js +++ b/packages/physics/dummy/body.js @@ -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) + ); } } diff --git a/packages/physics/dummy/world.js b/packages/physics/dummy/world.js index edfcd50..eee4c18 100644 --- a/packages/physics/dummy/world.js +++ b/packages/physics/dummy/world.js @@ -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); diff --git a/packages/physics/matter/body.js b/packages/physics/matter/body.js new file mode 100644 index 0000000..b54b231 --- /dev/null +++ b/packages/physics/matter/body.js @@ -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], + }); + } + +} diff --git a/packages/physics/matter/world.js b/packages/physics/matter/world.js new file mode 100644 index 0000000..db445f0 --- /dev/null +++ b/packages/physics/matter/world.js @@ -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); + } + +} diff --git a/packages/physics/package.json b/packages/physics/package.json index 6c3bf68..afeb805 100644 --- a/packages/physics/package.json +++ b/packages/physics/package.json @@ -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" + } }