Home Reference Source

main/service/PhysicsService.js

import { Body } from 'model/component/Body';
import { PhysicsEvent } from 'model/core/PhysicsEvent';
import { Vector2 } from 'commons/math/Vector2';
import { Box2D } from 'link/Box2D';
import { Logger } from 'commons/Logger';

export class PhysicsService {

    static get LISTENER() {
        return {
            BEGIN_CONTACT: 1, // 0001
            END_CONTACT: 2, // 0010
            BEGIN_END_CONTACT: 3, // 0011
            PRE_SOLVE: 4, // 0100
            POST_SOLVE: 8, // 1000
            ALL_LISTENERS: 15 //1111
        }
    }

    constructor(gravity, allowSleep, listeners) {
        this._logger = new Logger(PhysicsService.name);

        this.velocityIterations = 10;
        this.positionIterations = 10;
        this.clearForcesOnUpdate = false;
        this.listeners = listeners;

        this._events = new Array();
        this._world = new Box2D.b2World(new Box2D.b2Vec2(gravity.x, gravity.y), allowSleep);

        var listener = new Box2D.JSContactListener();

        listener.BeginContact = (this.listeners & PhysicsService.LISTENER.BEGIN_CONTACT) ?
            (contact) => this._events.push(new PhysicsEvent("BeginContact", contact)) : () => { };
        listener.EndContact = (this.listeners & PhysicsService.LISTENER.END_CONTACT) ?
            (contact) => this._events.push(new PhysicsEvent("EndContact", contact)) : () => { };
        listener.PreSolve = (this.listeners & PhysicsService.LISTENER.PRE_SOLVE) ?
            (contact, manifold) => this._events.push(new PhysicsEvent("PreSolve", contact, { manifold: manifold })) : () => { };
        listener.PostSolve = (this.listeners & PhysicsService.LISTENER.POST_SOLVE) ?
            (contact, impulse) => this._events.push(new PhysicsEvent("PostSolve", contact, { impulse: impulse })) : () => { };

        this._world.SetContactListener(listener);

        this._logger.debug("physics world ready with listeners", listener);
    }

    get events() {
        return this._events.splice(0);
    }

    destroy(body) {
        return this._world.DestroyBody(body.bodyDef);
    }

    update(body, go) {
        if (body.state === Body.STATE.REGISTERED) {
            go.position.x = body.position.x;
            go.position.y = body.position.y;

        } else if (body.state === Body.STATE.CREATED) {
            body.materialDef.set_userData(go.uid);
            body.position = Vector2(go.position.x, go.position.y);
            body.body = this._world.CreateBody(body.bodyDef);
            body.body.CreateFixture(body.materialDef);
            body.state = Body.STATE.REGISTERED;
        }
    }

    simulate(fps) {
        this._world.Step(1 / fps, this.velocityIterations, this.positionIterations);
        if (this.clearForcesOnUpdate) {
            this._world.ClearForces();
        }
    }

}