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 class Physical extends decorate(Trait) { static defaultState() { return { addedToPhysics: true, }; } initialize() { 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 (this.entity.container) { this.bodyView = new BodyView(body); this.bodyView.position = Vector.scale(this.entity.position, -1); 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(); } } }, positionChanged: () => { if (this._body) { const position = this.entity.position; this._body.position = position; } }, }; } methods() { return { applyForce: (force) => { if (this._world) { this._body.applyForce(force); } }, applyImpulse: (impulse, elapsed) => { if (this._world) { this._body.applyImpulse(impulse, elapsed); } }, } } }