API Documentation for: 0.11.10
Show:

File:src\components\CollisionBasic.js

                        /**
                         * This component causes this entity to collide with other entities. It must be part of a collision group and will receive messages when colliding with other entities in the collision group.
                         *
                         * Multiple collision components may be added to a single entity if distinct messages should be triggered for certain collision areas on the entity or if the soft collision area is a different shape from the solid collision area. Be aware that too many additional collision areas may adversely affect performance.
                         *
                         * @namespace platypus.components
                         * @class CollisionBasic
                         * @uses platypus.Component
                         */
                        /* global include, platypus */
                        (function () {
                            'use strict';
                            
                            var AABB = include('platypus.AABB'),
                                CollisionShape = include('platypus.CollisionShape'),
                                Data = include('platypus.Data'),
                                DataMap = include('platypus.DataMap'),
                                Vector = include('platypus.Vector'),
                        
                                /**
                                 * On receiving a 'hit-by' message, custom messages are triggered on the entity corresponding with the component's `solidCollisions` and `softCollisions` key/value mappings.
                                 *
                                 * @event *
                                 * @param collision {Object} A list of key/value pairs describing the collision.
                                 */
                                entityBroadcast = (function () {
                                    var stringBroadcast = function (event, collisionType, solidOrSoft, value) {
                                            if (value.myType === collisionType) {
                                                if (value.hitType === solidOrSoft) {
                                                    this.owner.triggerEvent(event, value);
                                                }
                                            }
                                        },
                                        arrayBroadcast = function (event, collisionType, solidOrSoft, value) {
                                            var i = 0;
                                            
                                            if (value.myType === collisionType) {
                                                if (value.hitType === solidOrSoft) {
                                                    for (i = 0; i < event.length; i++) {
                                                        this.owner.triggerEvent(event[i], value);
                                                    }
                                                }
                                            }
                                        },
                                        directionalBroadcast = function (event, collisionType, solidOrSoft, collisionInfo) {
                                            var dx = collisionInfo.x,
                                                dy = collisionInfo.y;
                        
                                            if (collisionInfo.entity && !(dx || dy)) {
                                                dx = collisionInfo.entity.x - this.owner.x;
                                                dy = collisionInfo.entity.y - this.owner.y;
                                            }
                        
                                            if (collisionInfo.myType === collisionType) {
                                                if (collisionInfo.hitType === solidOrSoft) {
                                                    if ((dy > 0) && event.bottom) {
                                                        this.owner.trigger(event.bottom, collisionInfo);
                                                    } else if ((dy < 0) && event.top) {
                                                        this.owner.trigger(event.top, collisionInfo);
                                                    }
                                                    if ((dx > 0) && event.right) {
                                                        this.owner.trigger(event.right, collisionInfo);
                                                    } else if ((dx < 0) && event.left) {
                                                        this.owner.trigger(event.left, collisionInfo);
                                                    }
                                                    if (event.all) {
                                                        this.owner.trigger(event.all, collisionInfo);
                                                    }
                                                }
                                            }
                                        };
                                    
                                    return function (self, event, solidOrSoft) {
                                        if (typeof event === 'string') {
                                            return stringBroadcast.bind(self, event, self.collisionType, solidOrSoft);
                                        } else if (Array.isArray(event)) {
                                            return arrayBroadcast.bind(self, event, self.collisionType, solidOrSoft);
                                        } else {
                                            return directionalBroadcast.bind(self, event, self.collisionType, solidOrSoft);
                                        }
                                    };
                                }()),
                                setupCollisionFunctions = (function () {
                                    var entityGetAABB = function (aabb, colFuncs, collisionType) {
                                            var keys = colFuncs.keys,
                                                i = keys.length,
                                                funcs = null;
                        
                                            if (!collisionType) {
                                                aabb.reset();
                                                while (i--) {
                                                    aabb.include(colFuncs.get(keys[i]).getAABB());
                                                }
                                                return aabb;
                                            } else {
                                                funcs = colFuncs.get(collisionType);
                                                if (funcs) {
                                                    return funcs.getAABB();
                                                } else {
                                                    return null;
                                                }
                                            }
                                        },
                                        entityGetPreviousAABB = function (colFuncs, collisionType) {
                                            var colFunc = colFuncs.get(collisionType);
                                            
                                            if (colFunc) {
                                                return colFunc.getPreviousAABB();
                                            } else {
                                                return null;
                                            }
                                        },
                                        entityGetShapes = function (colFuncs, collisionType) {
                                            var colFunc = colFuncs.get(collisionType);
                                            
                                            if (colFunc) {
                                                return colFunc.getShapes();
                                            } else {
                                                return null;
                                            }
                                        },
                                        entityGetPrevShapes = function (colFuncs, collisionType) {
                                            var colFunc = colFuncs.get(collisionType);
                                            
                                            if (colFunc) {
                                                return colFunc.getPrevShapes();
                                            } else {
                                                return null;
                                            }
                                        },
                                        entityPrepareCollision = function (colFuncs, x, y) {
                                            var keys = colFuncs.keys,
                                                i = keys.length;
                                            
                                            while (i--) {
                                                colFuncs.get(keys[i]).prepareCollision(x, y);
                                            }
                                        },
                                        entityRelocateEntity = (function () {
                                            var handleStuck = function (position, data, owner) {
                                                    var m = 0,
                                                        s = data.stuck;
                        
                                                    if (s) {
                                                        m = position.magnitude();
                                                        if (data.thatShape.owner && (Math.abs(s) > 1)) {
                                                            s *= 0.05;
                                                        }
                                                        if (!m || (m > Math.abs(s))) {
                                                            if (data.vector.x) {
                                                                position.x = s;
                                                                position.y = 0;
                                                            }
                                                            if (data.vector.y) {
                                                                position.x = 0;
                                                                position.y = s;
                                                            }
                                                            if (owner.stuckWith) {
                                                                owner.stuckWith.recycle();
                                                            }
                                                            owner.stuckWith = Vector.setUp(data.thatShape.x, data.thatShape.y);
                                                        }
                                                    }
                                                },
                                                message = {
                                                    position: null,
                                                    unstick: null
                                                };
                                            
                                            return function (vector, collisionData) {
                                                var colX = collisionData.xData[0],
                                                    colY = collisionData.yData[0],
                                                    msg = message,
                                                    v = null;
                        
                                                if (colX) {
                                                    v = Vector.setUp(0, 0, 0);
                                                    handleStuck(v, colX, this);
                                                }
                        
                                                if (colY) {
                                                    v = v || Vector.setUp(0, 0, 0);
                                                    handleStuck(v, colY, this);
                                                }
                        
                                                msg.position = vector;
                                                msg.unstick = v;
                                                this.triggerEvent('relocate-entity', msg);
                                                
                                                if (v) {
                                                    v.recycle();
                                                }
                                            };
                                        }()),
                                        entityMovePreviousX = function (colFuncs, x) {
                                            var keys = colFuncs.keys,
                                                i = keys.length;
                                            
                                            while (i--) {
                                                colFuncs.get(keys[i]).movePreviousX(x);
                                            }
                                        },
                                        entityGetCollisionTypes = function () {
                                            return this.collisionTypes;
                                        },
                                        entityGetSolidCollisions = function () {
                                            return this.solidCollisionMap;
                                        },
                                        getAABB = function () {
                                            return this.getAABB();
                                        },
                                        getPreviousAABB = function () {
                                            return this.getPreviousAABB();
                                        },
                                        getShapes = function () {
                                            return this.getShapes();
                                        },
                                        getPrevShapes = function () {
                                            return this.getPrevShapes();
                                        },
                                        prepareCollision = function (x, y) {
                                            this.prepareCollision(x, y);
                                        },
                                        movePreviousX = function (x) {
                                            this.movePreviousX(x);
                                        };
                                    
                                    return function (self, entity) {
                                        var colFuncs = entity.collisionFunctions;
                                        
                                        // This allows the same component type to be added multiple times.
                                        if (!colFuncs) {
                                            colFuncs = entity.collisionFunctions = DataMap.setUp();
                                            entity.aabb = AABB.setUp();
                                            entity.getAABB = entityGetAABB.bind(entity, entity.aabb, colFuncs);
                                            entity.getPreviousAABB = entityGetPreviousAABB.bind(entity, colFuncs);
                                            entity.getShapes = entityGetShapes.bind(entity, colFuncs);
                                            entity.getPrevShapes = entityGetPrevShapes.bind(entity, colFuncs);
                                            entity.prepareCollision = entityPrepareCollision.bind(entity, colFuncs);
                                            entity.relocateEntity = entityRelocateEntity.bind(entity);
                                            entity.movePreviousX = entityMovePreviousX.bind(entity, colFuncs);
                                            entity.getCollisionTypes = entityGetCollisionTypes.bind(entity);
                                            entity.getSolidCollisions = entityGetSolidCollisions.bind(entity);
                                        }
                        
                                        colFuncs.set(self.collisionType, Data.setUp(
                                            "getAABB", getAABB.bind(self),
                                            "getPreviousAABB", getPreviousAABB.bind(self),
                                            "getShapes", getShapes.bind(self),
                                            "getPrevShapes", getPrevShapes.bind(self),
                                            "prepareCollision", prepareCollision.bind(self),
                                            "movePreviousX", movePreviousX.bind(self)
                                        ));
                                    };
                                }());
                        
                            return platypus.createComponentClass({
                                
                                id: 'CollisionBasic',
                        
                                properties: {
                                    /**
                                     * Defines how this entity should be recognized by other colliding entities.
                                     *
                                     * @property collisionType
                                     * @type String
                                     * @default "none"
                                     */
                                    collisionType: "none",
                        
                                    /**
                                     * Defines the type of colliding shape.
                                     *
                                     * @property shapeType
                                     * @type String
                                     * @default "rectangle"
                                     */
                                    shapeType: "rectangle",
                                    
                                    /**
                                     * Determines whether the collision area should transform on orientation changes.
                                     *
                                     * @property ignoreOrientation
                                     * @type boolean
                                     * @default false
                                     */
                                    ignoreOrientation: false,
                                    
                                    /**
                                     * Determines the x-axis center of the collision shape.
                                     *
                                     * @property regX
                                     * @type number
                                     * @default width / 2
                                     */
                                    regX: null,
                                    
                                    /**
                                     * Determines the y-axis center of the collision shape.
                                     *
                                     * @property regY
                                     * @type number
                                     * @default height / 2
                                     */
                                    regY: null,
                                    
                                    /**
                                     * Sets the width of the collision area in world coordinates.
                                     *
                                     * @property width
                                     * @type number
                                     * @default 0
                                     */
                                    width: 0,
                                    
                                    /**
                                     * Sets the height of the collision area in world coordinates.
                                     *
                                     * @property height
                                     * @type number
                                     * @default 0
                                     */
                                    height: 0,
                                    
                                    /**
                                     * Sets the radius of a circle collision area in world coordinates.
                                     *
                                     * @property radius
                                     * @type number
                                     * @default 0
                                     */
                                    radius: 0,
                                    
                                    /**
                                     * Determines which collision types this entity should consider soft, meaning this entity may pass through them, but triggers collision messages on doing so. Example:
                                     *
                                     *     {
                                     *         "water": "soaked",       // This triggers a "soaked" message on the entity when it passes over a "water" collision-type entity.
                                     *         "lava": ["burn", "ouch"] // This triggers both messages on the entity when it passes over a "lava" collision-type entity.
                                     *     }
                                     *
                                     * @property softCollisions
                                     * @type Object
                                     * @default null
                                     */
                                    softCollisions: null,
                                    
                                    /**
                                     * Determines which collision types this entity should consider solid, meaning this entity should not pass through them. Example:
                                     *
                                     *     {
                                     *         "boulder": "",                       // This specifies that this entity should not pass through other "boulder" collision-type entities.
                                     *         "diamond": "crack-up",               // This specifies that this entity should not pass through "diamond" collision-type entities, but if it touches one, it triggers a "crack-up" message on the entity.
                                     *         "marble": ["flip", "dance", "crawl"] // This specifies that this entity should not pass through "marble" collision-type entities, but if it touches one, it triggers all three specified messages on the entity.
                                     *     }
                                     *
                                     * @property solidCollisions
                                     * @type Object
                                     * @default null
                                     */
                                    solidCollisions: null,
                                    
                                    /**
                                     * This is the margin around the entity's width and height. This is an alternative method for specifying the collision shape in terms of the size of the entity. Can also pass in an object specifying the following parameters if the margins vary per side: top, bottom, left, and right.
                                     *
                                     * @property margin
                                     * @type number|Object
                                     * @default 0
                                     */
                                    margin: 0,
                                    
                                    /**
                                     * Defines one or more shapes to create the collision area. Defaults to a single shape with the width, height, regX, and regY properties of the entity if not specified. See [CollisionShape](CollisionShape.html) for the full list of properties.
                                     *
                                     * @property shapes
                                     * @type Array
                                     * @default null
                                     */
                                    shapes: null
                                },
                                
                                publicProperties: {
                                    /**
                                     * This property should be set to true if entity doesn't move for better optimization. This causes other entities to check against this entity, but this entity performs no checks of its own. Available on the entity as `entity.immobile`.
                                     *
                                     * @property immobile
                                     * @type boolean
                                     * @default false
                                     */
                                    immobile: false,
                        
                                    /**
                                     * Whether this entity should be tested across its entire movement path. This is necessary for fast-moving entities, but shouldn't be used for others due to the processing overhead. Available on the entity as `entity.bullet`.
                                     *
                                     * @property bullet
                                     * @type boolean
                                     * @default false
                                     */
                                    bullet: false,
                                    
                                    /**
                                     * Whether the entity is only solid when being collided with from the top.
                                     *
                                     * @property jumpThrough
                                     * @type boolean
                                     * @default: false
                                     */
                                    jumpThrough: false
                                },
                                
                                initialize: function (definition) {
                                    var arr = null,
                                        x            = 0,
                                        key          = '',
                                        shapes       = null,
                                        regX         = this.regX,
                                        regY         = this.regY,
                                        width        = this.width,
                                        height       = this.height,
                                        radius       = this.radius,
                                        marginLeft   = 0,
                                        marginRight  = 0,
                                        marginTop    = 0,
                                        marginBottom = 0;
                        
                                    if (typeof this.margin === "number") {
                                        marginLeft   = this.margin;
                                        marginRight  = this.margin;
                                        marginTop    = this.margin;
                                        marginBottom = this.margin;
                                    } else {
                                        marginLeft   = this.margin.left || 0;
                                        marginRight  = this.margin.right || 0;
                                        marginTop    = this.margin.top || 0;
                                        marginBottom = this.margin.bottom || 0;
                                    }
                                    
                                    if (regX === null) {
                                        regX = this.regX = width / 2;
                                    }
                                    
                                    if (regY === null) {
                                        regY = this.regY = height / 2;
                                    }
                                    
                                    Vector.assign(this.owner, 'position', 'x', 'y', 'z');
                                    Vector.assign(this.owner, 'previousPosition', 'previousX', 'previousY', 'previousZ');
                                    this.owner.previousX = this.owner.previousX || this.owner.x;
                                    this.owner.previousY = this.owner.previousY || this.owner.y;
                                    
                                    this.aabb     = AABB.setUp();
                                    this.prevAABB = AABB.setUp();
                                    
                                    if (this.shapes) {
                                        shapes = this.shapes;
                                    } else if (this.shapeType === 'circle') {
                                        radius = radius || (((width || 0) + (height || 0)) / 4);
                                        shapes = [{
                                            regX: (isNaN(regX) ? radius : regX) - (marginRight - marginLeft) / 2,
                                            regY: (isNaN(regY) ? radius : regY) - (marginBottom - marginTop) / 2,
                                            radius: radius,
                                            type: this.shapeType
                                        }];
                                    } else {
                                        shapes = [{
                                            //regX: (isNaN(regX) ? (width  || 0) / 2 : regX) - (marginRight  - marginLeft) / 2,
                                            //regY: (isNaN(regY) ? (height || 0) / 2 : regY) - (marginBottom - marginTop)  / 2,
                                            regX: (isNaN(regX) ? (width  || 0) / 2 : regX) + marginLeft,
                                            regY: (isNaN(regY) ? (height || 0) / 2 : regY) + marginTop,
                                            points: definition.points,
                                            width: (width  || 0) + marginLeft + marginRight,
                                            height: (height || 0) + marginTop  + marginBottom,
                                            type: this.shapeType
                                        }];
                                    }
                                    
                                    this.owner.collisionTypes = this.owner.collisionTypes || Array.setUp();
                                    this.owner.collisionTypes.push(this.collisionType);
                                    
                                    this.shapes = Array.setUp();
                                    this.prevShapes = Array.setUp();
                                    this.entities = null;
                                    for (x = 0; x < shapes.length; x++) {
                                        this.shapes.push(CollisionShape.setUp(this.owner, shapes[x], this.collisionType));
                                        this.prevShapes.push(CollisionShape.setUp(this.owner, shapes[x], this.collisionType));
                                        this.prevAABB.include(this.prevShapes[x].aABB);
                                        this.aabb.include(this.shapes[x].aABB);
                                    }
                                    
                                    setupCollisionFunctions(this, this.owner);
                                    
                                    this.owner.solidCollisionMap = this.owner.solidCollisionMap || DataMap.setUp();
                                    arr = this.owner.solidCollisionMap.set(this.collisionType, Array.setUp());
                                    if (this.solidCollisions) {
                                        for (key in this.solidCollisions) {
                                            if (this.solidCollisions.hasOwnProperty(key)) {
                                                arr.push(key);
                                                if (this.solidCollisions[key]) { // To make sure it's not an empty string.
                                                    this.addEventListener('hit-by-' + key, entityBroadcast(this, this.solidCollisions[key], 'solid'));
                                                }
                                            }
                                        }
                                    }
                            
                                    this.owner.softCollisionMap = this.owner.softCollisionMap || DataMap.setUp();
                                    arr = this.owner.softCollisionMap.set(this.collisionType, Array.setUp());
                                    if (this.softCollisions) {
                                        for (key in this.softCollisions) {
                                            if (this.softCollisions.hasOwnProperty(key)) {
                                                arr.push(key);
                                                if (this.softCollisions[key]) { // To make sure it's not an empty string.
                                                    this.addEventListener('hit-by-' + key, entityBroadcast(this, this.softCollisions[key], 'soft'));
                                                }
                                            }
                                        }
                                    }
                                    
                                    this.active = true;
                                    this.stuck = false;
                                },
                                
                                events: {
                                    /**
                                     * On receiving this message, the component triggers `add-collision-entity` on the parent.
                                     *
                                     * @method 'collide-on'
                                     * @param type {String} If specified, only collision components of this type are added to the collision list.
                                     */
                                    "collide-on": function (type) {
                                        var owner = this.owner,
                                            colType = this.collisionType,
                                            colTypes = owner.collisionTypes;
                                        
                                        /**
                                         * On receiving 'collide-on', this message is triggered on the parent to turn on collision.
                                         *
                                         * @event 'add-collision-entity'
                                         * @param entity {platypus.Entity} The entity this component is attached to.
                                         */
                                        if (!this.active && ((typeof type !== 'string') || (type === colType))) {
                                            if (colTypes.indexOf(colType) === -1) {
                                                colTypes.push(colType);
                                            }
                                            owner.parent.triggerEvent('add-collision-entity', owner);
                                            this.active = true;
                                        }
                                    },
                                    
                                    /**
                                     * On receiving this message, the component triggers `remove-collision-entity` on the parent.
                                     *
                                     * @method 'collide-off'
                                     * @param type {String} If specified, only collision components of this type are removed from the collision list.
                                     */
                                    "collide-off": function (type) {
                                        var index = 0,
                                            owner = this.owner,
                                            parent = owner.parent,
                                            colType = this.collisionType,
                                            colTypes = owner.collisionTypes;
                                        
                                        /**
                                         * On receiving 'collide-off', this message is triggered on the parent to turn off collision.
                                         *
                                         * @event 'remove-collision-entity'
                                         * @param entity {platypus.Entity} The entity this component is attached to.
                                         */
                                        if (this.active && ((typeof type !== 'string') || (type === colType))) {
                                            parent.triggerEvent('remove-collision-entity', owner);
                                            index = colTypes.indexOf(colType);
                                            if (index >= 0) {
                                                colTypes.greenSplice(index);
                                            }
                                            this.active = false;
                        
                                            if (colTypes.length) {
                                                parent.triggerEvent('add-collision-entity', owner);
                                            }
                                        }
                                    },
                                    
                                    /**
                                     * This message causes the entity's x,y coordinates to update.
                                     *
                                     * @method 'relocate-entity'
                                     * @param position {platypus.Vector} The new coordinates.
                                     * @param [position.relative=false] {boolean} Determines whether the provided x,y coordinates are relative to the entity's current position.
                                     */
                                    "relocate-entity": function (resp) {
                                        var unstick = resp.unstick,
                                            um      = 0,
                                            i       = 0,
                                            x       = 0,
                                            y       = 0,
                                            aabb    = this.aabb,
                                            owner   = this.owner,
                                            shape   = null,
                                            shapes  = this.shapes;
                                        
                                        if (unstick) {
                                            um = unstick.magnitude();
                                        }
                                        
                                        if (this.move) {
                                            this.move.recycle();
                                            this.move = null;
                                        }
                                        
                                        if (resp.relative) {
                                            owner.position.setVector(owner.previousPosition).add(resp.position);
                                        } else {
                                            owner.position.setVector(resp.position);
                                        }
                        
                                        if (this.stuck) {
                                            if (um > 0) {
                                                owner.position.add(unstick);
                                            } else {
                                                this.stuck = false;
                                            }
                                        }
                                        
                                        x = owner.x;
                                        y = owner.y;
                                        
                                        aabb.reset();
                                        i = shapes.length;
                                        while (i--) {
                                            shape = shapes[i];
                                            shape.update(x, y);
                                            aabb.include(shape.aABB);
                                        }
                        
                                        owner.previousPosition.setVector(owner.position);
                                        
                                        if (um > 0) { // to force check in all directions for ultimate stuck resolution (esp. for stationary entities)
                                            if (!this.stuck) {
                                                this.stuck = true;
                                            }
                                            this.move = owner.stuckWith.copy().add(-x, -y).normalize();
                                        }
                                    },
                                    
                                    /**
                                     * If the entity is stuck to another entity, this component tries to unstick the entity on each logic step.
                                     *
                                     * @method 'handle-logic'
                                     */
                                    "handle-logic": function () {
                                        if (this.move) {
                                            this.owner.position.add(this.move); // By trying to move into it, we should get pushed back out.
                                        }
                                    },
                                    
                                    /**
                                     * Collision shapes are updated to reflect the new orientation when this message occurs.
                                     *
                                     * @method 'orientation-updated'
                                     * @param matrix {Array} A 2D matrix describing the new orientation.
                                     */
                                    "orientation-updated": function (matrix) {
                                        var i = 0;
                                        
                                        if (!this.ignoreOrientation) {
                                            for (i = 0; i < this.shapes.length; i++) {
                                                this.shapes[i].multiply(matrix);
                                            }
                                        }
                                    }
                                },
                                
                                methods: {
                                    getAABB: function () {
                                        return this.aabb;
                                    },
                                    
                                    getPreviousAABB: function () {
                                        return this.prevAABB;
                                    },
                                    
                                    getShapes: function () {
                                        return this.shapes;
                                    },
                                    
                                    getPrevShapes: function () {
                                        return this.prevShapes;
                                    },
                                    
                                    prepareCollision: function (x, y) {
                                        var i          = 0,
                                            shape      = null,
                                            prevShapes = this.shapes,
                                            shapes     = this.prevShapes,
                                            aabb       = this.aabb;
                                        
                                        this.owner.x = x;
                                        this.owner.y = y;
                                        
                                        this.prevShapes = prevShapes;
                                        this.shapes = shapes;
                                        
                                        this.prevAABB.set(aabb);
                                        aabb.reset();
                                        
                                        // update shapes
                                        i = shapes.length;
                                        while (i--) {
                                            shape = shapes[i];
                                            shape.update(x, y);
                                            aabb.include(shape.aABB);
                                        }
                                    },
                                    
                                    movePreviousX: function (x) {
                                        var i = 0;
                                        
                                        this.prevAABB.moveX(x);
                                        for (i = 0; i < this.prevShapes.length; i++) {
                                            this.prevShapes[i].setXWithEntityX(x);
                                        }
                                    },
                                    
                                    destroy: function () {
                                        var colFuncs = this.owner.collisionFunctions,
                                            collisionType = this.collisionType,
                                            i = this.owner.collisionTypes.indexOf(collisionType),
                                            owner = this.owner;
                                        
                                        owner.parent.triggerEvent('remove-collision-entity', owner);
                        
                                        this.aabb.recycle();
                                        delete this.aabb;
                                        this.prevAABB.recycle();
                                        delete this.prevAABB;
                                        
                                        if (i >= 0) {
                                            owner.collisionTypes.greenSplice(i);
                                        }
                                        
                                        if (owner.solidCollisionMap.has(collisionType)) {
                                            owner.solidCollisionMap.delete(collisionType).recycle();
                                        }
                                        if (owner.softCollisionMap.has(collisionType)) {
                                            owner.softCollisionMap.delete(collisionType).recycle();
                                        }
                        
                                        colFuncs.delete(collisionType).recycle();
                                        
                                        i = this.shapes.length;
                                        while (i--) {
                                            this.shapes[i].recycle();
                                            this.prevShapes[i].recycle();
                                        }
                                        this.shapes.recycle();
                                        this.prevShapes.recycle();
                                        delete this.shapes;
                                        delete this.prevShapes;
                        
                                        delete this.entities;
                        
                                        if (owner.collisionTypes.length) {
                                            owner.parent.triggerEvent('add-collision-entity', owner);
                                        } else { //remove collision functions
                                            colFuncs.recycle();
                                            owner.collisionFunctions = null;
                                            owner.solidCollisionMap.recycle();
                                            owner.solidCollisionMap = null;
                                            owner.softCollisionMap.recycle();
                                            owner.softCollisionMap = null;
                                            owner.aabb.recycle();
                                            owner.aabb = null;
                                        }
                                    }
                                }
                            });
                        }());