collider2d
Version:
A 2D collision checker for modern JavaScript games.
296 lines (251 loc) • 6.55 kB
text/typescript
'use strict'
/**
* Represents a vector in two dimensions with `x` and `y` properties.
*
* Create a new Vector, optionally passing in the `x` and `y` coordinates. If a coordinate is not specified, it will be set to `0`.
*/
export default class Vector {
/**
* The x coordinate of this vector.
*
* @private
*
* @property {number}
*/
private _x: number = 0;
/**
* The y coordinate of this vector.
*
* @private
*
* @property {number}
*/
private _y: number = 0;
/**
* @param {number} [x=0] The x coordinate of this vector.
* @param {number} [y=0] The y coordinate of this vector.
*/
constructor(x: number = 0, y: number = 0) {
this._x = x;
this._y = y;
}
/**
* Returns the x value of this vector.
*
* @returns {number}
*/
get x(): number { return this._x; }
/**
* Returns the y value of this vector.
*
* @returns {number}
*/
get y(): number { return this._y; }
/**
* Sets a new x value for this vector.
*
* @param {number} x The new x value for this vector.
*/
set x(x: number) { this._x = x; }
/**
* Sets a new y value for this vector.
*
* @param {number} y The new y value for this vector.
*/
set y(y: number) { this._y = y; }
/**
* Copy the values of another Vector into this one.
*
* @param {Vector} other The other Vector.
*
* @returns {Vector} Returns this for chaining.
*/
copy(other: Vector): Vector {
this._x = other.x;
this._y = other.y;
return this;
}
/**
* Create a new Vector with the same coordinates as the one.
*
* @returns {Vector} The new cloned Vector.
*/
clone(): Vector {
return new Vector(this.x, this.y);
}
/**
* Change this Vector to be perpendicular to what it was before.
*
* Effectively this rotates it 90 degrees in a clockwise direction.
*
* @returns {Vector} Returns this for chaining.
*/
perp(): Vector {
const x: number = this.x;
this._x = this.y;
this._y = -x;
return this;
}
/**
* Rotate this Vector (counter-clockwise) by the specified angle (in radians).
*
* @param {number} angle The angle to rotate (in radians).
*
* @returns {Vector} Returns this for chaining.
*/
rotate(angle: number): Vector {
const x: number = this.x;
const y: number = this.y;
this._x = x * Math.cos(angle) - y * Math.sin(angle);
this._y = x * Math.sin(angle) + y * Math.cos(angle);
return this;
}
/**
* Reverse this Vector.
*
* @returns {Vector} Returns this for chaining.
*/
reverse(): Vector {
this._x = -this.x;
this._y = -this.y;
return this;
}
/**
* Normalize this vector (make it have a length of `1`).
*
* @returns {Vector} Returns this for chaining.
*/
normalize(): Vector {
const d: number = this.len();
if (d > 0) {
this._x = this.x / d;
this._y = this.y / d;
}
return this;
}
/**
* Add another Vector to this one.
*
* @param {Vector} other The other Vector.
*
* @returns {Vector} Returns this for chaining.
*/
add(other: Vector): Vector {
this._x += other.x;
this._y += other.y;
return this;
}
/**
* Subtract another Vector from this one.
*
* @param {Vector} other The other Vector.
*
* @returns {Vector} Returns this for chaining.
*/
sub(other: Vector): Vector {
this._x -= other.x;
this._y -= other.y;
return this;
}
/**
* Scale this Vector.
*
* An independent scaling factor can be provided for each axis, or a single scaling factor will scale both `x` and `y`.
*
* @param {number} x The scaling factor in the x direction.
* @param {number} [y] The scaling factor in the y direction.
*
* @returns {Vector} Returns this for chaining.
*/
scale(x: number, y?: number): Vector {
this._x *= x;
this._y *= typeof y != 'undefined' ? y : x;
return this;
}
/**
* Project this Vector onto another Vector.
*
* @param {Vector} other The Vector to project onto.
*
* @returns {Vector} Returns this for chaining.
*/
project(other: Vector): Vector {
const amt: number = this.dot(other) / other.len2();
this._x = amt * other.x;
this._y = amt * other.y;
return this;
}
/**
* Project this Vector onto a Vector of unit length.
*
* This is slightly more efficient than `project` when dealing with unit vectors.
*
* @param {Vector} other The unit vector to project onto.
*
* @returns {Vector} Returns this for chaining.
*/
projectN(other: Vector): Vector {
const amt: number = this.dot(other);
this._x = amt * other.x;
this._y = amt * other.y;
return this;
}
/**
* Reflect this Vector on an arbitrary axis.
*
* @param {Vector} axis The Vector representing the axis.
*
* @returns {Vector} Returns this for chaining.
*/
reflect(axis: Vector): Vector {
const x: number = this.x;
const y: number = this.y;
this.project(axis).scale(2);
this._x -= x;
this._y -= y;
return this;
}
/**
* Reflect this Vector on an arbitrary axis.
*
* This is slightly more efficient than `reflect` when dealing with an axis that is a unit vector.
*
* @param {Vector} axis The Vector representing the axis.
*
* @returns {Vector} Returns this for chaining.
*/
reflectN(axis: Vector): Vector {
const x: number = this.x;
const y: number = this.y;
this.projectN(axis).scale(2);
this._x -= x;
this._y -= y;
return this;
}
/**
* Get the dot product of this Vector and another.
*
* @param {Vector} other The Vector to dot this one against.
*
* @returns {number} Returns the dot product of this vector.
*/
dot(other: Vector): number {
return this.x * other.x + this.y * other.y;
}
/**
* Get the squared length of this Vector.
*
* @returns {number} Returns the squared length of this vector.
*/
len2(): number {
return this.dot(this);
}
/**
* Get the length of this Vector.
*
* @returns {number} Returns the length of this vector.
*/
len(): number {
return Math.sqrt(this.len2());
}
}