components/LogicPushable.js

/**
## JSON Definition
    {
      "type": "LogicPushable",
       "xPush" : .01,
      //Optional - The distance per millisecond this object can be pushed in x. Defaults to .01.
      "yPush" : .01,
      //Optional - The distance per millisecond this object can be pushed in y. Defaults to .01.
      "push" : .01
      //Optional - The distance per millisecond this object can be pushed in x and y. Overwritten by the more specific values xPush and yPush. Defaults to .01.
    }
*/
import {arrayCache} from '../utils/array.js';
import createComponentClass from '../factory.js';

const
    setMagnitude = function (direction, magnitude) {
        return (direction / Math.abs(direction)) * magnitude;
    };

export default createComponentClass(/** @lends platypus.components.LogicPushable.prototype */{
    id: 'LogicPushable',

    /**
     * A component that enables an entity to be pushed.
     *
     * @memberof platypus.components
     * @uses platypus.Component
     * @constructs
     * @param {*} definition 
     * @listens platypus.Entity#handle-logic
     * @listens platypus.Entity#hit-solid
     */
    initialize: function (definition) {
        this.yPush = definition.push || definition.yPush || 0;
        this.xPush = definition.push || definition.xPush || 0.1;
        if (definition.roll) {
            this.radius = definition.radius || this.owner.radius || ((this.owner.width || this.owner.height || 2) / 2);
            this.owner.orientation = this.owner.orientation || 0;
        } else {
            this.radius = 0;
        }
        this.currentPushX = 0;
        this.currentPushY = 0;
        this.lastX = this.owner.x;
        this.lastY = this.owner.y;
        this.pushers = arrayCache.setUp();
    },

    events: {
        "handle-logic": function ({delta}) {
            if (this.currentPushY) {
                this.owner.y += setMagnitude(this.currentPushY, this.yPush * delta);
                this.currentPushY = 0;
            }
            if (this.currentPushX) {
                this.owner.x += setMagnitude(this.currentPushX, this.xPush * delta);
                this.currentPushX = 0;
            }
            if ((this.lastX !== this.owner.x) || (this.lastY !== this.owner.y)) {
                if (this.radius) {
                    this.owner.orientation += (this.owner.x + this.owner.y - this.lastX - this.lastY) / this.radius;
                }
                this.lastX = this.owner.x;
                this.lastY = this.owner.y;
            }
            for (let i = 0; i < this.pushers.length; i++) {
                this.pushers[i].triggerEvent('pushed', this.owner);
            }
            this.pushers.length = 0;
        },
        "push-entity": function (collisionInfo) {
            const
                x = (collisionInfo.x || 0),
                y = (collisionInfo.y || 0);
            
            this.currentPushX -= x;
            this.currentPushY -= y;
            if ((this.yPush && y) || (this.xPush && x)) {
                this.pushers.push(collisionInfo.entity);
            }
        },
        "hit-solid": function (collisionInfo) {
            if (((collisionInfo.y > 0) && (this.vY > 0)) || ((collisionInfo.y < 0) && (this.vY < 0))) {
                this.vY = 0;
            } else if (((collisionInfo.x < 0) && (this.vX < 0)) || ((collisionInfo.x > 0) && (this.vX > 0))) {
                this.vX = 0;
            }
            return true;
        }
    },
    
    methods: {
        destroy: function () {
            arrayCache.recycle(this.pushers);
        }
    }
});