mixins/Hittable.js

'use strict';

const { Point2D } = require('../shared.js');
const Interactable = require('./Interactable.js');

/**
 * The Hitbox interface is used by the Hittable mixin. If a Hitbox is attached
 * to a Hittable instance object, hit detection will be performed on the object
 * when the user's first input in an interaction sequence touches down.
 *
 * Note that a class implementing the Hitbox interface should not worry about
 * applying transformations to the points it receives. That will be taken care
 * of by the Hittable mixin. To produce accurate results, a Hitbox should behave
 * as if the object it is associated with is positioned at x = 0, y = 0, with
 * scale = 1 and rotation = 0. That is, with the identity transformation.
 *
 * @interface Hitbox
 * @memberof module:shared
 */

/**
 * Report whether the given (x,y) point is contained within the shape.
 *
 * @function
 * @name module:shared.Hitbox#contains
 * @param {module:shared.Point2D} point - The point to test.
 * @return {boolean} True if the given point is inside the shape, false
 * otherwise.
 */

/**
 * This mixin extends the Interactable mixin by allow hit detection. A Hittable
 * will not automatically be able to respond to hit detection. To make a
 * Hittable item responsive, add a 'hitbox' property to the class or
 * instantiated object, which is itself an instance of a class which implements
 * the 'Hitbox' interface.
 *
 * The purpose of the Hittable mixin is simply to provide functionality for
 * interacting with the 'hitbox' property.
 *
 * @private
 * @memberof module:mixins
 *
 * @mixin
 * @mixes module:mixins.Interactable
 */
const Hittable = (sclass) =>
  class Hittable extends Interactable(sclass) {
    /**
     * The hitbox for this Hittable instance. If it is null, hit detection will
     * always return a falsy value.
     *
     * @name hitbox
     * @type {?module:shared.Hitbox}
     * @default undefined
     * @memberof module:mixins.Hittable
     */

    /**
     * Checks whether a point with the given x,y coordinates is contained by
     * this item.
     *
     * @memberof module:mixins.Hittable
     *
     * @param {number} px - x coordinate of the point to check.
     * @param {number} py - y coordinate of the point to check.
     *
     * @return {boolean} True if the (x,y) point is located inside this Item.
     * False otherwise.
     */
    containsPoint(px, py) {
      const point = new Point2D(px, py).minus(this).divideBy(this.scale).rotate(this.rotation);
      return this.hitbox && this.hitbox.contains(point);
    }
  };

module.exports = Hittable;