playable.js
Version:
A lightweight HTML5 game engine.
156 lines (138 loc) • 3.71 kB
text/typescript
import {Vector} from './Vector';
/**
* ```
* {a b 0}
* (x, y, 1) * {c d 0} = (ax + cy + tx, bx + dy + ty, 1)
* {tx ty 1}
* ```
*/
export class Matrix {
public a: number;
public b: number;
public c: number;
public d: number;
public tx: number;
public ty: number;
protected constructor(a?: number, b?: number, c?: number, d?: number, tx?: number, ty?: number) {
if (arguments.length > 0) {
this.set(a, b, c, d, tx, ty);
} else {
this.identity();
}
}
public set(a: number, b: number, c: number, d: number, tx: number, ty: number): this {
this.a = a;
this.b = b;
this.c = c;
this.d = d;
this.tx = tx;
this.ty = ty;
return this;
}
public identity(): this {
return this.set(1, 0, 0, 1, 0, 0);
}
public invert(): this {
let a = this.a;
let b = this.b;
let c = this.c;
let d = this.d;
let tx = this.tx;
let ty = this.ty;
let n = a * d - c * b;
this.a = d / n;
this.b = -b / n;
this.c = -c / n;
this.d = a / n;
this.tx = (c * ty - d * tx) / n;
this.ty = (b * tx - a * ty) / n;
return this;
}
public prepend(m: Matrix): this;
public prepend(a: number, b: number, c: number, d: number, tx: number, ty: number): this;
public prepend(a: number | Matrix, b?: number, c?: number, d?: number, tx?: number, ty?: number): this {
if (a instanceof Matrix) {
return this.prepend(a.a, a.b, a.c, a.d, a.tx, a.ty);
}
let a1 = this.a;
let b1 = this.b;
let c1 = this.c;
let d1 = this.d;
let tx1 = this.tx;
let ty1 = this.ty;
this.a = a * a1 + b * c1;
this.b = a * b1 + b * d1;
this.c = c * a1 + d * c1;
this.d = c * b1 + d * d1;
this.tx = tx * a1 + ty * c1 + tx1;
this.ty = tx * b1 + ty * d1 + ty1;
return this;
}
public append(m: Matrix): this;
public append(a: number, b: number, c: number, d: number, tx: number, ty: number): this;
public append(a: number | Matrix, b?: number, c?: number, d?: number, tx?: number, ty?: number): this {
if (a instanceof Matrix) {
return this.append(a.a, a.b, a.c, a.d, a.tx, a.ty);
}
let a1 = this.a;
let b1 = this.b;
let c1 = this.c;
let d1 = this.d;
let tx1 = this.tx;
let ty1 = this.ty;
this.a = a * a1 + c * b1;
this.b = b * a1 + d * b1;
this.c = a * c1 + c * d1;
this.d = b * c1 + d * d1;
this.tx = a * tx1 + c * ty1 + tx;
this.ty = b * tx1 + d * ty1 + ty;
return this;
}
public scale(x: number, y?: number): this {
return this.append(x, 0, 0, y === undefined ? x : y, 0, 0);
}
public rotate(angle: number): this {
let sin = Math.sin(angle);
let cos = Math.cos(angle);
return this.append(cos, sin, -sin, cos, 0, 0);
}
public skew(skewX: number, skewY: number): this {
return this.append(1, Math.tan(skewY), Math.tan(skewX), 1, 0, 0);
}
public translate(v: Vector): this;
public translate(x: number, y: number): this;
public translate(x: number | Vector, y?: number): this {
if (x instanceof Vector) {
return this.append(1, 0, 0, 1, x.x, x.y);
}
return this.append(1, 0, 0, 1, x, y);
}
public equal(m: Matrix): boolean {
return m instanceof Matrix &&
this.a === m.a && this.b === m.b &&
this.c === m.c && this.d === m.d &&
this.tx === m.tx && this.ty === m.ty;
}
public release(): void {
Matrix.recycle(this);
}
protected static readonly $pool: Array<Matrix> = [];
public static create(a?: number, b?: number, c?: number, d?: number, tx?: number, ty?: number): Matrix {
let m;
let pool = this.$pool;
if (pool.length > 0) {
m = pool.pop();
} else {
m = new Matrix();
}
if (arguments.length) {
m.set(a, b, c, d, tx, ty);
} else {
m.identity();
}
return m;
}
public static recycle(m: Matrix) {
this.$pool.push(m);
}
}