171 lines
3.4 KiB
JavaScript
171 lines
3.4 KiB
JavaScript
import {compose} from '@avocado/core';
|
|
import {StateProperty, Trait} from '@avocado/entity';
|
|
import {Vector} from '@avocado/math';
|
|
|
|
import {BodyView} from '../body-view';
|
|
|
|
const decorate = compose(
|
|
StateProperty('addedToPhysics', {
|
|
track: true,
|
|
}),
|
|
);
|
|
|
|
export default class Physical extends decorate(Trait) {
|
|
|
|
static behaviorTypes() {
|
|
return {
|
|
applyForce: {
|
|
type: 'void',
|
|
label: 'Apply force.',
|
|
args: [
|
|
['force', {
|
|
type: 'vector',
|
|
}],
|
|
],
|
|
},
|
|
applyImpulse: {
|
|
type: 'void',
|
|
label: 'Apply impulse.',
|
|
args: [
|
|
['impulse', {
|
|
type: 'vector',
|
|
}],
|
|
],
|
|
},
|
|
};
|
|
}
|
|
|
|
static defaultState() {
|
|
return {
|
|
addedToPhysics: true,
|
|
};
|
|
}
|
|
|
|
static describeState() {
|
|
return {
|
|
addedToPhysics: {
|
|
type: 'bool',
|
|
label: 'Added to physics',
|
|
},
|
|
}
|
|
}
|
|
|
|
static type() {
|
|
return 'physical';
|
|
}
|
|
|
|
constructor(entity, params, state) {
|
|
super(entity, params, state);
|
|
this._body = undefined;
|
|
this.bodyView = undefined;
|
|
this._world = undefined;
|
|
}
|
|
|
|
destroy() {
|
|
this.world = undefined;
|
|
}
|
|
|
|
addToWorld() {
|
|
const world = this._world;
|
|
if (world) {
|
|
const body = world.createBody(this.entity.shape);
|
|
world.associateBodyWithEntity(body, this.entity);
|
|
body.setCollisionForEntity(this.entity);
|
|
world.addBody(body);
|
|
this._body = body;
|
|
if (AVOCADO_CLIENT) {
|
|
if (this.entity.is('visible') && this.entity.is('debuggable')) {
|
|
this.bodyView = new BodyView(body);
|
|
this.bodyView.position = Vector.scale(this.entity.position, -1);
|
|
this.bodyView.visible = this.entity.isDebugging;
|
|
this.bodyView.zIndex = 101;
|
|
this.entity.container.addChild(this.bodyView);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
get body() {
|
|
return this._body;
|
|
}
|
|
|
|
removeFromWorld() {
|
|
if (this._world && this._body) {
|
|
this._world.removeBody(this._body);
|
|
}
|
|
this._body = undefined;
|
|
if (this.bodyView) {
|
|
if (this.entity.is('visible')) {
|
|
this.entity.container.removeChild(this.bodyView);
|
|
}
|
|
this.bodyView.destroy();
|
|
}
|
|
this.bodyView = undefined;
|
|
}
|
|
|
|
set world(world) {
|
|
this.removeFromWorld();
|
|
this._world = world;
|
|
this.addToWorld();
|
|
}
|
|
|
|
listeners() {
|
|
return {
|
|
|
|
addedToRoom: () => {
|
|
this.entity.world = this.entity.room.world;
|
|
},
|
|
|
|
addedToPhysicsChanged: () => {
|
|
if (this.entity.addedToPhysics) {
|
|
if (!this._body) {
|
|
this.addToWorld();
|
|
}
|
|
}
|
|
else {
|
|
if (this._body) {
|
|
this.removeFromWorld();
|
|
}
|
|
}
|
|
},
|
|
|
|
isDyingChanged: (_, isDying) => {
|
|
this.entity.addedToPhysics = !isDying;
|
|
},
|
|
|
|
positionChanged: () => {
|
|
if (this._body) {
|
|
const position = this.entity.position;
|
|
this._body.position = position;
|
|
}
|
|
},
|
|
|
|
removedFromRoom: (room) => {
|
|
if (this._body) {
|
|
this.removeFromWorld();
|
|
}
|
|
},
|
|
|
|
};
|
|
}
|
|
|
|
methods() {
|
|
return {
|
|
|
|
applyForce: (force) => {
|
|
if (this._world && this._body) {
|
|
this._body.applyForce(force);
|
|
}
|
|
},
|
|
|
|
applyImpulse: (impulse) => {
|
|
if (this._world && this._body) {
|
|
this._body.applyImpulse(impulse);
|
|
}
|
|
},
|
|
|
|
}
|
|
}
|
|
|
|
}
|