162 lines
3.5 KiB
JavaScript
162 lines
3.5 KiB
JavaScript
import {Composite, Bodies, Body as MatterBody, Vertices} from 'matter-js';
|
|
|
|
import {Vector} from '@avocado/math';
|
|
import {ShapeList, PolygonShape, RectangleShape} from '@avocado/physics';
|
|
|
|
import {AbstractBody} from '../abstract/body';
|
|
|
|
export class Body extends AbstractBody {
|
|
|
|
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];
|
|
}
|
|
|
|
static lookupBody(matterBody) {
|
|
if (this.bodies) {
|
|
return this.bodies.get(matterBody);
|
|
}
|
|
}
|
|
|
|
static associateBody(matterBody, avocadoBody) {
|
|
if (!this.bodies) {
|
|
this.bodies = new Map();
|
|
}
|
|
this.bodies.set(matterBody, avocadoBody);
|
|
}
|
|
|
|
constructor(shape) {
|
|
super(shape);
|
|
[this.origin, this.matterBody] = this.constructor.bodyFromShape(shape);
|
|
this.constructor.associateBody(this.matterBody, this);
|
|
}
|
|
|
|
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,
|
|
];
|
|
}
|
|
|
|
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) {
|
|
const body = Bodies.rectangle(
|
|
0,
|
|
0,
|
|
shape.width,
|
|
shape.height,
|
|
);
|
|
return [shape.position, body];
|
|
}
|
|
else if (shape instanceof PolygonShape) {
|
|
const vectors = [];
|
|
for (const vertice of shape) {
|
|
vectors.push({
|
|
x: vertice[0],
|
|
y: vertice[1],
|
|
});
|
|
}
|
|
const centre = Vertices.centre(vectors);
|
|
const body = Bodies.fromVertices(
|
|
0,
|
|
0,
|
|
vectors,
|
|
);
|
|
const origin = Vector.add(
|
|
shape.position,
|
|
Vector.scale([centre.x, centre.y], 1),
|
|
);
|
|
return [origin, body];
|
|
}
|
|
}
|
|
|
|
get position() {
|
|
return [
|
|
this.matterBody.position.x,
|
|
this.matterBody.position.y,
|
|
];
|
|
}
|
|
|
|
set position(position) {
|
|
position = Vector.add(position, this.origin);
|
|
if (Vector.equalsClose(this.position, position)) {
|
|
return;
|
|
}
|
|
MatterBody.setPosition(this.matterBody, {
|
|
x: position[0],
|
|
y: position[1],
|
|
});
|
|
}
|
|
|
|
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);
|
|
}
|
|
else {
|
|
this.setCollision(0, 0, -1);
|
|
}
|
|
}
|
|
|
|
get static() {
|
|
return this.matterBody.isStatic;
|
|
}
|
|
|
|
set static(isStatic) {
|
|
MatterBody.setStatic(this.matterBody, isStatic);
|
|
}
|
|
|
|
get vertices() {
|
|
const vertices = [];
|
|
for (const {x, y} of this.matterBody.vertices) {
|
|
vertices.push([x, y]);
|
|
}
|
|
return vertices;
|
|
}
|
|
|
|
}
|