avocado-old/packages/physics/matter/body.js

179 lines
4.9 KiB
JavaScript
Raw Permalink Normal View History

2019-04-13 03:17:58 -05:00
import {Composite, Bodies, Body as MatterBody, Bounds, Vertices} from 'matter-js';
2019-03-24 03:24:35 -05:00
import {Vector} from '@avocado/math';
2019-04-12 23:51:40 -05:00
import {
ShapeList,
CircleShape,
PolygonShape,
RectangleShape,
} from '@avocado/physics';
2019-03-24 03:24:35 -05:00
import {AbstractBody} from '../abstract/body';
2019-04-13 03:17:58 -05:00
// Trick matter into not needing decomp for our convex polygons.
const g = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : undefined;
if (g) {
g.decomp = require('poly-decomp');
}
2019-04-13 16:35:23 -05:00
// Translate "real" coordinates to physics coordinates.
2019-04-13 03:17:58 -05:00
const SCALE = 1;
2019-03-24 03:24:35 -05:00
export class Body extends AbstractBody {
2019-04-08 15:20:28 -05:00
static collisionCategory(group) {
if (!('filterCategoryBit' in this)) {
this.filterCategoryBit = 0;
}
if (!('filterCategories' in this)) {
this.filterCategories = {};
}
if (!this.filterCategories[group]) {
this.filterCategories[group] = 1 << this.filterCategoryBit;
this.filterCategoryBit += 1;
}
return this.filterCategories[group];
}
2019-03-27 18:38:12 -05:00
static lookupBody(matterBody) {
if (this.bodies) {
return this.bodies.get(matterBody);
}
}
static associateBody(matterBody, avocadoBody) {
if (!this.bodies) {
2019-04-30 18:21:06 -05:00
this.bodies = new WeakMap();
2019-03-27 18:38:12 -05:00
}
this.bodies.set(matterBody, avocadoBody);
}
2019-05-04 13:31:16 -05:00
constructor(world, shape) {
super(world, shape);
2019-04-13 12:46:26 -05:00
const [body, position, origin] = this.constructor.bodyFromShape(shape);
2019-04-13 16:35:23 -05:00
// Set body first, then origin, then position. Order important.
2019-04-13 12:46:26 -05:00
this.matterBody = body;
this.origin = origin;
2019-04-13 16:35:23 -05:00
this.position = Vector.scale(position, SCALE);
2019-03-27 18:38:12 -05:00
this.constructor.associateBody(this.matterBody, this);
2019-03-24 03:24:35 -05:00
}
2019-03-24 18:58:26 -05:00
get aabb() {
const bounds = this.matterBody.bounds;
return [
bounds.min.x,
bounds.min.y,
bounds.max.x - bounds.min.x,
bounds.max.y - bounds.min.y,
2019-04-13 03:17:58 -05:00
].map((p) => p * SCALE);
2019-03-24 18:58:26 -05:00
}
2019-03-24 03:24:35 -05:00
applyForce(force) {
2019-04-13 03:17:58 -05:00
force = Vector.scale(force, 1 / SCALE);
const [x, y] = force;
MatterBody.applyForce(this.matterBody, this.matterBody.position, {x, y});
2019-03-24 03:24:35 -05:00
}
2019-05-04 13:31:16 -05:00
applyImpulse(impulse) {
2020-04-19 21:02:11 -05:00
this.impulse = Vector.add(this.impulse, Vector.scale(impulse, 1 / SCALE));
2019-03-24 03:24:35 -05:00
}
static bodyFromShape(shape) {
2019-04-13 03:17:58 -05:00
const shapePosition = Vector.scale(shape.position, 1 / SCALE);
if (shape instanceof ShapeList) {
const children = [];
for (const child of shape) {
const [body, position, origin] = this.bodyFromShape(child);
2019-04-13 16:35:23 -05:00
const [x, y] = Vector.add(position, origin);
2019-04-13 03:17:58 -05:00
MatterBody.setPosition(body, {x, y});
children.push(body);
}
2019-04-13 13:37:44 -05:00
let body = MatterBody.create({parts: children});
// Convex hull?
if (true) {
const {vertices} = body;
body = Bodies.fromVertices(0, 0, vertices);
MatterBody.setPosition(body, Vertices.centre(vertices));
}
2019-04-13 03:17:58 -05:00
const {x, y} = body.position;
2019-04-13 16:35:23 -05:00
return [body, shapePosition, [x, y]];
2019-04-13 03:17:58 -05:00
}
else if (shape instanceof RectangleShape) {
const [width, height] = Vector.scale(shape.size, 1 / SCALE);
const body = Bodies.rectangle(0, 0, width, height);
return [body, shapePosition, [0, 0]];
2019-03-24 03:24:35 -05:00
}
2019-04-12 23:51:40 -05:00
else if (shape instanceof CircleShape) {
2019-04-13 03:17:58 -05:00
const body = Bodies.circle(0, 0, shape.radius / SCALE);
return [body, shapePosition, [0, 0]];
2019-04-12 23:51:40 -05:00
}
2019-03-24 03:24:35 -05:00
else if (shape instanceof PolygonShape) {
const vectors = [];
2019-04-13 03:17:58 -05:00
for (let vertice of shape) {
const[x, y] = Vector.scale(vertice, 1 / SCALE)
vectors.push({x, y});
2019-03-24 03:24:35 -05:00
}
2019-04-13 03:17:58 -05:00
const {x, y} = Vertices.centre(vectors);
const body = Bodies.fromVertices(0, 0, vectors);
return [body, shapePosition, [x, y]];
2019-03-24 03:24:35 -05:00
}
}
get position() {
2019-04-13 03:17:58 -05:00
const {x, y} = this.matterBody.position;
2019-04-13 12:46:36 -05:00
return Vector.sub(Vector.scale([x, y], SCALE), this.origin);
2019-03-24 03:24:35 -05:00
}
set position(position) {
2019-04-13 03:17:58 -05:00
position = Vector.scale(position, 1 / SCALE);
position = Vector.add(position, this.origin);
if (Vector.equalsClose(this.position, position)) {
return;
}
2019-04-13 03:17:58 -05:00
const [x, y] = position;
MatterBody.setPosition(this.matterBody, {x, y});
2019-03-24 03:24:35 -05:00
}
2019-04-08 15:20:28 -05:00
setCollision(category, mask, group = 0) {
MatterBody.set(this.matterBody, 'collisionFilter', {
category,
group,
mask,
});
}
setCollisionForEntity(entity) {
if (entity.is('collider')) {
const ctor = this.constructor;
const category = ctor.collisionCategory(entity.collisionGroup);
let mask = 0;
for (const group of entity.collidesWithGroups) {
mask = mask | ctor.collisionCategory(group);
}
this.setCollision(category, mask);
2019-04-19 02:52:39 -05:00
if (entity.isSensor) {
MatterBody.set(this.matterBody, 'isSensor', true);
}
2019-04-08 15:20:28 -05:00
}
else {
this.setCollision(0, 0, -1);
}
}
2019-03-27 23:21:13 -05:00
get static() {
return this.matterBody.isStatic;
}
set static(isStatic) {
MatterBody.setStatic(this.matterBody, isStatic);
}
2019-04-12 20:25:40 -05:00
get vertices() {
const vertices = [];
for (const {x, y} of this.matterBody.vertices) {
2019-04-13 03:17:58 -05:00
vertices.push(Vector.scale([x, y], SCALE));
2019-04-12 20:25:40 -05:00
}
return vertices;
}
2019-03-24 03:24:35 -05:00
}