Source: ray/matter-physics-methods.js

/*Matter physics methods for ray body*/
/**
 * Sets the collision category of this ray's Matter Body. This number must be a power of two between 2^0 (= 1) and 2^31.
 * Two bodies with different collision groups (see {@link #setCollisionGroup}) will only collide if their collision
 * categories are included in their collision masks (see {@link #setCollidesWith}).
 *
 * @method Raycaster.Ray#setCollisionCategory
 * @memberof Raycaster.Ray
 * @instance
 * @since 0.9.1
 *
 * @param {number} value - Unique category bitfield.
 * 
 * @return {Raycaster.Ray} {@link Raycaster.Ray Raycaster.Ray} instance
 */
export function setCollisionCategory(value) {
    this.body.collisionFilter.category = value;

    return this;
};

/**
 * Sets the collision group of this ray's Matter Body. If this is zero or two Matter Bodies have different values,
 * they will collide according to the usual rules (see {@link #setCollisionCategory} and {@link #setCollisionGroup}).
 * If two Matter Bodies have the same positive value, they will always collide; if they have the same negative value,
 * they will never collide.
 *
 * @method Raycaster.Ray#setCollisionCategory
 * @memberof Raycaster.Ray
 * @instance
 * @since 0.9.1
 *
 * @param {number} value - Unique group index.
 * 
 * @return {Raycaster.Ray} {@link Raycaster.Ray Raycaster.Ray} instance
 */
export function setCollisionGroup(value) {
    this.body.collisionFilter.group = value;

    return this;
};

/**
 * Sets the collision mask for this ray's Matter Body. Two Matter Bodies with different collision groups will only
 * collide if each one includes the other's category in its mask based on a bitwise AND, i.e. `(categoryA & maskB) !== 0`
 * and `(categoryB & maskA) !== 0` are both true.*
 *
 * @method Raycaster.Ray#setCollidesWith
 * @memberof Raycaster.Ray
 * @instance
 * @since 0.9.1
 *
 * @param {(number|number[])} categories - A unique category bitfield, or an array of them.
 * 
 * @return {Raycaster.Ray} {@link Raycaster.Ray Raycaster.Ray} instance
 */

export function setCollidesWith(categories) {
    var flags = 0;

    if (!Array.isArray(categories))
    {
        flags = categories;
    }
    else
    {
        for (var i = 0; i < categories.length; i++)
        {
            flags |= categories[i];
        }
    }

    this.body.collisionFilter.mask = flags;

    return this;
};

/**
 * The callback is sent a `Phaser.Types.Physics.Matter.MatterCollisionData` object.
 * 
 * This does not change the bodies collision category, group or filter. Those must be set in addition
 * to the callback.
 *
 * @method Raycaster.Ray#setOnCollide
 * @memberof Raycaster.Ray
 * @instance
 * @since 0.9.1
 *
 * @param {function} callback - The callback to invoke when this body starts colliding with another.
 * 
 * @return {Raycaster.Ray} {@link Raycaster.Ray Raycaster.Ray} instance
 */
export function setOnCollide(callback) {
    let self = this;
    this.body.onCollideCallback = function(collisionInfo) {
        if(collisionInfo.rayCollided) {
            callback(collisionInfo);
        }
        else if(self.processOverlap(collisionInfo)) {
            collisionInfo.rayCollided = true;
            callback(collisionInfo);
        }
    };

    return this;
};

/**
 * The callback is sent a `Phaser.Types.Physics.Matter.MatterCollisionData` object.
 * 
 * This does not change the bodies collision category, group or filter. Those must be set in addition
 * to the callback.
 *
 * @method Raycaster.Ray#setOnCollideEnd
 * @memberof Raycaster.Ray
 * @instance
 * @since 0.9.1
 *
 * @param {function} callback - The callback to invoke when this body stops colliding with another.
 * 
 * @return {Raycaster.Ray} {@link Raycaster.Ray Raycaster.Ray} instance
 */
export function setOnCollideEnd(callback) {
    this.body.onCollideEndCallback = function(collisionInfo) {
        if(collisionInfo.rayCollided) {
            collisionInfo.rayCollided = false;
            callback(collisionInfo);
        }
    }

    return this;
};

/**
 * The callback is sent a `Phaser.Types.Physics.Matter.MatterCollisionData` object.
 * 
 * This does not change the bodies collision category, group or filter. Those must be set in addition
 * to the callback.
 *
 * @method Raycaster.Ray#setOnCollideActive
 * @memberof Raycaster.Ray
 * @instance
 * @since 0.9.1
 *
 * @param {function} callback - The callback to invoke for the duration of this body colliding with another.
 * 
 * @return {Raycaster.Ray} {@link Raycaster.Ray Raycaster.Ray} instance
 */
export function setOnCollideActive(callback) {
    let self = this;
    let func = function(collisionInfo) {
        if(self.processOverlap(collisionInfo)) {
            let body = collisionInfo.bodyA.label === 'phaser-raycaster-ray-body' ? collisionInfo.bodyB : collisionInfo.bodyA;

            if(collisionInfo.rayCollided !== true) {
                collisionInfo.rayCollided = true;
                if(self.body.onCollideCallback) {
                    self.body.onCollideCallback(collisionInfo);
                }

                if(self.body.onCollideWith !== undefined && self.body.onCollideWith[body.id]) {
                    self.body.onCollideWith[body.id](body, collisionInfo);
                }
            }
            if(callback)
                callback(collisionInfo);
        }
        else {
            if(self.body.onCollideEndCallback && collisionInfo.rayCollided === true) {
                self.body.onCollideEndCallback(collisionInfo);
            }
        }
    }

    this.body.onCollideActiveCallback = func;

    return this;
}

/**
 * The callback is sent a reference to the other body, along with a `Phaser.Types.Physics.Matter.MatterCollisionData` object.
 * 
 * This does not change the bodies collision category, group or filter. Those must be set in addition
 * to the callback.
 *
 * @method Raycaster.Ray#setOnCollideWith
 * @memberof Raycaster.Ray
 * @instance
 * @since 0.9.1
 *
 * @param {(MatterJS.Body|MatterJS.Body[])} body - The body, or an array of bodies, to test for collisions with.
 * @param {function} callback - The callback to invoke when this body collides with the given body or bodies.
 * 
 * @return {Raycaster.Ray} {@link Raycaster.Ray Raycaster.Ray} instance
 */
export function setOnCollideWith(body, callback) {
    let self = this;
    let func = function(body, collisionInfo) {
        if(collisionInfo.rayCollided) {
            callback(body, collisionInfo);
        }
        else if(self.processOverlap(collisionInfo)) {
            collisionInfo.rayCollided = true;
            callback(body, collisionInfo);
        }
    }

    if (!Array.isArray(body))
    {
        body = [ body ];
    }

    for (var i = 0; i < body.length; i++)
    {
        var src = (body[i].hasOwnProperty('body')) ? body[i].body : body[i];

        this.body.setOnCollideWith(src, func);
    }

    return this;
};