diff --git a/Phaser/Phaser.csproj b/Phaser/Phaser.csproj
index 04cf115a..4890ae97 100644
--- a/Phaser/Phaser.csproj
+++ b/Phaser/Phaser.csproj
@@ -184,6 +184,18 @@
Bounds.ts
+
+
+
+ Collision.ts
+
+
+ Contact.ts
+
+
+
+ ContactSolver.ts
+
Joint.ts
@@ -196,9 +208,25 @@
Shape.ts
+
+
+ ShapeBox.ts
+
ShapeCircle.ts
+
+
+
+ ShapePoly.ts
+
+
+ ShapeSegment.ts
+
+
+
+ ShapeTriangle.ts
+
ArcadePhysics.ts
diff --git a/Phaser/math/Vec2.ts b/Phaser/math/Vec2.ts
index 32e136a1..de216c88 100644
--- a/Phaser/math/Vec2.ts
+++ b/Phaser/math/Vec2.ts
@@ -137,6 +137,20 @@ module Phaser {
return (this.x * this.x) + (this.y * this.y);
}
+ /**
+ * Normalize this vector.
+ *
+ * @return {Vec2} This for chaining.
+ */
+ public normalize(): Vec2 {
+
+ var inv = (this.x != 0 || this.y != 0) ? 1 / Math.sqrt(this.x * this.x + this.y * this.y) : 0;
+ this.x *= inv;
+ this.y *= inv;
+ return this;
+
+ }
+
/**
* The dot product of two 2D vectors.
*
diff --git a/Phaser/math/Vec2Utils.ts b/Phaser/math/Vec2Utils.ts
index 260625a5..6c1ff49d 100644
--- a/Phaser/math/Vec2Utils.ts
+++ b/Phaser/math/Vec2Utils.ts
@@ -85,6 +85,17 @@ module Phaser {
return out.setTo(a.x + b.x * s, a.y + b.y * s);
}
+ /**
+ * Return a negative vector.
+ *
+ * @param {Vec2} a Reference to a source Vec2 object.
+ * @param {Vec2} out The output Vec2 that is the result of the operation.
+ * @return {Vec2} A Vec2 that is the negative vector.
+ */
+ static negative(a: Vec2, out?: Vec2 = new Vec2): Vec2 {
+ return out.setTo(-a.x, -a.y);
+ }
+
/**
* Return a perpendicular vector (90 degrees rotation)
*
@@ -277,12 +288,30 @@ module Phaser {
* @param {Vec2} out The output Vec2 that is the result of the operation.
* @return {Vec2} A Vec2.
*/
- static rotate(a: Vec2, b: Vec2, theta: number, out?: Vec2 = new Vec2): Vec2 {
+ static rotateAroundOrigin(a: Vec2, b: Vec2, theta: number, out?: Vec2 = new Vec2): Vec2 {
var x = a.x - b.x;
var y = a.y - b.y;
return out.setTo(x * Math.cos(theta) - y * Math.sin(theta) + b.x, x * Math.sin(theta) + y * Math.cos(theta) + b.y);
}
+ /**
+ * Rotate a 2D vector to the given angle (theta).
+ *
+ * @param {Vec2} a Reference to a source Vec2 object.
+ * @param {Vec2} b Reference to a source Vec2 object.
+ * @param {Number} theta The angle of rotation in radians.
+ * @param {Vec2} out The output Vec2 that is the result of the operation.
+ * @return {Vec2} A Vec2.
+ */
+ static rotate(a: Vec2, theta: number, out?: Vec2 = new Vec2): Vec2 {
+
+ var c = Math.cos(theta);
+ var s = Math.sin(theta);
+
+ return out.setTo(a.x * c - a.y * s, a.x * s + a.y * c);
+
+ }
+
/**
* Clone a 2D vector.
*
diff --git a/Phaser/physics/advanced/Collision.ts b/Phaser/physics/advanced/Collision.ts
new file mode 100644
index 00000000..68d474f3
--- /dev/null
+++ b/Phaser/physics/advanced/Collision.ts
@@ -0,0 +1,551 @@
+///
+///
+///
+///
+///
+///
+///
+///
+
+/**
+* Phaser - Advanced Physics - Collision Handlers
+*
+* Based on the work Ju Hyung Lee started in JS PhyRus.
+*/
+
+module Phaser.Physics.Advanced {
+
+ export class Collision {
+
+ constructor() {
+ }
+
+ public collide(a, b, contacts: Contact[]) {
+
+ // Circle (a is the circle)
+ if (a.type == Manager.SHAPE_TYPE_CIRCLE)
+ {
+ if (b.type == Manager.SHAPE_TYPE_CIRCLE)
+ {
+ return this.circle2Circle(a, b, contacts);
+ }
+ else if (b.type == Manager.SHAPE_TYPE_SEGMENT)
+ {
+ return this.circle2Segment(a, b, contacts);
+ }
+ else if (b.type == Manager.SHAPE_TYPE_POLY)
+ {
+ return this.circle2Poly(a, b, contacts);
+ }
+ }
+
+ // Segment (a is the segment)
+ if (a.type == Manager.SHAPE_TYPE_SEGMENT)
+ {
+ if (b.type == Manager.SHAPE_TYPE_CIRCLE)
+ {
+ return this.circle2Segment(b, a, contacts);
+ }
+ else if (b.type == Manager.SHAPE_TYPE_SEGMENT)
+ {
+ return this.segment2Segment(a, b, contacts);
+ }
+ else if (b.type == Manager.SHAPE_TYPE_POLY)
+ {
+ return this.segment2Poly(a, b, contacts);
+ }
+ }
+
+ // Poly (a is the poly)
+ if (a.type == Manager.SHAPE_TYPE_POLY)
+ {
+ if (b.type == Manager.SHAPE_TYPE_CIRCLE)
+ {
+ return this.circle2Poly(b, a, contacts);
+ }
+ else if (b.type == Manager.SHAPE_TYPE_SEGMENT)
+ {
+ return this.segment2Poly(b, a, contacts);
+ }
+ else if (b.type == Manager.SHAPE_TYPE_POLY)
+ {
+ return this.poly2Poly(a, b, contacts);
+ }
+ }
+
+ }
+
+ private _circle2Circle(c1, r1, c2, r2, contactArr) {
+
+ var rmax = r1 + r2;
+
+ var t: Phaser.Vec2 = new Phaser.Vec2;
+ //var t = vec2.sub(c2, c1);
+ Phaser.Vec2Utils.subtract(c2, c1, t);
+
+ var distsq = t.lengthSq();
+
+ if (distsq > rmax * rmax)
+ {
+ return 0;
+ }
+
+ var dist = Math.sqrt(distsq);
+
+ var p: Phaser.Vec2 = new Phaser.Vec2;
+ Phaser.Vec2Utils.multiplyAdd(c1, t, 0.5 + (r1 - r2) * 0.5 / dist, p);
+ //var p = vec2.mad(c1, t, 0.5 + (r1 - r2) * 0.5 / dist);
+
+ var n: Phaser.Vec2 = new Phaser.Vec2;
+ //var n = (dist != 0) ? vec2.scale(t, 1 / dist) : vec2.zero;
+
+ if (dist != 0)
+ {
+ Phaser.Vec2Utils.scale(t, 1 / dist, n);
+ }
+
+ var d = dist - rmax;
+
+ contactArr.push(new Contact(p, n, d, 0));
+
+ return 1;
+
+ }
+
+ public circle2Circle(circ1, circ2, contactArr) {
+ return this._circle2Circle(circ1.tc, circ1.r, circ2.tc, circ2.r, contactArr);
+ }
+
+ public circle2Segment(circ: ShapeCircle, seg, contactArr: Contact[]) {
+
+ var rsum = circ.radius + seg.r;
+
+ // Normal distance from segment
+ var dn = Phaser.Vec2Utils.dot(circ.tc, seg.tn) - Phaser.Vec2Utils.dot(seg.ta, seg.tn);
+ var dist = (dn < 0 ? dn * -1 : dn) - rsum;
+ if (dist > 0)
+ {
+ return 0;
+ }
+
+ // Tangential distance along segment
+ var dt = Phaser.Vec2Utils.cross(circ.tc, seg.tn);
+ var dtMin = Phaser.Vec2Utils.cross(seg.ta, seg.tn);
+ var dtMax = Phaser.Vec2Utils.cross(seg.tb, seg.tn);
+
+ if (dt < dtMin)
+ {
+ if (dt < dtMin - rsum)
+ {
+ return 0;
+ }
+
+ return this._circle2Circle(circ.tc, circ.radius, seg.ta, seg.r, contactArr);
+ }
+ else if (dt > dtMax)
+ {
+ if (dt > dtMax + rsum)
+ {
+ return 0;
+ }
+
+ return this._circle2Circle(circ.tc, circ.radius, seg.tb, seg.r, contactArr);
+ }
+
+ var n: Phaser.Vec2 = new Phaser.Vec2;
+ if (dn > 0)
+ {
+ n.copyFrom(seg.tn);
+ }
+ else
+ {
+ Phaser.Vec2Utils.negative(seg.tn, n);
+ }
+ //var n = (dn > 0) ? seg.tn : vec2.neg(seg.tn);
+
+ var c1: Phaser.Vec2 = new Phaser.Vec2;
+ Phaser.Vec2Utils.multiplyAdd(circ.tc, n, -(circ.radius + dist * 0.5), c1);
+
+ var c2: Phaser.Vec2 = new Phaser.Vec2;
+ Phaser.Vec2Utils.negative(n, c2);
+
+ contactArr.push(new Contact(c1, c2, dist, 0));
+ //contactArr.push(new Contact(vec2.mad(circ.tc, n, -(circ.r + dist * 0.5)), vec2.neg(n), dist, 0));
+
+ return 1;
+
+ }
+
+ public circle2Poly(circ: ShapeCircle, poly, contactArr: Contact[]) {
+
+ var minDist = -999999;
+ var minIdx = -1;
+
+ for (var i = 0; i < poly.verts.length; i++)
+ {
+ var plane = poly.tplanes[i];
+ var dist = Phaser.Vec2Utils.dot(circ.tc, plane.n) - plane.d - circ.radius;
+
+ if (dist > 0)
+ {
+ return 0;
+ }
+ else if (dist > minDist)
+ {
+ minDist = dist;
+ minIdx = i;
+ }
+ }
+
+ var n = poly.tplanes[minIdx].n;
+ var a = poly.tverts[minIdx];
+ var b = poly.tverts[(minIdx + 1) % poly.verts.length];
+ var dta = Phaser.Vec2Utils.cross(a, n);
+ var dtb = Phaser.Vec2Utils.cross(b, n);
+ var dt = Phaser.Vec2Utils.cross(circ.tc, n);
+
+ if (dt > dta)
+ {
+ return this._circle2Circle(circ.tc, circ.radius, a, 0, contactArr);
+ }
+ else if (dt < dtb)
+ {
+ return this._circle2Circle(circ.tc, circ.radius, b, 0, contactArr);
+ }
+
+ var c1: Phaser.Vec2 = new Phaser.Vec2;
+ Phaser.Vec2Utils.multiplyAdd(circ.tc, n, -(circ.radius + minDist * 0.5), c1);
+
+ var c2: Phaser.Vec2 = new Phaser.Vec2;
+ Phaser.Vec2Utils.negative(n, c2);
+
+ contactArr.push(new Contact(c1, c2, minDist, 0));
+
+ //contactArr.push(new Contact(vec2.mad(circ.tc, n, -(circ.r + minDist * 0.5)), vec2.neg(n), minDist, 0));
+
+ return 1;
+
+ }
+
+ public segmentPointDistanceSq(seg, p) {
+
+ var w: Phaser.Vec2 = new Phaser.Vec2;
+ var d: Phaser.Vec2 = new Phaser.Vec2;
+ Phaser.Vec2Utils.subtract(p, seg.ta, w);
+ Phaser.Vec2Utils.subtract(seg.tb, seg.ta, d);
+
+ //var w = vec2.sub(p, seg.ta);
+ //var d = vec2.sub(seg.tb, seg.ta);
+
+ var proj = w.dot(d);
+
+ if (proj <= 0)
+ {
+ return w.dot(w);
+ }
+
+ var vsq = d.dot(d);
+
+ if (proj >= vsq)
+ {
+ return w.dot(w) - 2 * proj + vsq;
+ }
+
+ return w.dot(w) - proj * proj / vsq;
+
+ }
+
+ // FIXME and optimise me lots!!!
+ public segment2Segment(seg1, seg2, contactArr) {
+
+ var d = [];
+ d[0] = this.segmentPointDistanceSq(seg1, seg2.ta);
+ d[1] = this.segmentPointDistanceSq(seg1, seg2.tb);
+ d[2] = this.segmentPointDistanceSq(seg2, seg1.ta);
+ d[3] = this.segmentPointDistanceSq(seg2, seg1.tb);
+
+ var idx1 = d[0] < d[1] ? 0 : 1;
+ var idx2 = d[2] < d[3] ? 2 : 3;
+ var idxm = d[idx1] < d[idx2] ? idx1 : idx2;
+ var s, t;
+
+ var u = Phaser.Vec2Utils.subtract(seg1.tb, seg1.ta);
+ var v = Phaser.Vec2Utils.subtract(seg2.tb, seg2.ta);
+
+ switch (idxm)
+ {
+ case 0:
+ s = Phaser.Vec2Utils.dot(Phaser.Vec2Utils.subtract(seg2.ta, seg1.ta), u) / Phaser.Vec2Utils.dot(u, u);
+ s = s < 0 ? 0 : (s > 1 ? 1 : s);
+ t = 0;
+ break;
+ case 1:
+ s = Phaser.Vec2Utils.dot(Phaser.Vec2Utils.subtract(seg2.tb, seg1.ta), u) / Phaser.Vec2Utils.dot(u, u);
+ s = s < 0 ? 0 : (s > 1 ? 1 : s);
+ t = 1;
+ break;
+ case 2:
+ s = 0;
+ t = Phaser.Vec2Utils.dot(Phaser.Vec2Utils.subtract(seg1.ta, seg2.ta), v) / Phaser.Vec2Utils.dot(v, v);
+ t = t < 0 ? 0 : (t > 1 ? 1 : t);
+ break;
+ case 3:
+ s = 1;
+ t = Phaser.Vec2Utils.dot(Phaser.Vec2Utils.subtract(seg1.tb, seg2.ta), v) / Phaser.Vec2Utils.dot(v, v);
+ t = t < 0 ? 0 : (t > 1 ? 1 : t);
+ break;
+ }
+
+ var minp1 = Phaser.Vec2Utils.multiplyAdd(seg1.ta, u, s);
+ var minp2 = Phaser.Vec2Utils.multiplyAdd(seg2.ta, v, t);
+
+ return this._circle2Circle(minp1, seg1.r, minp2, seg2.r, contactArr);
+
+ }
+
+ // Identify vertexes that have penetrated the segment.
+ public findPointsBehindSeg(contactArr, seg, poly, dist, coef) {
+
+ var dta = Phaser.Vec2Utils.cross(seg.tn, seg.ta);
+ var dtb = Phaser.Vec2Utils.cross(seg.tn, seg.tb);
+
+ var n: Phaser.Vec2 = new Phaser.Vec2;
+ Phaser.Vec2Utils.scale(seg.tn, coef, n);
+ //var n = vec2.scale(seg.tn, coef);
+
+ for (var i = 0; i < poly.verts.length; i++)
+ {
+ var v = poly.tverts[i];
+
+ if (Phaser.Vec2Utils.dot(v, n) < Phaser.Vec2Utils.dot(seg.tn, seg.ta) * coef + seg.r)
+ {
+ var dt = Phaser.Vec2Utils.cross(seg.tn, v);
+
+ if (dta >= dt && dt >= dtb)
+ {
+ contactArr.push(new Contact(v, n, dist, (poly.id << 16) | i));
+ }
+ }
+ }
+ }
+
+ public segment2Poly(seg, poly, contactArr) {
+ var seg_td = Phaser.Vec2Utils.dot(seg.tn, seg.ta);
+ var seg_d1 = poly.distanceOnPlane(seg.tn, seg_td) - seg.r;
+ if (seg_d1 > 0)
+ {
+ return 0;
+ }
+
+ var n: Phaser.Vec2 = new Phaser.Vec2;
+ Phaser.Vec2Utils.negative(seg.tn, n);
+ var seg_d2 = poly.distanceOnPlane(n, -seg_td) - seg.r;
+ //var seg_d2 = poly.distanceOnPlane(vec2.neg(seg.tn), -seg_td) - seg.r;
+
+ if (seg_d2 > 0)
+ {
+ return 0;
+ }
+
+ var poly_d = -999999;
+ var poly_i = -1;
+
+ for (var i = 0; i < poly.verts.length; i++)
+ {
+ var plane = poly.tplanes[i];
+ var dist = seg.distanceOnPlane(plane.n, plane.d);
+
+ if (dist > 0)
+ {
+ return 0;
+ }
+
+ if (dist > poly_d)
+ {
+ poly_d = dist;
+ poly_i = i;
+ }
+ }
+
+ var poly_n: Phaser.Vec2 = new Phaser.Vec2;
+ Phaser.Vec2Utils.negative(poly.tplanes[poly_i].n, poly_n);
+ //var poly_n = vec2.neg(poly.tplanes[poly_i].n);
+
+ var va: Phaser.Vec2 = new Phaser.Vec2;
+ Phaser.Vec2Utils.multiplyAdd(seg.ta, poly_n, seg.r, va);
+ //var va = vec2.mad(seg.ta, poly_n, seg.r);
+
+ var vb: Phaser.Vec2 = new Phaser.Vec2;
+ Phaser.Vec2Utils.multiplyAdd(seg.tb, poly_n, seg.r, vb);
+ //var vb = vec2.mad(seg.tb, poly_n, seg.r);
+
+ if (poly.containPoint(va))
+ {
+ contactArr.push(new Contact(va, poly_n, poly_d, (seg.id << 16) | 0));
+ }
+
+ if (poly.containPoint(vb))
+ {
+ contactArr.push(new Contact(vb, poly_n, poly_d, (seg.id << 16) | 1));
+ }
+
+ // Floating point precision problems here.
+ // This will have to do for now.
+ poly_d -= 0.1
+ if (seg_d1 >= poly_d || seg_d2 >= poly_d)
+ {
+ if (seg_d1 > seg_d2)
+ {
+ this.findPointsBehindSeg(contactArr, seg, poly, seg_d1, 1);
+ }
+ else
+ {
+ this.findPointsBehindSeg(contactArr, seg, poly, seg_d2, -1);
+ }
+ }
+
+ // If no other collision points are found, try colliding endpoints.
+ if (contactArr.length == 0)
+ {
+ var poly_a = poly.tverts[poly_i];
+ var poly_b = poly.tverts[(poly_i + 1) % poly.verts.length];
+
+ if (this._circle2Circle(seg.ta, seg.r, poly_a, 0, contactArr))
+ {
+ return 1;
+ }
+
+ if (this._circle2Circle(seg.tb, seg.r, poly_a, 0, contactArr))
+ {
+ return 1;
+ }
+
+ if (this._circle2Circle(seg.ta, seg.r, poly_b, 0, contactArr))
+ {
+ return 1;
+ }
+
+ if (this._circle2Circle(seg.tb, seg.r, poly_b, 0, contactArr))
+ {
+ return 1;
+ }
+ }
+
+ return contactArr.length;
+
+ }
+
+ // Find the minimum separating axis for the given poly and plane list.
+ public findMSA(poly, planes, num) {
+
+ var min_dist = -999999;
+ var min_index = -1;
+
+ for (var i = 0; i < num; i++)
+ {
+ var dist = poly.distanceOnPlane(planes[i].n, planes[i].d);
+ if (dist > 0)
+ { // no collision
+ return { dist: 0, index: -1 };
+ }
+ else if (dist > min_dist)
+ {
+ min_dist = dist;
+ min_index = i;
+ }
+ }
+
+ // new object - see what we can do here
+ return { dist: min_dist, index: min_index };
+
+ }
+
+ public findVertsFallback(contactArr, poly1, poly2, n, dist) {
+
+ var num = 0;
+
+ for (var i = 0; i < poly1.verts.length; i++)
+ {
+ var v = poly1.tverts[i];
+
+ if (poly2.containPointPartial(v, n))
+ {
+ contactArr.push(new Contact(v, n, dist, (poly1.id << 16) | i));
+ num++;
+ }
+ }
+
+ for (var i = 0; i < poly2.verts.length; i++)
+ {
+ var v = poly2.tverts[i];
+
+ if (poly1.containPointPartial(v, n))
+ {
+ contactArr.push(new Contact(v, n, dist, (poly2.id << 16) | i));
+ num++;
+ }
+ }
+
+ return num;
+
+ }
+
+ // Find the overlapped vertices.
+ public findVerts(contactArr, poly1, poly2, n, dist) {
+
+ var num = 0;
+
+ for (var i = 0; i < poly1.verts.length; i++)
+ {
+ var v = poly1.tverts[i];
+
+ if (poly2.containPoint(v))
+ {
+ contactArr.push(new Contact(v, n, dist, (poly1.id << 16) | i));
+ num++;
+ }
+ }
+
+ for (var i = 0; i < poly2.verts.length; i++)
+ {
+ var v = poly2.tverts[i];
+
+ if (poly1.containPoint(v))
+ {
+ contactArr.push(new Contact(v, n, dist, (poly2.id << 16) | i));
+ num++;
+ }
+ }
+
+ return num > 0 ? num : this.findVertsFallback(contactArr, poly1, poly2, n, dist);
+
+ }
+
+ public poly2Poly(poly1, poly2, contactArr) {
+
+ var msa1 = this.findMSA(poly2, poly1.tplanes, poly1.verts.length);
+
+ if (msa1.index == -1)
+ {
+ return 0;
+ }
+
+ var msa2 = this.findMSA(poly1, poly2.tplanes, poly2.verts.length);
+ if (msa2.index == -1)
+ {
+ return 0;
+ }
+
+ // Penetration normal direction shoud be from poly1 to poly2
+ if (msa1.dist > msa2.dist)
+ {
+ return this.findVerts(contactArr, poly1, poly2, poly1.tplanes[msa1.index].n, msa1.dist);
+ }
+
+ return this.findVerts(contactArr, poly1, poly2, Phaser.Vec2Utils.negative(poly2.tplanes[msa2.index].n), msa2.dist);
+
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/Phaser/physics/advanced/Contact.ts b/Phaser/physics/advanced/Contact.ts
new file mode 100644
index 00000000..0380db09
--- /dev/null
+++ b/Phaser/physics/advanced/Contact.ts
@@ -0,0 +1,58 @@
+///
+///
+///
+///
+///
+///
+
+/**
+* Phaser - Advanced Physics - Contact
+*
+* Based on the work Ju Hyung Lee started in JS PhyRus.
+*/
+
+module Phaser.Physics.Advanced {
+
+ export class Contact {
+
+ constructor(p, n, d, hash) {
+
+ this.hash = hash;
+ this.point = p;
+ this.normal = n;
+ this.depth = d;
+ this.lambdaNormal = 0;
+ this.lambdaTangential = 0;
+
+ }
+
+ public hash;
+
+ // Linear velocities at contact point
+ public r1: Phaser.Vec2;
+ public r2: Phaser.Vec2;
+ public r1_local;
+ public r2_local;
+ // Bounce velocity
+ public bounce;
+ public emn;
+ public emt;
+
+ // Contact point
+ public point;
+
+ // Contact normal (toward shape2)
+ public normal: Phaser.Vec2;
+
+ // Penetration depth (d < 0)
+ public depth;
+
+ // Accumulated normal constraint impulse
+ public lambdaNormal;
+
+ // Accumulated tangential constraint impulse
+ public lambdaTangential;
+
+ }
+
+}
diff --git a/Phaser/physics/advanced/ContactSolver.ts b/Phaser/physics/advanced/ContactSolver.ts
new file mode 100644
index 00000000..ac6f16e8
--- /dev/null
+++ b/Phaser/physics/advanced/ContactSolver.ts
@@ -0,0 +1,352 @@
+///
+///
+///
+///
+///
+///
+///
+
+/**
+* Phaser - Advanced Physics - ContactSolver
+*
+* Based on the work Ju Hyung Lee started in JS PhyRus.
+*/
+
+//-------------------------------------------------------------------------------------------------
+// Contact Constraint
+//
+// Non-penetration constraint:
+// C = dot(p2 - p1, n)
+// Cdot = dot(v2 - v1, n)
+// J = [ -n, -cross(r1, n), n, cross(r2, n) ]
+//
+// impulse = JT * lambda = [ -n * lambda, -cross(r1, n) * lambda, n * lambda, cross(r1, n) * lambda ]
+//
+// Friction constraint:
+// C = dot(p2 - p1, t)
+// Cdot = dot(v2 - v1, t)
+// J = [ -t, -cross(r1, t), t, cross(r2, t) ]
+//
+// impulse = JT * lambda = [ -t * lambda, -cross(r1, t) * lambda, t * lambda, cross(r1, t) * lambda ]
+//
+// NOTE: lambda is an impulse in constraint space.
+//-------------------------------------------------------------------------------------------------
+
+module Phaser.Physics.Advanced {
+
+ export class ContactSolver {
+
+ constructor(shape1, shape2) {
+
+ this.shape1 = shape1;
+ this.shape2 = shape2;
+
+ this.contacts = [];
+ this.elasticity = 1;
+ this.friction = 1;
+
+ }
+
+ public shape1;
+ public shape2;
+
+ // Contact list
+ public contacts: Contact[];
+
+ // Coefficient of restitution (elasticity)
+ public elasticity: number;
+
+ // Frictional coefficient
+ public friction: number;
+
+ public update(newContactArr: Contact[]) {
+
+ for (var i = 0; i < newContactArr.length; i++)
+ {
+ var newContact = newContactArr[i];
+ var k = -1;
+
+ for (var j = 0; j < this.contacts.length; j++)
+ {
+ if (newContact.hash == this.contacts[j].hash)
+ {
+ k = j;
+ break;
+ }
+ }
+
+ if (k > -1)
+ {
+ newContact.lambdaNormal = this.contacts[k].lambdaNormal;
+ newContact.lambdaTangential = this.contacts[k].lambdaTangential;
+ }
+ }
+
+ this.contacts = newContactArr;
+
+ }
+
+ public initSolver(dt_inv) {
+
+ var body1: Body = this.shape1.body;
+ var body2: Body = this.shape2.body;
+
+ var sum_m_inv = body1.massInverted + body2.massInverted;
+
+ for (var i = 0; i < this.contacts.length; i++)
+ {
+ var con = this.contacts[i];
+
+ // Transformed r1, r2
+ Phaser.Vec2Utils.subtract(con.point, body1.position, con.r1);
+ Phaser.Vec2Utils.subtract(con.point, body2.position, con.r2);
+ //con.r1 = vec2.sub(con.point, body1.p);
+ //con.r2 = vec2.sub(con.point, body2.p);
+
+ // Local r1, r2
+ con.r1_local = body1.transform.unrotate(con.r1);
+ con.r2_local = body2.transform.unrotate(con.r2);
+
+ var n = con.normal;
+ var t = Phaser.Vec2Utils.perp(con.normal);
+
+ // invEMn = J * invM * JT
+ // J = [ -n, -cross(r1, n), n, cross(r2, n) ]
+ var sn1 = Phaser.Vec2Utils.cross(con.r1, n);
+ var sn2 = Phaser.Vec2Utils.cross(con.r2, n);
+ var emn_inv = sum_m_inv + body1.inertiaInverted * sn1 * sn1 + body2.inertiaInverted * sn2 * sn2;
+ con.emn = emn_inv == 0 ? 0 : 1 / emn_inv;
+
+ // invEMt = J * invM * JT
+ // J = [ -t, -cross(r1, t), t, cross(r2, t) ]
+ var st1 = Phaser.Vec2Utils.cross(con.r1, t);
+ var st2 = Phaser.Vec2Utils.cross(con.r2, t);
+ var emt_inv = sum_m_inv + body1.inertiaInverted * st1 * st1 + body2.inertiaInverted * st2 * st2;
+ con.emt = emt_inv == 0 ? 0 : 1 / emt_inv;
+
+ // Linear velocities at contact point
+ // in 2D: cross(w, r) = perp(r) * w
+
+ var v1 = new Phaser.Vec2;
+ var v2 = new Phaser.Vec2;
+
+ Phaser.Vec2Utils.multiplyAdd(body1.velocity, Phaser.Vec2Utils.perp(con.r1), body1.angularVelocity, v1);
+ Phaser.Vec2Utils.multiplyAdd(body2.velocity, Phaser.Vec2Utils.perp(con.r2), body2.angularVelocity, v2);
+ //var v1 = vec2.mad(body1.v, vec2.perp(con.r1), body1.w);
+ //var v2 = vec2.mad(body2.v, vec2.perp(con.r2), body2.w);
+
+ // relative velocity at contact point
+ var rv = new Phaser.Vec2;
+ Phaser.Vec2Utils.subtract(v2, v1, rv);
+ //var rv = vec2.sub(v2, v1);
+
+ // bounce velocity dot n
+ con.bounce = Phaser.Vec2Utils.dot(rv, con.normal) * this.elasticity;
+
+ }
+ }
+
+ public warmStart() {
+
+ var body1: Body = this.shape1.body;
+ var body2: Body = this.shape2.body;
+
+ for (var i = 0; i < this.contacts.length; i++)
+ {
+ var con = this.contacts[i];
+ var n = con.normal;
+ var lambda_n = con.lambdaNormal;
+ var lambda_t = con.lambdaTangential;
+
+ // Apply accumulated impulses
+ //var impulse = vec2.rotate_vec(new vec2(lambda_n, lambda_t), n);
+ //var impulse = new vec2(lambda_n * n.x - lambda_t * n.y, lambda_t * n.x + lambda_n * n.y);
+ var impulse = new Phaser.Vec2(lambda_n * n.x - lambda_t * n.y, lambda_t * n.x + lambda_n * n.y);
+
+ body1.velocity.multiplyAddByScalar(impulse, -body1.massInverted);
+ //body1.v.mad(impulse, -body1.m_inv);
+
+ body1.angularVelocity -= Phaser.Vec2Utils.cross(con.r1, impulse) * body1.inertiaInverted;
+ //body1.w -= vec2.cross(con.r1, impulse) * body1.i_inv;
+
+ body2.velocity.multiplyAddByScalar(impulse, -body2.massInverted);
+ //body2.v.mad(impulse, body2.m_inv);
+
+ body2.angularVelocity -= Phaser.Vec2Utils.cross(con.r2, impulse) * body2.inertiaInverted;
+ //body2.w += vec2.cross(con.r2, impulse) * body2.i_inv;
+ }
+
+ }
+
+ public solveVelocityConstraints() {
+
+ var body1: Body = this.shape1.body;
+ var body2: Body = this.shape2.body;
+
+ var m1_inv = body1.massInverted;
+ var i1_inv = body1.inertiaInverted;
+ var m2_inv = body2.massInverted;
+ var i2_inv = body2.inertiaInverted;
+
+ for (var i = 0; i < this.contacts.length; i++)
+ {
+ var con = this.contacts[i];
+ var n = con.normal;
+ var t = Phaser.Vec2Utils.perp(n);
+ var r1 = con.r1;
+ var r2 = con.r2;
+
+ // Linear velocities at contact point
+ // in 2D: cross(w, r) = perp(r) * w
+
+ var v1 = new Phaser.Vec2;
+ var v2 = new Phaser.Vec2;
+
+ Phaser.Vec2Utils.multiplyAdd(body1.velocity, Phaser.Vec2Utils.perp(r1), body1.angularVelocity, v1);
+ //var v1 = vec2.mad(body1.v, vec2.perp(r1), body1.w);
+
+ Phaser.Vec2Utils.multiplyAdd(body2.velocity, Phaser.Vec2Utils.perp(r2), body2.angularVelocity, v2);
+ //var v2 = vec2.mad(body2.v, vec2.perp(r2), body2.w);
+
+ // Relative velocity at contact point
+ var rv = new Phaser.Vec2;
+ Phaser.Vec2Utils.subtract(v2, v1, rv);
+ //var rv = vec2.sub(v2, v1);
+
+ // Compute normal constraint impulse + adding bounce as a velocity bias
+ // lambda_n = -EMn * J * V
+ var lambda_n = -con.emn * (Phaser.Vec2Utils.dot(n, rv) + con.bounce);
+
+ // Accumulate and clamp
+ var lambda_n_old = con.lambdaNormal;
+ con.lambdaNormal = Math.max(lambda_n_old + lambda_n, 0);
+ lambda_n = con.lambdaNormal - lambda_n_old;
+
+ // Compute frictional constraint impulse
+ // lambda_t = -EMt * J * V
+ var lambda_t = -con.emt * Phaser.Vec2Utils.dot(t, rv);
+
+ // Max friction constraint impulse (Coulomb's Law)
+ var lambda_t_max = con.lambdaNormal * this.friction;
+
+ // Accumulate and clamp
+ var lambda_t_old = con.lambdaTangential;
+ con.lambdaTangential = this.clamp(lambda_t_old + lambda_t, -lambda_t_max, lambda_t_max);
+ lambda_t = con.lambdaTangential - lambda_t_old;
+
+ // Apply the final impulses
+ //var impulse = vec2.rotate_vec(new vec2(lambda_n, lambda_t), n);
+ var impulse = new Phaser.Vec2(lambda_n * n.x - lambda_t * n.y, lambda_t * n.x + lambda_n * n.y);
+
+
+ body1.velocity.multiplyAddByScalar(impulse, -m1_inv);
+ //body1.v.mad(impulse, -m1_inv);
+
+ body1.angularVelocity -= Phaser.Vec2Utils.cross(r1, impulse) * i1_inv;
+ //body1.w -= vec2.cross(r1, impulse) * i1_inv;
+
+ body2.velocity.multiplyAddByScalar(impulse, m2_inv);
+ //body2.v.mad(impulse, m2_inv);
+
+ body1.angularVelocity += Phaser.Vec2Utils.cross(r2, impulse) * i2_inv;
+ //body2.w += vec2.cross(r2, impulse) * i2_inv;
+
+ }
+
+ }
+
+ public solvePositionConstraints() {
+
+ var body1: Body = this.shape1.body;
+ var body2: Body = this.shape2.body;
+
+ var m1_inv = body1.massInverted;
+ var i1_inv = body1.inertiaInverted;
+ var m2_inv = body2.massInverted;
+ var i2_inv = body2.inertiaInverted;
+ var sum_m_inv = m1_inv + m2_inv;
+
+ var max_penetration = 0;
+
+ for (var i = 0; i < this.contacts.length; i++)
+ {
+ var con = this.contacts[i];
+ var n = con.normal;
+
+ var r1 = new Phaser.Vec2;
+ var r2 = new Phaser.Vec2;
+
+ // Transformed r1, r2
+
+ Phaser.Vec2Utils.rotate(con.r1_local, body1.angle, r1);
+ //var r1 = vec2.rotate(con.r1_local, body1.a);
+
+
+ Phaser.Vec2Utils.rotate(con.r2_local, body2.angle, r2);
+ //var r2 = vec2.rotate(con.r2_local, body2.a);
+
+ // Contact points (corrected)
+ var p1 = new Phaser.Vec2;
+ var p2 = new Phaser.Vec2;
+
+ Phaser.Vec2Utils.add(body1.position, r1, p1);
+ //var p1 = vec2.add(body1.p, r1);
+
+ Phaser.Vec2Utils.add(body2.position, r2, p2);
+ //var p2 = vec2.add(body2.p, r2);
+
+ // Corrected delta vector
+ var dp = new Phaser.Vec2;
+ Phaser.Vec2Utils.subtract(p2, p1);
+ //var dp = vec2.sub(p2, p1);
+
+ // Position constraint
+ var c = Phaser.Vec2Utils.dot(dp, n) + con.depth;
+
+ var correction = this.clamp(Manager.CONTACT_SOLVER_BAUMGARTE * (c + Manager.CONTACT_SOLVER_COLLISION_SLOP), -Manager.CONTACT_SOLVER_MAX_LINEAR_CORRECTION, 0);
+
+ if (correction == 0)
+ {
+ continue;
+ }
+
+ // We don't need max_penetration less than or equal slop
+ max_penetration = Math.max(max_penetration, -c);
+
+ // Compute lambda for position constraint
+ // Solve (J * invM * JT) * lambda = -C / dt
+ var sn1 = Phaser.Vec2Utils.cross(r1, n);
+ var sn2 = Phaser.Vec2Utils.cross(r2, n);
+
+ var em_inv = sum_m_inv + body1.inertiaInverted * sn1 * sn1 + body2.inertiaInverted * sn2 * sn2;
+
+ var lambda_dt = em_inv == 0 ? 0 : -correction / em_inv;
+
+ // Apply correction impulses
+ var impulse_dt = new Phaser.Vec2;
+ Phaser.Vec2Utils.scale(n, lambda_dt, impulse_dt);
+ //var impulse_dt = vec2.scale(n, lambda_dt);
+
+ body1.position.multiplyAddByScalar(impulse_dt, -m1_inv);
+ //body1.p.mad(impulse_dt, -m1_inv);
+
+ body1.angle -= sn1 * lambda_dt * i1_inv;
+
+ body2.position.multiplyAddByScalar(impulse_dt, m2_inv);
+ //body2.p.mad(impulse_dt, m2_inv);
+
+ body2.angle += sn2 * lambda_dt * i2_inv;
+ }
+
+ return max_penetration <= Manager.CONTACT_SOLVER_COLLISION_SLOP * 3;
+
+ }
+
+ public clamp(v, min, max) {
+ return v < min ? min : (v > max ? max : v);
+ }
+
+
+ }
+
+}
diff --git a/Phaser/physics/advanced/Manager.ts b/Phaser/physics/advanced/Manager.ts
index 675c6541..57b86601 100644
--- a/Phaser/physics/advanced/Manager.ts
+++ b/Phaser/physics/advanced/Manager.ts
@@ -48,6 +48,10 @@ module Phaser.Physics.Advanced {
public static JOINT_LIMIT_STATE_AT_UPPER: number = 2;
public static JOINT_LIMIT_STATE_EQUAL_LIMITS: number = 3;
+ public static CONTACT_SOLVER_COLLISION_SLOP: number = 0.0008;
+ public static CONTACT_SOLVER_BAUMGARTE: number = 0.28;
+ public static CONTACT_SOLVER_MAX_LINEAR_CORRECTION: number = 1;//Infinity;
+
public static bodyCounter: number = 0;
public static jointCounter: number = 0;
public static shapeCounter: number = 0;
@@ -68,6 +72,159 @@ module Phaser.Physics.Advanced {
return value * 50;
}
+ public static areaForCircle(radius_outer, radius_inner) {
+ return Math.PI * (radius_outer * radius_outer - radius_inner * radius_inner);
+ }
+
+ public static inertiaForCircle(mass, center, radius_outer, radius_inner) {
+ return mass * ((radius_outer * radius_outer + radius_inner * radius_inner) * 0.5 + center.lengthsq());
+ }
+
+ public static areaForSegment(a, b, radius) {
+ return radius * (Math.PI * radius + 2 * Phaser.Vec2Utils.distance(a, b));
+ }
+
+ public static centroidForSegment(a, b) {
+ return Phaser.Vec2Utils.scale(Phaser.Vec2Utils.add(a, b), 0.5);
+ }
+
+ public static inertiaForSegment(mass, a, b) {
+
+ var distsq = Phaser.Vec2Utils.distanceSq(b, a);
+ var offset: Phaser.Vec2 = Phaser.Vec2Utils.scale(Phaser.Vec2Utils.add(a, b), 0.5);
+
+ return mass * (distsq / 12 + offset.lengthSq());
+ }
+
+ public static areaForPoly(verts) {
+
+ var area = 0;
+
+ for (var i = 0; i < verts.length; i++)
+ {
+ area += Phaser.Vec2Utils.cross(verts[i], verts[(i + 1) % verts.length]);
+ }
+
+ return area / 2;
+ }
+
+ public static centroidForPoly(verts) {
+
+ var area = 0;
+ var vsum = new Phaser.Vec2;
+
+ for (var i = 0; i < verts.length; i++)
+ {
+ var v1 = verts[i];
+ var v2 = verts[(i + 1) % verts.length];
+ var cross = Phaser.Vec2Utils.cross(v1, v2);
+
+ area += cross;
+
+ // SO many vecs created here - unroll these bad boys
+ vsum.add(Phaser.Vec2Utils.scale(Phaser.Vec2Utils.add(v1, v2), cross));
+ }
+
+ return Phaser.Vec2Utils.scale(vsum, 1 / (3 * area));
+ }
+
+ public static inertiaForPoly(mass, verts, offset) {
+
+ var sum1 = 0;
+ var sum2 = 0;
+
+ for (var i = 0; i < verts.length; i++)
+ {
+ var v1 = Phaser.Vec2Utils.add(verts[i], offset);
+ var v2 = Phaser.Vec2Utils.add(verts[(i + 1) % verts.length], offset);
+
+ var a = Phaser.Vec2Utils.cross(v2, v1);
+ var b = Phaser.Vec2Utils.dot(v1, v1) + Phaser.Vec2Utils.dot(v1, v2) + Phaser.Vec2Utils.dot(v2, v2);
+
+ sum1 += a * b;
+ sum2 += a;
+ }
+
+ return (mass * sum1) / (6 * sum2);
+ }
+
+ public static inertiaForBox(mass, w, h) {
+ return mass * (w * w + h * h) / 12;
+ }
+
+ // Create the convex hull using the Gift wrapping algorithm (http://en.wikipedia.org/wiki/Gift_wrapping_algorithm)
+ public static createConvexHull(points) {
+
+ // Find the right most point on the hull
+ var i0 = 0;
+ var x0 = points[0].x;
+
+ for (var i = 1; i < points.length; i++)
+ {
+ var x = points[i].x;
+
+ if (x > x0 || (x == x0 && points[i].y < points[i0].y))
+ {
+ i0 = i;
+ x0 = x;
+ }
+ }
+
+ var n = points.length;
+ var hull = [];
+ var m = 0;
+ var ih = i0;
+
+ while (1)
+ {
+ hull[m] = ih;
+
+ var ie = 0;
+
+ for (var j = 1; j < n; j++)
+ {
+ if (ie == ih)
+ {
+ ie = j;
+ continue;
+ }
+
+ var r = Phaser.Vec2Utils.subtract(points[ie], points[hull[m]]);
+ var v = Phaser.Vec2Utils.subtract(points[j], points[hull[m]]);
+ var c = Phaser.Vec2Utils.cross(r, v);
+
+ if (c < 0)
+ {
+ ie = j;
+ }
+
+ // Collinearity check
+ if (c == 0 && v.lengthSq() > r.lengthSq())
+ {
+ ie = j;
+ }
+ }
+
+ m++;
+ ih = ie;
+
+ if (ie == i0)
+ {
+ break;
+ }
+ }
+
+ // Copy vertices
+ var newPoints = [];
+
+ for (var i = 0; i < m; ++i)
+ {
+ newPoints.push(points[hull[i]]);
+ }
+
+ return newPoints;
+ }
+
}
}
\ No newline at end of file
diff --git a/Phaser/physics/advanced/ShapeBox.ts b/Phaser/physics/advanced/ShapeBox.ts
new file mode 100644
index 00000000..4784a351
--- /dev/null
+++ b/Phaser/physics/advanced/ShapeBox.ts
@@ -0,0 +1,35 @@
+///
+///
+///
+///
+///
+///
+///
+
+/**
+* Phaser - Advanced Physics - ShapeBox
+*
+* Based on the work Ju Hyung Lee started in JS PhyRus.
+*/
+
+module Phaser.Physics.Advanced {
+
+ export class ShapeBox extends Phaser.Physics.Advanced.ShapePoly {
+
+ constructor(x, y, width, height) {
+
+ var hw = width * 0.5;
+ var hh = height * 0.5;
+
+ super([
+ new Phaser.Vec2(-hw + x, +hh + y),
+ new Phaser.Vec2(-hw + x, -hh + y),
+ new Phaser.Vec2(+hw + x, -hh + y),
+ new Phaser.Vec2(+hw + x, +hh + y)
+ ]);
+
+ }
+
+ }
+
+}
diff --git a/Phaser/physics/advanced/ShapeCircle.ts b/Phaser/physics/advanced/ShapeCircle.ts
index 51629b6b..680f52c5 100644
--- a/Phaser/physics/advanced/ShapeCircle.ts
+++ b/Phaser/physics/advanced/ShapeCircle.ts
@@ -15,14 +15,81 @@ module Phaser.Physics.Advanced {
export class ShapeCircle extends Phaser.Physics.Advanced.Shape {
- constructor() {
+ constructor(radius: number, x?: number = 0, y?: number = 0) {
super(Manager.SHAPE_TYPE_CIRCLE);
+ this.center = new Phaser.Vec2(x, y);
+ this.radius = radius;
+ this.tc = new Phaser.Vec2;
+ this.finishVerts();
}
+ public radius: number;
+ public center: Phaser.Vec2;
+ public tc: Phaser.Vec2;
+
+ public finishVerts() {
+ this.radius = Math.abs(this.radius);
+ }
+
+ public duplicate() {
+ return new ShapeCircle(this.center.x, this.center.y, this.radius);
+ }
+
+ public recenter(c) {
+ this.center.subtract(c);
+ }
+
+ public transform(xf) {
+ this.center = xf.transform(this.center);
+ }
+
+ public untransform(xf) {
+ this.center = xf.untransform(this.center);
+ }
+
+ public area() {
+ return Manager.areaForCircle(this.radius, 0);
+ }
+
+ public centroid() {
+ //return this.center.duplicate();
+ }
+
+ public inertia(mass) {
+ return Manager.inertiaForCircle(mass, this.center, this.radius, 0);
+ }
+
+
+ public cacheData(xf) {
+ this.tc = xf.transform(this.center);
+ this.bounds.mins.set(this.tc.x - this.radius, this.tc.y - this.radius);
+ this.bounds.maxs.set(this.tc.x + this.radius, this.tc.y + this.radius);
+ }
+
+ public pointQuery(p) {
+ //return vec2.distsq(this.tc, p) < (this.r * this.r);
+ return Phaser.Vec2Utils.distanceSq(this.tc, p) < (this.radius * this.radius);
+ }
+
+ public findVertexByPoint(p, minDist) {
+
+ var dsq = minDist * minDist;
+
+ if (Phaser.Vec2Utils.distanceSq(this.tc, p) < dsq)
+ {
+ return 0;
+ }
+
+ return -1;
+ }
+
+ public distanceOnPlane(n, d) {
+ Phaser.Vec2Utils.dot(n, this.tc) - this.radius - d;
+ }
}
diff --git a/Phaser/physics/advanced/ShapePoly.ts b/Phaser/physics/advanced/ShapePoly.ts
new file mode 100644
index 00000000..918dfaeb
--- /dev/null
+++ b/Phaser/physics/advanced/ShapePoly.ts
@@ -0,0 +1,293 @@
+///
+///
+///
+///
+///
+///
+
+/**
+* Phaser - Advanced Physics - ShapePoly (convex only)
+*
+* Based on the work Ju Hyung Lee started in JS PhyRus.
+*/
+
+module Phaser.Physics.Advanced {
+
+ export class ShapePoly extends Phaser.Physics.Advanced.Shape {
+
+ constructor(verts?:Phaser.Vec2[]) {
+
+ super(Manager.SHAPE_TYPE_POLY);
+
+ this.verts = [];
+ this.planes = [];
+
+ this.tverts = [];
+ this.tplanes = [];
+
+ if (verts)
+ {
+ for (var i = 0; i < verts.length; i++)
+ {
+ Phaser.Vec2Utils.clone(verts[i], this.verts[i]);
+ this.tverts[i] = this.verts[i];
+
+ this.tplanes[i] = {};
+ this.tplanes[i].n = new Phaser.Vec2;
+ this.tplanes[i].d = 0;
+ }
+ }
+
+ this.finishVerts();
+
+ }
+
+ public verts: Phaser.Vec2[];
+ public planes;
+
+ public tverts;
+ public tplanes;
+
+ public convexity: bool;
+
+ public finishVerts() {
+
+ if (this.verts.length < 2)
+ {
+ this.convexity = false;
+ this.planes = [];
+ return;
+ }
+
+ this.convexity = true;
+ this.tverts = [];
+ this.tplanes = [];
+
+ // Must be counter-clockwise verts
+ for (var i = 0; i < this.verts.length; i++)
+ {
+ var a = this.verts[i];
+ var b = this.verts[(i + 1) % this.verts.length];
+ var n = Phaser.Vec2Utils.normalize(Phaser.Vec2Utils.perp(Phaser.Vec2Utils.subtract(a, b)));
+
+ this.planes[i] = {};
+ this.planes[i].n = n;
+ this.planes[i].d = Phaser.Vec2Utils.dot(n, a);
+
+ this.tverts[i] = this.verts[i];
+
+ this.tplanes[i] = {};
+ this.tplanes[i].n = new Phaser.Vec2;
+ this.tplanes[i].d = 0;
+ }
+
+ for (var i = 0; i < this.verts.length; i++)
+ {
+ var b = this.verts[(i + 2) % this.verts.length];
+ var n = this.planes[i].n;
+ var d = this.planes[i].d;
+
+ if (Phaser.Vec2Utils.dot(n, b) - d > 0)
+ {
+ this.convexity = false;
+ }
+ }
+ }
+
+ public duplicate() {
+ return new ShapePoly(this.verts);
+ }
+
+ public recenter(c) {
+
+ for (var i = 0; i < this.verts.length; i++)
+ {
+ this.verts[i].subtract(c);
+ }
+
+ }
+
+ public transform(xf) {
+ for (var i = 0; i < this.verts.length; i++)
+ {
+ this.verts[i] = xf.transform(this.verts[i]);
+ }
+ }
+
+ public untransform(xf) {
+ for (var i = 0; i < this.verts.length; i++)
+ {
+ this.verts[i] = xf.untransform(this.verts[i]);
+ }
+ }
+
+ public area() {
+ return Manager.areaForPoly(this.verts);
+ }
+
+ public centroid() {
+ return Manager.centroidForPoly(this.verts);
+ }
+
+ public inertia(mass) {
+ return Manager.inertiaForPoly(mass, this.verts, new Phaser.Vec2);
+ }
+
+ public cacheData(xf) {
+
+ this.bounds.clear();
+
+ var numVerts = this.verts.length;
+
+ if (numVerts == 0)
+ {
+ return;
+ }
+
+ for (var i = 0; i < numVerts; i++)
+ {
+ this.tverts[i] = xf.transform(this.verts[i]);
+ }
+
+ if (numVerts < 2)
+ {
+ this.bounds.addPoint(this.tverts[0]);
+ return;
+ }
+
+ for (var i = 0; i < numVerts; i++)
+ {
+ var a = this.tverts[i];
+ var b = this.tverts[(i + 1) % numVerts];
+
+ var n = Phaser.Vec2Utils.normalize(Phaser.Vec2Utils.perp(Phaser.Vec2Utils.subtract(a, b)));
+
+ this.tplanes[i].n = n;
+ this.tplanes[i].d = Phaser.Vec2Utils.dot(n, a);
+
+ this.bounds.addPoint(a);
+ }
+
+ }
+
+ public pointQuery(p) {
+
+ if (!this.bounds.containPoint(p))
+ {
+ return false;
+ }
+
+ return this.containPoint(p);
+ }
+
+ public findVertexByPoint(p, minDist) {
+
+ var dsq = minDist * minDist;
+
+ for (var i = 0; i < this.tverts.length; i++)
+ {
+ if (Phaser.Vec2Utils.distanceSq(this.tverts[i], p) < dsq)
+ {
+ return i;
+ }
+ }
+
+ return -1;
+ }
+
+ public findEdgeByPoint(p, minDist) {
+
+ var dsq = minDist * minDist;
+ var numVerts = this.tverts.length;
+
+ for (var i = 0; i < this.tverts.length; i++)
+ {
+ var v1 = this.tverts[i];
+ var v2 = this.tverts[(i + 1) % numVerts];
+ var n = this.tplanes[i].n;
+
+ var dtv1 = Phaser.Vec2Utils.cross(v1, n);
+ var dtv2 = Phaser.Vec2Utils.cross(v2, n);
+ var dt = Phaser.Vec2Utils.cross(p, n);
+
+ if (dt > dtv1)
+ {
+ if (Phaser.Vec2Utils.distanceSq(v1, p) < dsq)
+ {
+ return i;
+ }
+ }
+ else if (dt < dtv2)
+ {
+ if (Phaser.Vec2Utils.distanceSq(v2, p) < dsq)
+ {
+ return i;
+ }
+ }
+ else
+ {
+ var dist = Phaser.Vec2Utils.dot(n, p) - Phaser.Vec2Utils.dot(n, v1);
+
+ if (dist * dist < dsq)
+ {
+ return i;
+ }
+ }
+ }
+
+ return -1;
+
+ }
+
+ public distanceOnPlane(n, d) {
+
+ var min = 999999;
+
+ for (var i = 0; i < this.verts.length; i++)
+ {
+ min = Math.min(min, Phaser.Vec2Utils.dot(n, this.tverts[i]));
+ }
+
+ return min - d;
+
+ }
+
+ public containPoint(p) {
+
+ for (var i = 0; i < this.verts.length; i++)
+ {
+ var plane = this.tplanes[i];
+
+ if (Phaser.Vec2Utils.dot(plane.n, p) - plane.d > 0)
+ {
+ return false;
+ }
+ }
+
+ return true;
+
+ }
+
+ public containPointPartial(p, n) {
+
+ for (var i = 0; i < this.verts.length; i++)
+ {
+ var plane = this.tplanes[i];
+
+ if (Phaser.Vec2Utils.dot(plane.n, n) < 0.0001)
+ {
+ continue;
+ }
+
+ if (Phaser.Vec2Utils.dot(plane.n, p) - plane.d > 0)
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/Phaser/physics/advanced/ShapeSegment.ts b/Phaser/physics/advanced/ShapeSegment.ts
new file mode 100644
index 00000000..4359eb93
--- /dev/null
+++ b/Phaser/physics/advanced/ShapeSegment.ts
@@ -0,0 +1,192 @@
+///
+///
+///
+///
+///
+///
+
+/**
+* Phaser - Advanced Physics - Shape
+*
+* Based on the work Ju Hyung Lee started in JS PhyRus.
+*/
+
+module Phaser.Physics.Advanced {
+
+ export class ShapeSegment extends Phaser.Physics.Advanced.Shape {
+
+ constructor(a, b, radius: number) {
+
+ super(Manager.SHAPE_TYPE_SEGMENT);
+
+ // What types are A and B??!
+ this.a = a.duplicate();
+ this.b = b.duplicate();
+ this.radius = radius;
+
+ this.normal = Phaser.Vec2Utils.perp(Phaser.Vec2Utils.subtract(b, a));
+ this.normal.normalize();
+
+ this.ta = new Phaser.Vec2;
+ this.tb = new Phaser.Vec2;
+ this.tn = new Phaser.Vec2;
+
+ this.finishVerts();
+
+ }
+
+ public a: Phaser.Vec2;
+ public b: Phaser.Vec2;
+ public radius: number;
+
+ public normal: Phaser.Vec2;
+ public ta: Phaser.Vec2;
+ public tb: Phaser.Vec2;
+ public tn: Phaser.Vec2;
+
+ public finishVerts() {
+
+ this.normal = Phaser.Vec2Utils.perp(Phaser.Vec2Utils.subtract(this.b, this.a));
+ this.normal.normalize();
+
+ this.radius = Math.abs(this.radius);
+
+ }
+
+ public duplicate() {
+ return new ShapeSegment(this.a, this.b, this.radius);
+ }
+
+ public recenter(c) {
+ this.a.subtract(c);
+ this.b.subtract(c);
+ }
+
+ public transform(xf) {
+ this.a = xf.transform(this.a);
+ this.b = xf.transform(this.b);
+ }
+
+ public untransform(xf) {
+ this.a = xf.untransform(this.a);
+ this.b = xf.untransform(this.b);
+ }
+
+ public area() {
+ return Manager.areaForSegment(this.a, this.b, this.radius);
+ }
+
+ public centroid() {
+ return Manager.centroidForSegment(this.a, this.b);
+ }
+
+ public inertia(mass) {
+ return Manager.inertiaForSegment(mass, this.a, this.b);
+ }
+
+ public cacheData(xf) {
+
+ this.ta = xf.transform(this.a);
+ this.tb = xf.transform(this.b);
+ this.tn = Phaser.Vec2Utils.perp(Phaser.Vec2Utils.subtract(this.tb, this.ta)).normalize();
+
+ var l;
+ var r;
+ var t;
+ var b;
+
+ if (this.ta.x < this.tb.x)
+ {
+ l = this.ta.x;
+ r = this.tb.x;
+ }
+ else
+ {
+ l = this.tb.x;
+ r = this.ta.x;
+ }
+
+ if (this.ta.y < this.tb.y)
+ {
+ b = this.ta.y;
+ t = this.tb.y;
+ } else
+ {
+ b = this.tb.y;
+ t = this.ta.y;
+ }
+
+ this.bounds.mins.set(l - this.radius, b - this.radius);
+ this.bounds.maxs.set(r + this.radius, t + this.radius);
+
+ }
+
+ public pointQuery(p) {
+
+ if (!this.bounds.containPoint(p))
+ {
+ return false;
+ }
+
+ var dn = Phaser.Vec2Utils.dot(this.tn, p) - Phaser.Vec2Utils.dot(this.ta, this.tn);
+ var dist = Math.abs(dn);
+
+ if (dist > this.radius)
+ {
+ return false;
+ }
+
+ var dt = Phaser.Vec2Utils.cross(p, this.tn);
+ var dta = Phaser.Vec2Utils.cross(this.ta, this.tn);
+ var dtb = Phaser.Vec2Utils.cross(this.tb, this.tn);
+
+ if (dt <= dta)
+ {
+ if (dt < dta - this.radius)
+ {
+ return false;
+ }
+
+ return Phaser.Vec2Utils.distanceSq(this.ta, p) < (this.radius * this.radius);
+ }
+ else if (dt > dtb)
+ {
+ if (dt > dtb + this.radius)
+ {
+ return false;
+ }
+
+ return Phaser.Vec2Utils.distanceSq(this.tb, p) < (this.radius * this.radius);
+ }
+
+ return true;
+ }
+
+ public findVertexByPoint(p, minDist) {
+
+ var dsq = minDist * minDist;
+
+ if (Phaser.Vec2Utils.distanceSq(this.ta, p) < dsq)
+ {
+ return 0;
+ }
+
+ if (Phaser.Vec2Utils.distanceSq(this.tb, p) < dsq)
+ {
+ return 1;
+ }
+
+ return -1;
+ }
+
+ public distanceOnPlane(n, d) {
+
+ var a = Phaser.Vec2Utils.dot(n, this.ta) - this.radius;
+ var b = Phaser.Vec2Utils.dot(n, this.tb) - this.radius;
+
+ return Math.min(a, b) - d;
+ }
+
+ }
+
+}
\ No newline at end of file
diff --git a/Phaser/physics/advanced/ShapeTriangle.ts b/Phaser/physics/advanced/ShapeTriangle.ts
new file mode 100644
index 00000000..769c4084
--- /dev/null
+++ b/Phaser/physics/advanced/ShapeTriangle.ts
@@ -0,0 +1,27 @@
+///
+///
+///
+///
+///
+///
+///
+
+/**
+* Phaser - Advanced Physics - ShapeTriangle
+*
+* Based on the work Ju Hyung Lee started in JS PhyRus.
+*/
+
+module Phaser.Physics.Advanced {
+
+ export class ShapeTriangle extends Phaser.Physics.Advanced.ShapePoly {
+
+ constructor(p1, p2, p3) {
+
+ super( [ new Phaser.Vec2(p1.x, p1.y), new Phaser.Vec2(p2.x, p2.y), new Phaser.Vec2(p3.x, p3.y) ] );
+
+ }
+
+ }
+
+}
diff --git a/Tests/phaser.js b/Tests/phaser.js
index 9899b1dd..e2525f58 100644
--- a/Tests/phaser.js
+++ b/Tests/phaser.js
@@ -833,6 +833,17 @@ var Phaser;
function () {
return (this.x * this.x) + (this.y * this.y);
};
+ Vec2.prototype.normalize = /**
+ * Normalize this vector.
+ *
+ * @return {Vec2} This for chaining.
+ */
+ function () {
+ var inv = (this.x != 0 || this.y != 0) ? 1 / Math.sqrt(this.x * this.x + this.y * this.y) : 0;
+ this.x *= inv;
+ this.y *= inv;
+ return this;
+ };
Vec2.prototype.dot = /**
* The dot product of two 2D vectors.
*
@@ -3986,6 +3997,17 @@ var Phaser;
if (typeof out === "undefined") { out = new Phaser.Vec2(); }
return out.setTo(a.x + b.x * s, a.y + b.y * s);
};
+ Vec2Utils.negative = /**
+ * Return a negative vector.
+ *
+ * @param {Vec2} a Reference to a source Vec2 object.
+ * @param {Vec2} out The output Vec2 that is the result of the operation.
+ * @return {Vec2} A Vec2 that is the negative vector.
+ */
+ function negative(a, out) {
+ if (typeof out === "undefined") { out = new Phaser.Vec2(); }
+ return out.setTo(-a.x, -a.y);
+ };
Vec2Utils.perp = /**
* Return a perpendicular vector (90 degrees rotation)
*
@@ -4147,7 +4169,7 @@ var Phaser;
function angleSq(a, b) {
return a.subtract(b).angle(b.subtract(a));
};
- Vec2Utils.rotate = /**
+ Vec2Utils.rotateAroundOrigin = /**
* Rotate a 2D vector around the origin to the given angle (theta).
*
* @param {Vec2} a Reference to a source Vec2 object.
@@ -4156,12 +4178,27 @@ var Phaser;
* @param {Vec2} out The output Vec2 that is the result of the operation.
* @return {Vec2} A Vec2.
*/
- function rotate(a, b, theta, out) {
+ function rotateAroundOrigin(a, b, theta, out) {
if (typeof out === "undefined") { out = new Phaser.Vec2(); }
var x = a.x - b.x;
var y = a.y - b.y;
return out.setTo(x * Math.cos(theta) - y * Math.sin(theta) + b.x, x * Math.sin(theta) + y * Math.cos(theta) + b.y);
};
+ Vec2Utils.rotate = /**
+ * Rotate a 2D vector to the given angle (theta).
+ *
+ * @param {Vec2} a Reference to a source Vec2 object.
+ * @param {Vec2} b Reference to a source Vec2 object.
+ * @param {Number} theta The angle of rotation in radians.
+ * @param {Vec2} out The output Vec2 that is the result of the operation.
+ * @return {Vec2} A Vec2.
+ */
+ function rotate(a, theta, out) {
+ if (typeof out === "undefined") { out = new Phaser.Vec2(); }
+ var c = Math.cos(theta);
+ var s = Math.sin(theta);
+ return out.setTo(a.x * c - a.y * s, a.x * s + a.y * c);
+ };
Vec2Utils.clone = /**
* Clone a 2D vector.
*
@@ -17849,28 +17886,6 @@ var Phaser;
Phaser.Line = Line;
})(Phaser || (Phaser = {}));
///
-///
-/**
-* Phaser - 2D Transform
-*
-* A 2D Transform
-*/
-var Phaser;
-(function (Phaser) {
- var Bounds = (function () {
- /**
- * Creates a new 2D AABB object.
- * @class Bounds
- * @constructor
- * @return {Bounds} This object
- **/
- function Bounds(pos, angle) {
- }
- return Bounds;
- })();
- Phaser.Bounds = Bounds;
-})(Phaser || (Phaser = {}));
-///
///
///
/**
@@ -19119,6 +19134,9 @@ var Phaser;
Manager.JOINT_LIMIT_STATE_AT_LOWER = 1;
Manager.JOINT_LIMIT_STATE_AT_UPPER = 2;
Manager.JOINT_LIMIT_STATE_EQUAL_LIMITS = 3;
+ Manager.CONTACT_SOLVER_COLLISION_SLOP = 0.0008;
+ Manager.CONTACT_SOLVER_BAUMGARTE = 0.28;
+ Manager.CONTACT_SOLVER_MAX_LINEAR_CORRECTION = 1;
Manager.bodyCounter = 0;
Manager.jointCounter = 0;
Manager.shapeCounter = 0;
@@ -19134,6 +19152,107 @@ var Phaser;
Manager.m2p = function m2p(value) {
return value * 50;
};
+ Manager.areaForCircle = function areaForCircle(radius_outer, radius_inner) {
+ return Math.PI * (radius_outer * radius_outer - radius_inner * radius_inner);
+ };
+ Manager.inertiaForCircle = function inertiaForCircle(mass, center, radius_outer, radius_inner) {
+ return mass * ((radius_outer * radius_outer + radius_inner * radius_inner) * 0.5 + center.lengthsq());
+ };
+ Manager.areaForSegment = function areaForSegment(a, b, radius) {
+ return radius * (Math.PI * radius + 2 * Phaser.Vec2Utils.distance(a, b));
+ };
+ Manager.centroidForSegment = function centroidForSegment(a, b) {
+ return Phaser.Vec2Utils.scale(Phaser.Vec2Utils.add(a, b), 0.5);
+ };
+ Manager.inertiaForSegment = function inertiaForSegment(mass, a, b) {
+ var distsq = Phaser.Vec2Utils.distanceSq(b, a);
+ var offset = Phaser.Vec2Utils.scale(Phaser.Vec2Utils.add(a, b), 0.5);
+ return mass * (distsq / 12 + offset.lengthSq());
+ };
+ Manager.areaForPoly = function areaForPoly(verts) {
+ var area = 0;
+ for(var i = 0; i < verts.length; i++) {
+ area += Phaser.Vec2Utils.cross(verts[i], verts[(i + 1) % verts.length]);
+ }
+ return area / 2;
+ };
+ Manager.centroidForPoly = function centroidForPoly(verts) {
+ var area = 0;
+ var vsum = new Phaser.Vec2();
+ for(var i = 0; i < verts.length; i++) {
+ var v1 = verts[i];
+ var v2 = verts[(i + 1) % verts.length];
+ var cross = Phaser.Vec2Utils.cross(v1, v2);
+ area += cross;
+ // SO many vecs created here - unroll these bad boys
+ vsum.add(Phaser.Vec2Utils.scale(Phaser.Vec2Utils.add(v1, v2), cross));
+ }
+ return Phaser.Vec2Utils.scale(vsum, 1 / (3 * area));
+ };
+ Manager.inertiaForPoly = function inertiaForPoly(mass, verts, offset) {
+ var sum1 = 0;
+ var sum2 = 0;
+ for(var i = 0; i < verts.length; i++) {
+ var v1 = Phaser.Vec2Utils.add(verts[i], offset);
+ var v2 = Phaser.Vec2Utils.add(verts[(i + 1) % verts.length], offset);
+ var a = Phaser.Vec2Utils.cross(v2, v1);
+ var b = Phaser.Vec2Utils.dot(v1, v1) + Phaser.Vec2Utils.dot(v1, v2) + Phaser.Vec2Utils.dot(v2, v2);
+ sum1 += a * b;
+ sum2 += a;
+ }
+ return (mass * sum1) / (6 * sum2);
+ };
+ Manager.inertiaForBox = function inertiaForBox(mass, w, h) {
+ return mass * (w * w + h * h) / 12;
+ };
+ Manager.createConvexHull = // Create the convex hull using the Gift wrapping algorithm (http://en.wikipedia.org/wiki/Gift_wrapping_algorithm)
+ function createConvexHull(points) {
+ // Find the right most point on the hull
+ var i0 = 0;
+ var x0 = points[0].x;
+ for(var i = 1; i < points.length; i++) {
+ var x = points[i].x;
+ if(x > x0 || (x == x0 && points[i].y < points[i0].y)) {
+ i0 = i;
+ x0 = x;
+ }
+ }
+ var n = points.length;
+ var hull = [];
+ var m = 0;
+ var ih = i0;
+ while(1) {
+ hull[m] = ih;
+ var ie = 0;
+ for(var j = 1; j < n; j++) {
+ if(ie == ih) {
+ ie = j;
+ continue;
+ }
+ var r = Phaser.Vec2Utils.subtract(points[ie], points[hull[m]]);
+ var v = Phaser.Vec2Utils.subtract(points[j], points[hull[m]]);
+ var c = Phaser.Vec2Utils.cross(r, v);
+ if(c < 0) {
+ ie = j;
+ }
+ // Collinearity check
+ if(c == 0 && v.lengthSq() > r.lengthSq()) {
+ ie = j;
+ }
+ }
+ m++;
+ ih = ie;
+ if(ie == i0) {
+ break;
+ }
+ }
+ // Copy vertices
+ var newPoints = [];
+ for(var i = 0; i < m; ++i) {
+ newPoints.push(points[hull[i]]);
+ }
+ return newPoints;
+ };
return Manager;
})();
Advanced.Manager = Manager;
@@ -19667,6 +19786,38 @@ var Phaser;
var Physics = Phaser.Physics;
})(Phaser || (Phaser = {}));
var Phaser;
+(function (Phaser) {
+ (function (Physics) {
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /**
+ * Phaser - Advanced Physics - Contact
+ *
+ * Based on the work Ju Hyung Lee started in JS PhyRus.
+ */
+ (function (Advanced) {
+ var Contact = (function () {
+ function Contact(p, n, d, hash) {
+ this.hash = hash;
+ this.point = p;
+ this.normal = n;
+ this.depth = d;
+ this.lambdaNormal = 0;
+ this.lambdaTangential = 0;
+ }
+ return Contact;
+ })();
+ Advanced.Contact = Contact;
+ })(Physics.Advanced || (Physics.Advanced = {}));
+ var Advanced = Physics.Advanced;
+ })(Phaser.Physics || (Phaser.Physics = {}));
+ var Physics = Phaser.Physics;
+})(Phaser || (Phaser = {}));
+var Phaser;
(function (Phaser) {
(function (Physics) {
///
@@ -19683,9 +19834,58 @@ var Phaser;
(function (Advanced) {
var ShapeCircle = (function (_super) {
__extends(ShapeCircle, _super);
- function ShapeCircle() {
+ function ShapeCircle(radius, x, y) {
+ if (typeof x === "undefined") { x = 0; }
+ if (typeof y === "undefined") { y = 0; }
_super.call(this, Advanced.Manager.SHAPE_TYPE_CIRCLE);
+ this.center = new Phaser.Vec2(x, y);
+ this.radius = radius;
+ this.tc = new Phaser.Vec2();
+ this.finishVerts();
}
+ ShapeCircle.prototype.finishVerts = function () {
+ this.radius = Math.abs(this.radius);
+ };
+ ShapeCircle.prototype.duplicate = function () {
+ return new ShapeCircle(this.center.x, this.center.y, this.radius);
+ };
+ ShapeCircle.prototype.recenter = function (c) {
+ this.center.subtract(c);
+ };
+ ShapeCircle.prototype.transform = function (xf) {
+ this.center = xf.transform(this.center);
+ };
+ ShapeCircle.prototype.untransform = function (xf) {
+ this.center = xf.untransform(this.center);
+ };
+ ShapeCircle.prototype.area = function () {
+ return Advanced.Manager.areaForCircle(this.radius, 0);
+ };
+ ShapeCircle.prototype.centroid = function () {
+ //return this.center.duplicate();
+ };
+ ShapeCircle.prototype.inertia = function (mass) {
+ return Advanced.Manager.inertiaForCircle(mass, this.center, this.radius, 0);
+ };
+ ShapeCircle.prototype.cacheData = function (xf) {
+ this.tc = xf.transform(this.center);
+ this.bounds.mins.set(this.tc.x - this.radius, this.tc.y - this.radius);
+ this.bounds.maxs.set(this.tc.x + this.radius, this.tc.y + this.radius);
+ };
+ ShapeCircle.prototype.pointQuery = function (p) {
+ //return vec2.distsq(this.tc, p) < (this.r * this.r);
+ return Phaser.Vec2Utils.distanceSq(this.tc, p) < (this.radius * this.radius);
+ };
+ ShapeCircle.prototype.findVertexByPoint = function (p, minDist) {
+ var dsq = minDist * minDist;
+ if(Phaser.Vec2Utils.distanceSq(this.tc, p) < dsq) {
+ return 0;
+ }
+ return -1;
+ };
+ ShapeCircle.prototype.distanceOnPlane = function (n, d) {
+ Phaser.Vec2Utils.dot(n, this.tc) - this.radius - d;
+ };
return ShapeCircle;
})(Phaser.Physics.Advanced.Shape);
Advanced.ShapeCircle = ShapeCircle;
@@ -19694,6 +19894,1023 @@ var Phaser;
})(Phaser.Physics || (Phaser.Physics = {}));
var Physics = Phaser.Physics;
})(Phaser || (Phaser = {}));
+var Phaser;
+(function (Phaser) {
+ (function (Physics) {
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /**
+ * Phaser - Advanced Physics - Collision Handlers
+ *
+ * Based on the work Ju Hyung Lee started in JS PhyRus.
+ */
+ (function (Advanced) {
+ var Collision = (function () {
+ function Collision() {
+ }
+ Collision.prototype.collide = function (a, b, contacts) {
+ // Circle (a is the circle)
+ if(a.type == Advanced.Manager.SHAPE_TYPE_CIRCLE) {
+ if(b.type == Advanced.Manager.SHAPE_TYPE_CIRCLE) {
+ return this.circle2Circle(a, b, contacts);
+ } else if(b.type == Advanced.Manager.SHAPE_TYPE_SEGMENT) {
+ return this.circle2Segment(a, b, contacts);
+ } else if(b.type == Advanced.Manager.SHAPE_TYPE_POLY) {
+ return this.circle2Poly(a, b, contacts);
+ }
+ }
+ // Segment (a is the segment)
+ if(a.type == Advanced.Manager.SHAPE_TYPE_SEGMENT) {
+ if(b.type == Advanced.Manager.SHAPE_TYPE_CIRCLE) {
+ return this.circle2Segment(b, a, contacts);
+ } else if(b.type == Advanced.Manager.SHAPE_TYPE_SEGMENT) {
+ return this.segment2Segment(a, b, contacts);
+ } else if(b.type == Advanced.Manager.SHAPE_TYPE_POLY) {
+ return this.segment2Poly(a, b, contacts);
+ }
+ }
+ // Poly (a is the poly)
+ if(a.type == Advanced.Manager.SHAPE_TYPE_POLY) {
+ if(b.type == Advanced.Manager.SHAPE_TYPE_CIRCLE) {
+ return this.circle2Poly(b, a, contacts);
+ } else if(b.type == Advanced.Manager.SHAPE_TYPE_SEGMENT) {
+ return this.segment2Poly(b, a, contacts);
+ } else if(b.type == Advanced.Manager.SHAPE_TYPE_POLY) {
+ return this.poly2Poly(a, b, contacts);
+ }
+ }
+ };
+ Collision.prototype._circle2Circle = function (c1, r1, c2, r2, contactArr) {
+ var rmax = r1 + r2;
+ var t = new Phaser.Vec2();
+ //var t = vec2.sub(c2, c1);
+ Phaser.Vec2Utils.subtract(c2, c1, t);
+ var distsq = t.lengthSq();
+ if(distsq > rmax * rmax) {
+ return 0;
+ }
+ var dist = Math.sqrt(distsq);
+ var p = new Phaser.Vec2();
+ Phaser.Vec2Utils.multiplyAdd(c1, t, 0.5 + (r1 - r2) * 0.5 / dist, p);
+ //var p = vec2.mad(c1, t, 0.5 + (r1 - r2) * 0.5 / dist);
+ var n = new Phaser.Vec2();
+ //var n = (dist != 0) ? vec2.scale(t, 1 / dist) : vec2.zero;
+ if(dist != 0) {
+ Phaser.Vec2Utils.scale(t, 1 / dist, n);
+ }
+ var d = dist - rmax;
+ contactArr.push(new Advanced.Contact(p, n, d, 0));
+ return 1;
+ };
+ Collision.prototype.circle2Circle = function (circ1, circ2, contactArr) {
+ return this._circle2Circle(circ1.tc, circ1.r, circ2.tc, circ2.r, contactArr);
+ };
+ Collision.prototype.circle2Segment = function (circ, seg, contactArr) {
+ var rsum = circ.radius + seg.r;
+ // Normal distance from segment
+ var dn = Phaser.Vec2Utils.dot(circ.tc, seg.tn) - Phaser.Vec2Utils.dot(seg.ta, seg.tn);
+ var dist = (dn < 0 ? dn * -1 : dn) - rsum;
+ if(dist > 0) {
+ return 0;
+ }
+ // Tangential distance along segment
+ var dt = Phaser.Vec2Utils.cross(circ.tc, seg.tn);
+ var dtMin = Phaser.Vec2Utils.cross(seg.ta, seg.tn);
+ var dtMax = Phaser.Vec2Utils.cross(seg.tb, seg.tn);
+ if(dt < dtMin) {
+ if(dt < dtMin - rsum) {
+ return 0;
+ }
+ return this._circle2Circle(circ.tc, circ.radius, seg.ta, seg.r, contactArr);
+ } else if(dt > dtMax) {
+ if(dt > dtMax + rsum) {
+ return 0;
+ }
+ return this._circle2Circle(circ.tc, circ.radius, seg.tb, seg.r, contactArr);
+ }
+ var n = new Phaser.Vec2();
+ if(dn > 0) {
+ n.copyFrom(seg.tn);
+ } else {
+ Phaser.Vec2Utils.negative(seg.tn, n);
+ }
+ //var n = (dn > 0) ? seg.tn : vec2.neg(seg.tn);
+ var c1 = new Phaser.Vec2();
+ Phaser.Vec2Utils.multiplyAdd(circ.tc, n, -(circ.radius + dist * 0.5), c1);
+ var c2 = new Phaser.Vec2();
+ Phaser.Vec2Utils.negative(n, c2);
+ contactArr.push(new Advanced.Contact(c1, c2, dist, 0));
+ //contactArr.push(new Contact(vec2.mad(circ.tc, n, -(circ.r + dist * 0.5)), vec2.neg(n), dist, 0));
+ return 1;
+ };
+ Collision.prototype.circle2Poly = function (circ, poly, contactArr) {
+ var minDist = -999999;
+ var minIdx = -1;
+ for(var i = 0; i < poly.verts.length; i++) {
+ var plane = poly.tplanes[i];
+ var dist = Phaser.Vec2Utils.dot(circ.tc, plane.n) - plane.d - circ.radius;
+ if(dist > 0) {
+ return 0;
+ } else if(dist > minDist) {
+ minDist = dist;
+ minIdx = i;
+ }
+ }
+ var n = poly.tplanes[minIdx].n;
+ var a = poly.tverts[minIdx];
+ var b = poly.tverts[(minIdx + 1) % poly.verts.length];
+ var dta = Phaser.Vec2Utils.cross(a, n);
+ var dtb = Phaser.Vec2Utils.cross(b, n);
+ var dt = Phaser.Vec2Utils.cross(circ.tc, n);
+ if(dt > dta) {
+ return this._circle2Circle(circ.tc, circ.radius, a, 0, contactArr);
+ } else if(dt < dtb) {
+ return this._circle2Circle(circ.tc, circ.radius, b, 0, contactArr);
+ }
+ var c1 = new Phaser.Vec2();
+ Phaser.Vec2Utils.multiplyAdd(circ.tc, n, -(circ.radius + minDist * 0.5), c1);
+ var c2 = new Phaser.Vec2();
+ Phaser.Vec2Utils.negative(n, c2);
+ contactArr.push(new Advanced.Contact(c1, c2, minDist, 0));
+ //contactArr.push(new Contact(vec2.mad(circ.tc, n, -(circ.r + minDist * 0.5)), vec2.neg(n), minDist, 0));
+ return 1;
+ };
+ Collision.prototype.segmentPointDistanceSq = function (seg, p) {
+ var w = new Phaser.Vec2();
+ var d = new Phaser.Vec2();
+ Phaser.Vec2Utils.subtract(p, seg.ta, w);
+ Phaser.Vec2Utils.subtract(seg.tb, seg.ta, d);
+ //var w = vec2.sub(p, seg.ta);
+ //var d = vec2.sub(seg.tb, seg.ta);
+ var proj = w.dot(d);
+ if(proj <= 0) {
+ return w.dot(w);
+ }
+ var vsq = d.dot(d);
+ if(proj >= vsq) {
+ return w.dot(w) - 2 * proj + vsq;
+ }
+ return w.dot(w) - proj * proj / vsq;
+ };
+ Collision.prototype.segment2Segment = // FIXME and optimise me lots!!!
+ function (seg1, seg2, contactArr) {
+ var d = [];
+ d[0] = this.segmentPointDistanceSq(seg1, seg2.ta);
+ d[1] = this.segmentPointDistanceSq(seg1, seg2.tb);
+ d[2] = this.segmentPointDistanceSq(seg2, seg1.ta);
+ d[3] = this.segmentPointDistanceSq(seg2, seg1.tb);
+ var idx1 = d[0] < d[1] ? 0 : 1;
+ var idx2 = d[2] < d[3] ? 2 : 3;
+ var idxm = d[idx1] < d[idx2] ? idx1 : idx2;
+ var s, t;
+ var u = Phaser.Vec2Utils.subtract(seg1.tb, seg1.ta);
+ var v = Phaser.Vec2Utils.subtract(seg2.tb, seg2.ta);
+ switch(idxm) {
+ case 0:
+ s = Phaser.Vec2Utils.dot(Phaser.Vec2Utils.subtract(seg2.ta, seg1.ta), u) / Phaser.Vec2Utils.dot(u, u);
+ s = s < 0 ? 0 : (s > 1 ? 1 : s);
+ t = 0;
+ break;
+ case 1:
+ s = Phaser.Vec2Utils.dot(Phaser.Vec2Utils.subtract(seg2.tb, seg1.ta), u) / Phaser.Vec2Utils.dot(u, u);
+ s = s < 0 ? 0 : (s > 1 ? 1 : s);
+ t = 1;
+ break;
+ case 2:
+ s = 0;
+ t = Phaser.Vec2Utils.dot(Phaser.Vec2Utils.subtract(seg1.ta, seg2.ta), v) / Phaser.Vec2Utils.dot(v, v);
+ t = t < 0 ? 0 : (t > 1 ? 1 : t);
+ break;
+ case 3:
+ s = 1;
+ t = Phaser.Vec2Utils.dot(Phaser.Vec2Utils.subtract(seg1.tb, seg2.ta), v) / Phaser.Vec2Utils.dot(v, v);
+ t = t < 0 ? 0 : (t > 1 ? 1 : t);
+ break;
+ }
+ var minp1 = Phaser.Vec2Utils.multiplyAdd(seg1.ta, u, s);
+ var minp2 = Phaser.Vec2Utils.multiplyAdd(seg2.ta, v, t);
+ return this._circle2Circle(minp1, seg1.r, minp2, seg2.r, contactArr);
+ };
+ Collision.prototype.findPointsBehindSeg = // Identify vertexes that have penetrated the segment.
+ function (contactArr, seg, poly, dist, coef) {
+ var dta = Phaser.Vec2Utils.cross(seg.tn, seg.ta);
+ var dtb = Phaser.Vec2Utils.cross(seg.tn, seg.tb);
+ var n = new Phaser.Vec2();
+ Phaser.Vec2Utils.scale(seg.tn, coef, n);
+ //var n = vec2.scale(seg.tn, coef);
+ for(var i = 0; i < poly.verts.length; i++) {
+ var v = poly.tverts[i];
+ if(Phaser.Vec2Utils.dot(v, n) < Phaser.Vec2Utils.dot(seg.tn, seg.ta) * coef + seg.r) {
+ var dt = Phaser.Vec2Utils.cross(seg.tn, v);
+ if(dta >= dt && dt >= dtb) {
+ contactArr.push(new Advanced.Contact(v, n, dist, (poly.id << 16) | i));
+ }
+ }
+ }
+ };
+ Collision.prototype.segment2Poly = function (seg, poly, contactArr) {
+ var seg_td = Phaser.Vec2Utils.dot(seg.tn, seg.ta);
+ var seg_d1 = poly.distanceOnPlane(seg.tn, seg_td) - seg.r;
+ if(seg_d1 > 0) {
+ return 0;
+ }
+ var n = new Phaser.Vec2();
+ Phaser.Vec2Utils.negative(seg.tn, n);
+ var seg_d2 = poly.distanceOnPlane(n, -seg_td) - seg.r;
+ //var seg_d2 = poly.distanceOnPlane(vec2.neg(seg.tn), -seg_td) - seg.r;
+ if(seg_d2 > 0) {
+ return 0;
+ }
+ var poly_d = -999999;
+ var poly_i = -1;
+ for(var i = 0; i < poly.verts.length; i++) {
+ var plane = poly.tplanes[i];
+ var dist = seg.distanceOnPlane(plane.n, plane.d);
+ if(dist > 0) {
+ return 0;
+ }
+ if(dist > poly_d) {
+ poly_d = dist;
+ poly_i = i;
+ }
+ }
+ var poly_n = new Phaser.Vec2();
+ Phaser.Vec2Utils.negative(poly.tplanes[poly_i].n, poly_n);
+ //var poly_n = vec2.neg(poly.tplanes[poly_i].n);
+ var va = new Phaser.Vec2();
+ Phaser.Vec2Utils.multiplyAdd(seg.ta, poly_n, seg.r, va);
+ //var va = vec2.mad(seg.ta, poly_n, seg.r);
+ var vb = new Phaser.Vec2();
+ Phaser.Vec2Utils.multiplyAdd(seg.tb, poly_n, seg.r, vb);
+ //var vb = vec2.mad(seg.tb, poly_n, seg.r);
+ if(poly.containPoint(va)) {
+ contactArr.push(new Advanced.Contact(va, poly_n, poly_d, (seg.id << 16) | 0));
+ }
+ if(poly.containPoint(vb)) {
+ contactArr.push(new Advanced.Contact(vb, poly_n, poly_d, (seg.id << 16) | 1));
+ }
+ // Floating point precision problems here.
+ // This will have to do for now.
+ poly_d -= 0.1;
+ if(seg_d1 >= poly_d || seg_d2 >= poly_d) {
+ if(seg_d1 > seg_d2) {
+ this.findPointsBehindSeg(contactArr, seg, poly, seg_d1, 1);
+ } else {
+ this.findPointsBehindSeg(contactArr, seg, poly, seg_d2, -1);
+ }
+ }
+ // If no other collision points are found, try colliding endpoints.
+ if(contactArr.length == 0) {
+ var poly_a = poly.tverts[poly_i];
+ var poly_b = poly.tverts[(poly_i + 1) % poly.verts.length];
+ if(this._circle2Circle(seg.ta, seg.r, poly_a, 0, contactArr)) {
+ return 1;
+ }
+ if(this._circle2Circle(seg.tb, seg.r, poly_a, 0, contactArr)) {
+ return 1;
+ }
+ if(this._circle2Circle(seg.ta, seg.r, poly_b, 0, contactArr)) {
+ return 1;
+ }
+ if(this._circle2Circle(seg.tb, seg.r, poly_b, 0, contactArr)) {
+ return 1;
+ }
+ }
+ return contactArr.length;
+ };
+ Collision.prototype.findMSA = // Find the minimum separating axis for the given poly and plane list.
+ function (poly, planes, num) {
+ var min_dist = -999999;
+ var min_index = -1;
+ for(var i = 0; i < num; i++) {
+ var dist = poly.distanceOnPlane(planes[i].n, planes[i].d);
+ if(dist > 0) {
+ // no collision
+ return {
+ dist: 0,
+ index: -1
+ };
+ } else if(dist > min_dist) {
+ min_dist = dist;
+ min_index = i;
+ }
+ }
+ // new object - see what we can do here
+ return {
+ dist: min_dist,
+ index: min_index
+ };
+ };
+ Collision.prototype.findVertsFallback = function (contactArr, poly1, poly2, n, dist) {
+ var num = 0;
+ for(var i = 0; i < poly1.verts.length; i++) {
+ var v = poly1.tverts[i];
+ if(poly2.containPointPartial(v, n)) {
+ contactArr.push(new Advanced.Contact(v, n, dist, (poly1.id << 16) | i));
+ num++;
+ }
+ }
+ for(var i = 0; i < poly2.verts.length; i++) {
+ var v = poly2.tverts[i];
+ if(poly1.containPointPartial(v, n)) {
+ contactArr.push(new Advanced.Contact(v, n, dist, (poly2.id << 16) | i));
+ num++;
+ }
+ }
+ return num;
+ };
+ Collision.prototype.findVerts = // Find the overlapped vertices.
+ function (contactArr, poly1, poly2, n, dist) {
+ var num = 0;
+ for(var i = 0; i < poly1.verts.length; i++) {
+ var v = poly1.tverts[i];
+ if(poly2.containPoint(v)) {
+ contactArr.push(new Advanced.Contact(v, n, dist, (poly1.id << 16) | i));
+ num++;
+ }
+ }
+ for(var i = 0; i < poly2.verts.length; i++) {
+ var v = poly2.tverts[i];
+ if(poly1.containPoint(v)) {
+ contactArr.push(new Advanced.Contact(v, n, dist, (poly2.id << 16) | i));
+ num++;
+ }
+ }
+ return num > 0 ? num : this.findVertsFallback(contactArr, poly1, poly2, n, dist);
+ };
+ Collision.prototype.poly2Poly = function (poly1, poly2, contactArr) {
+ var msa1 = this.findMSA(poly2, poly1.tplanes, poly1.verts.length);
+ if(msa1.index == -1) {
+ return 0;
+ }
+ var msa2 = this.findMSA(poly1, poly2.tplanes, poly2.verts.length);
+ if(msa2.index == -1) {
+ return 0;
+ }
+ // Penetration normal direction shoud be from poly1 to poly2
+ if(msa1.dist > msa2.dist) {
+ return this.findVerts(contactArr, poly1, poly2, poly1.tplanes[msa1.index].n, msa1.dist);
+ }
+ return this.findVerts(contactArr, poly1, poly2, Phaser.Vec2Utils.negative(poly2.tplanes[msa2.index].n), msa2.dist);
+ };
+ return Collision;
+ })();
+ Advanced.Collision = Collision;
+ })(Physics.Advanced || (Physics.Advanced = {}));
+ var Advanced = Physics.Advanced;
+ })(Phaser.Physics || (Phaser.Physics = {}));
+ var Physics = Phaser.Physics;
+})(Phaser || (Phaser = {}));
+var Phaser;
+(function (Phaser) {
+ (function (Physics) {
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /**
+ * Phaser - Advanced Physics - ContactSolver
+ *
+ * Based on the work Ju Hyung Lee started in JS PhyRus.
+ */
+ //-------------------------------------------------------------------------------------------------
+ // Contact Constraint
+ //
+ // Non-penetration constraint:
+ // C = dot(p2 - p1, n)
+ // Cdot = dot(v2 - v1, n)
+ // J = [ -n, -cross(r1, n), n, cross(r2, n) ]
+ //
+ // impulse = JT * lambda = [ -n * lambda, -cross(r1, n) * lambda, n * lambda, cross(r1, n) * lambda ]
+ //
+ // Friction constraint:
+ // C = dot(p2 - p1, t)
+ // Cdot = dot(v2 - v1, t)
+ // J = [ -t, -cross(r1, t), t, cross(r2, t) ]
+ //
+ // impulse = JT * lambda = [ -t * lambda, -cross(r1, t) * lambda, t * lambda, cross(r1, t) * lambda ]
+ //
+ // NOTE: lambda is an impulse in constraint space.
+ //-------------------------------------------------------------------------------------------------
+ (function (Advanced) {
+ var ContactSolver = (function () {
+ function ContactSolver(shape1, shape2) {
+ this.shape1 = shape1;
+ this.shape2 = shape2;
+ this.contacts = [];
+ this.elasticity = 1;
+ this.friction = 1;
+ }
+ ContactSolver.prototype.update = function (newContactArr) {
+ for(var i = 0; i < newContactArr.length; i++) {
+ var newContact = newContactArr[i];
+ var k = -1;
+ for(var j = 0; j < this.contacts.length; j++) {
+ if(newContact.hash == this.contacts[j].hash) {
+ k = j;
+ break;
+ }
+ }
+ if(k > -1) {
+ newContact.lambdaNormal = this.contacts[k].lambdaNormal;
+ newContact.lambdaTangential = this.contacts[k].lambdaTangential;
+ }
+ }
+ this.contacts = newContactArr;
+ };
+ ContactSolver.prototype.initSolver = function (dt_inv) {
+ var body1 = this.shape1.body;
+ var body2 = this.shape2.body;
+ var sum_m_inv = body1.massInverted + body2.massInverted;
+ for(var i = 0; i < this.contacts.length; i++) {
+ var con = this.contacts[i];
+ // Transformed r1, r2
+ Phaser.Vec2Utils.subtract(con.point, body1.position, con.r1);
+ Phaser.Vec2Utils.subtract(con.point, body2.position, con.r2);
+ //con.r1 = vec2.sub(con.point, body1.p);
+ //con.r2 = vec2.sub(con.point, body2.p);
+ // Local r1, r2
+ con.r1_local = body1.transform.unrotate(con.r1);
+ con.r2_local = body2.transform.unrotate(con.r2);
+ var n = con.normal;
+ var t = Phaser.Vec2Utils.perp(con.normal);
+ // invEMn = J * invM * JT
+ // J = [ -n, -cross(r1, n), n, cross(r2, n) ]
+ var sn1 = Phaser.Vec2Utils.cross(con.r1, n);
+ var sn2 = Phaser.Vec2Utils.cross(con.r2, n);
+ var emn_inv = sum_m_inv + body1.inertiaInverted * sn1 * sn1 + body2.inertiaInverted * sn2 * sn2;
+ con.emn = emn_inv == 0 ? 0 : 1 / emn_inv;
+ // invEMt = J * invM * JT
+ // J = [ -t, -cross(r1, t), t, cross(r2, t) ]
+ var st1 = Phaser.Vec2Utils.cross(con.r1, t);
+ var st2 = Phaser.Vec2Utils.cross(con.r2, t);
+ var emt_inv = sum_m_inv + body1.inertiaInverted * st1 * st1 + body2.inertiaInverted * st2 * st2;
+ con.emt = emt_inv == 0 ? 0 : 1 / emt_inv;
+ // Linear velocities at contact point
+ // in 2D: cross(w, r) = perp(r) * w
+ var v1 = new Phaser.Vec2();
+ var v2 = new Phaser.Vec2();
+ Phaser.Vec2Utils.multiplyAdd(body1.velocity, Phaser.Vec2Utils.perp(con.r1), body1.angularVelocity, v1);
+ Phaser.Vec2Utils.multiplyAdd(body2.velocity, Phaser.Vec2Utils.perp(con.r2), body2.angularVelocity, v2);
+ //var v1 = vec2.mad(body1.v, vec2.perp(con.r1), body1.w);
+ //var v2 = vec2.mad(body2.v, vec2.perp(con.r2), body2.w);
+ // relative velocity at contact point
+ var rv = new Phaser.Vec2();
+ Phaser.Vec2Utils.subtract(v2, v1, rv);
+ //var rv = vec2.sub(v2, v1);
+ // bounce velocity dot n
+ con.bounce = Phaser.Vec2Utils.dot(rv, con.normal) * this.elasticity;
+ }
+ };
+ ContactSolver.prototype.warmStart = function () {
+ var body1 = this.shape1.body;
+ var body2 = this.shape2.body;
+ for(var i = 0; i < this.contacts.length; i++) {
+ var con = this.contacts[i];
+ var n = con.normal;
+ var lambda_n = con.lambdaNormal;
+ var lambda_t = con.lambdaTangential;
+ // Apply accumulated impulses
+ //var impulse = vec2.rotate_vec(new vec2(lambda_n, lambda_t), n);
+ //var impulse = new vec2(lambda_n * n.x - lambda_t * n.y, lambda_t * n.x + lambda_n * n.y);
+ var impulse = new Phaser.Vec2(lambda_n * n.x - lambda_t * n.y, lambda_t * n.x + lambda_n * n.y);
+ body1.velocity.multiplyAddByScalar(impulse, -body1.massInverted);
+ //body1.v.mad(impulse, -body1.m_inv);
+ body1.angularVelocity -= Phaser.Vec2Utils.cross(con.r1, impulse) * body1.inertiaInverted;
+ //body1.w -= vec2.cross(con.r1, impulse) * body1.i_inv;
+ body2.velocity.multiplyAddByScalar(impulse, -body2.massInverted);
+ //body2.v.mad(impulse, body2.m_inv);
+ body2.angularVelocity -= Phaser.Vec2Utils.cross(con.r2, impulse) * body2.inertiaInverted;
+ //body2.w += vec2.cross(con.r2, impulse) * body2.i_inv;
+ }
+ };
+ ContactSolver.prototype.solveVelocityConstraints = function () {
+ var body1 = this.shape1.body;
+ var body2 = this.shape2.body;
+ var m1_inv = body1.massInverted;
+ var i1_inv = body1.inertiaInverted;
+ var m2_inv = body2.massInverted;
+ var i2_inv = body2.inertiaInverted;
+ for(var i = 0; i < this.contacts.length; i++) {
+ var con = this.contacts[i];
+ var n = con.normal;
+ var t = Phaser.Vec2Utils.perp(n);
+ var r1 = con.r1;
+ var r2 = con.r2;
+ // Linear velocities at contact point
+ // in 2D: cross(w, r) = perp(r) * w
+ var v1 = new Phaser.Vec2();
+ var v2 = new Phaser.Vec2();
+ Phaser.Vec2Utils.multiplyAdd(body1.velocity, Phaser.Vec2Utils.perp(r1), body1.angularVelocity, v1);
+ //var v1 = vec2.mad(body1.v, vec2.perp(r1), body1.w);
+ Phaser.Vec2Utils.multiplyAdd(body2.velocity, Phaser.Vec2Utils.perp(r2), body2.angularVelocity, v2);
+ //var v2 = vec2.mad(body2.v, vec2.perp(r2), body2.w);
+ // Relative velocity at contact point
+ var rv = new Phaser.Vec2();
+ Phaser.Vec2Utils.subtract(v2, v1, rv);
+ //var rv = vec2.sub(v2, v1);
+ // Compute normal constraint impulse + adding bounce as a velocity bias
+ // lambda_n = -EMn * J * V
+ var lambda_n = -con.emn * (Phaser.Vec2Utils.dot(n, rv) + con.bounce);
+ // Accumulate and clamp
+ var lambda_n_old = con.lambdaNormal;
+ con.lambdaNormal = Math.max(lambda_n_old + lambda_n, 0);
+ lambda_n = con.lambdaNormal - lambda_n_old;
+ // Compute frictional constraint impulse
+ // lambda_t = -EMt * J * V
+ var lambda_t = -con.emt * Phaser.Vec2Utils.dot(t, rv);
+ // Max friction constraint impulse (Coulomb's Law)
+ var lambda_t_max = con.lambdaNormal * this.friction;
+ // Accumulate and clamp
+ var lambda_t_old = con.lambdaTangential;
+ con.lambdaTangential = this.clamp(lambda_t_old + lambda_t, -lambda_t_max, lambda_t_max);
+ lambda_t = con.lambdaTangential - lambda_t_old;
+ // Apply the final impulses
+ //var impulse = vec2.rotate_vec(new vec2(lambda_n, lambda_t), n);
+ var impulse = new Phaser.Vec2(lambda_n * n.x - lambda_t * n.y, lambda_t * n.x + lambda_n * n.y);
+ body1.velocity.multiplyAddByScalar(impulse, -m1_inv);
+ //body1.v.mad(impulse, -m1_inv);
+ body1.angularVelocity -= Phaser.Vec2Utils.cross(r1, impulse) * i1_inv;
+ //body1.w -= vec2.cross(r1, impulse) * i1_inv;
+ body2.velocity.multiplyAddByScalar(impulse, m2_inv);
+ //body2.v.mad(impulse, m2_inv);
+ body1.angularVelocity += Phaser.Vec2Utils.cross(r2, impulse) * i2_inv;
+ //body2.w += vec2.cross(r2, impulse) * i2_inv;
+ }
+ };
+ ContactSolver.prototype.solvePositionConstraints = function () {
+ var body1 = this.shape1.body;
+ var body2 = this.shape2.body;
+ var m1_inv = body1.massInverted;
+ var i1_inv = body1.inertiaInverted;
+ var m2_inv = body2.massInverted;
+ var i2_inv = body2.inertiaInverted;
+ var sum_m_inv = m1_inv + m2_inv;
+ var max_penetration = 0;
+ for(var i = 0; i < this.contacts.length; i++) {
+ var con = this.contacts[i];
+ var n = con.normal;
+ var r1 = new Phaser.Vec2();
+ var r2 = new Phaser.Vec2();
+ // Transformed r1, r2
+ Phaser.Vec2Utils.rotate(con.r1_local, body1.angle, r1);
+ //var r1 = vec2.rotate(con.r1_local, body1.a);
+ Phaser.Vec2Utils.rotate(con.r2_local, body2.angle, r2);
+ //var r2 = vec2.rotate(con.r2_local, body2.a);
+ // Contact points (corrected)
+ var p1 = new Phaser.Vec2();
+ var p2 = new Phaser.Vec2();
+ Phaser.Vec2Utils.add(body1.position, r1, p1);
+ //var p1 = vec2.add(body1.p, r1);
+ Phaser.Vec2Utils.add(body2.position, r2, p2);
+ //var p2 = vec2.add(body2.p, r2);
+ // Corrected delta vector
+ var dp = new Phaser.Vec2();
+ Phaser.Vec2Utils.subtract(p2, p1);
+ //var dp = vec2.sub(p2, p1);
+ // Position constraint
+ var c = Phaser.Vec2Utils.dot(dp, n) + con.depth;
+ var correction = this.clamp(Advanced.Manager.CONTACT_SOLVER_BAUMGARTE * (c + Advanced.Manager.CONTACT_SOLVER_COLLISION_SLOP), -Advanced.Manager.CONTACT_SOLVER_MAX_LINEAR_CORRECTION, 0);
+ if(correction == 0) {
+ continue;
+ }
+ // We don't need max_penetration less than or equal slop
+ max_penetration = Math.max(max_penetration, -c);
+ // Compute lambda for position constraint
+ // Solve (J * invM * JT) * lambda = -C / dt
+ var sn1 = Phaser.Vec2Utils.cross(r1, n);
+ var sn2 = Phaser.Vec2Utils.cross(r2, n);
+ var em_inv = sum_m_inv + body1.inertiaInverted * sn1 * sn1 + body2.inertiaInverted * sn2 * sn2;
+ var lambda_dt = em_inv == 0 ? 0 : -correction / em_inv;
+ // Apply correction impulses
+ var impulse_dt = new Phaser.Vec2();
+ Phaser.Vec2Utils.scale(n, lambda_dt, impulse_dt);
+ //var impulse_dt = vec2.scale(n, lambda_dt);
+ body1.position.multiplyAddByScalar(impulse_dt, -m1_inv);
+ //body1.p.mad(impulse_dt, -m1_inv);
+ body1.angle -= sn1 * lambda_dt * i1_inv;
+ body2.position.multiplyAddByScalar(impulse_dt, m2_inv);
+ //body2.p.mad(impulse_dt, m2_inv);
+ body2.angle += sn2 * lambda_dt * i2_inv;
+ }
+ return max_penetration <= Advanced.Manager.CONTACT_SOLVER_COLLISION_SLOP * 3;
+ };
+ ContactSolver.prototype.clamp = function (v, min, max) {
+ return v < min ? min : (v > max ? max : v);
+ };
+ return ContactSolver;
+ })();
+ Advanced.ContactSolver = ContactSolver;
+ })(Physics.Advanced || (Physics.Advanced = {}));
+ var Advanced = Physics.Advanced;
+ })(Phaser.Physics || (Phaser.Physics = {}));
+ var Physics = Phaser.Physics;
+})(Phaser || (Phaser = {}));
+var Phaser;
+(function (Phaser) {
+ (function (Physics) {
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /**
+ * Phaser - Advanced Physics - ShapePoly (convex only)
+ *
+ * Based on the work Ju Hyung Lee started in JS PhyRus.
+ */
+ (function (Advanced) {
+ var ShapePoly = (function (_super) {
+ __extends(ShapePoly, _super);
+ function ShapePoly(verts) {
+ _super.call(this, Advanced.Manager.SHAPE_TYPE_POLY);
+ this.verts = [];
+ this.planes = [];
+ this.tverts = [];
+ this.tplanes = [];
+ if(verts) {
+ for(var i = 0; i < verts.length; i++) {
+ Phaser.Vec2Utils.clone(verts[i], this.verts[i]);
+ this.tverts[i] = this.verts[i];
+ this.tplanes[i] = {
+ };
+ this.tplanes[i].n = new Phaser.Vec2();
+ this.tplanes[i].d = 0;
+ }
+ }
+ this.finishVerts();
+ }
+ ShapePoly.prototype.finishVerts = function () {
+ if(this.verts.length < 2) {
+ this.convexity = false;
+ this.planes = [];
+ return;
+ }
+ this.convexity = true;
+ this.tverts = [];
+ this.tplanes = [];
+ // Must be counter-clockwise verts
+ for(var i = 0; i < this.verts.length; i++) {
+ var a = this.verts[i];
+ var b = this.verts[(i + 1) % this.verts.length];
+ var n = Phaser.Vec2Utils.normalize(Phaser.Vec2Utils.perp(Phaser.Vec2Utils.subtract(a, b)));
+ this.planes[i] = {
+ };
+ this.planes[i].n = n;
+ this.planes[i].d = Phaser.Vec2Utils.dot(n, a);
+ this.tverts[i] = this.verts[i];
+ this.tplanes[i] = {
+ };
+ this.tplanes[i].n = new Phaser.Vec2();
+ this.tplanes[i].d = 0;
+ }
+ for(var i = 0; i < this.verts.length; i++) {
+ var b = this.verts[(i + 2) % this.verts.length];
+ var n = this.planes[i].n;
+ var d = this.planes[i].d;
+ if(Phaser.Vec2Utils.dot(n, b) - d > 0) {
+ this.convexity = false;
+ }
+ }
+ };
+ ShapePoly.prototype.duplicate = function () {
+ return new ShapePoly(this.verts);
+ };
+ ShapePoly.prototype.recenter = function (c) {
+ for(var i = 0; i < this.verts.length; i++) {
+ this.verts[i].subtract(c);
+ }
+ };
+ ShapePoly.prototype.transform = function (xf) {
+ for(var i = 0; i < this.verts.length; i++) {
+ this.verts[i] = xf.transform(this.verts[i]);
+ }
+ };
+ ShapePoly.prototype.untransform = function (xf) {
+ for(var i = 0; i < this.verts.length; i++) {
+ this.verts[i] = xf.untransform(this.verts[i]);
+ }
+ };
+ ShapePoly.prototype.area = function () {
+ return Advanced.Manager.areaForPoly(this.verts);
+ };
+ ShapePoly.prototype.centroid = function () {
+ return Advanced.Manager.centroidForPoly(this.verts);
+ };
+ ShapePoly.prototype.inertia = function (mass) {
+ return Advanced.Manager.inertiaForPoly(mass, this.verts, new Phaser.Vec2());
+ };
+ ShapePoly.prototype.cacheData = function (xf) {
+ this.bounds.clear();
+ var numVerts = this.verts.length;
+ if(numVerts == 0) {
+ return;
+ }
+ for(var i = 0; i < numVerts; i++) {
+ this.tverts[i] = xf.transform(this.verts[i]);
+ }
+ if(numVerts < 2) {
+ this.bounds.addPoint(this.tverts[0]);
+ return;
+ }
+ for(var i = 0; i < numVerts; i++) {
+ var a = this.tverts[i];
+ var b = this.tverts[(i + 1) % numVerts];
+ var n = Phaser.Vec2Utils.normalize(Phaser.Vec2Utils.perp(Phaser.Vec2Utils.subtract(a, b)));
+ this.tplanes[i].n = n;
+ this.tplanes[i].d = Phaser.Vec2Utils.dot(n, a);
+ this.bounds.addPoint(a);
+ }
+ };
+ ShapePoly.prototype.pointQuery = function (p) {
+ if(!this.bounds.containPoint(p)) {
+ return false;
+ }
+ return this.containPoint(p);
+ };
+ ShapePoly.prototype.findVertexByPoint = function (p, minDist) {
+ var dsq = minDist * minDist;
+ for(var i = 0; i < this.tverts.length; i++) {
+ if(Phaser.Vec2Utils.distanceSq(this.tverts[i], p) < dsq) {
+ return i;
+ }
+ }
+ return -1;
+ };
+ ShapePoly.prototype.findEdgeByPoint = function (p, minDist) {
+ var dsq = minDist * minDist;
+ var numVerts = this.tverts.length;
+ for(var i = 0; i < this.tverts.length; i++) {
+ var v1 = this.tverts[i];
+ var v2 = this.tverts[(i + 1) % numVerts];
+ var n = this.tplanes[i].n;
+ var dtv1 = Phaser.Vec2Utils.cross(v1, n);
+ var dtv2 = Phaser.Vec2Utils.cross(v2, n);
+ var dt = Phaser.Vec2Utils.cross(p, n);
+ if(dt > dtv1) {
+ if(Phaser.Vec2Utils.distanceSq(v1, p) < dsq) {
+ return i;
+ }
+ } else if(dt < dtv2) {
+ if(Phaser.Vec2Utils.distanceSq(v2, p) < dsq) {
+ return i;
+ }
+ } else {
+ var dist = Phaser.Vec2Utils.dot(n, p) - Phaser.Vec2Utils.dot(n, v1);
+ if(dist * dist < dsq) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ };
+ ShapePoly.prototype.distanceOnPlane = function (n, d) {
+ var min = 999999;
+ for(var i = 0; i < this.verts.length; i++) {
+ min = Math.min(min, Phaser.Vec2Utils.dot(n, this.tverts[i]));
+ }
+ return min - d;
+ };
+ ShapePoly.prototype.containPoint = function (p) {
+ for(var i = 0; i < this.verts.length; i++) {
+ var plane = this.tplanes[i];
+ if(Phaser.Vec2Utils.dot(plane.n, p) - plane.d > 0) {
+ return false;
+ }
+ }
+ return true;
+ };
+ ShapePoly.prototype.containPointPartial = function (p, n) {
+ for(var i = 0; i < this.verts.length; i++) {
+ var plane = this.tplanes[i];
+ if(Phaser.Vec2Utils.dot(plane.n, n) < 0.0001) {
+ continue;
+ }
+ if(Phaser.Vec2Utils.dot(plane.n, p) - plane.d > 0) {
+ return false;
+ }
+ }
+ return true;
+ };
+ return ShapePoly;
+ })(Phaser.Physics.Advanced.Shape);
+ Advanced.ShapePoly = ShapePoly;
+ })(Physics.Advanced || (Physics.Advanced = {}));
+ var Advanced = Physics.Advanced;
+ })(Phaser.Physics || (Phaser.Physics = {}));
+ var Physics = Phaser.Physics;
+})(Phaser || (Phaser = {}));
+var Phaser;
+(function (Phaser) {
+ (function (Physics) {
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /**
+ * Phaser - Advanced Physics - ShapeBox
+ *
+ * Based on the work Ju Hyung Lee started in JS PhyRus.
+ */
+ (function (Advanced) {
+ var ShapeBox = (function (_super) {
+ __extends(ShapeBox, _super);
+ function ShapeBox(x, y, width, height) {
+ var hw = width * 0.5;
+ var hh = height * 0.5;
+ _super.call(this, [
+ new Phaser.Vec2(-hw + x, +hh + y),
+ new Phaser.Vec2(-hw + x, -hh + y),
+ new Phaser.Vec2(+hw + x, -hh + y),
+ new Phaser.Vec2(+hw + x, +hh + y)
+ ]);
+ }
+ return ShapeBox;
+ })(Phaser.Physics.Advanced.ShapePoly);
+ Advanced.ShapeBox = ShapeBox;
+ })(Physics.Advanced || (Physics.Advanced = {}));
+ var Advanced = Physics.Advanced;
+ })(Phaser.Physics || (Phaser.Physics = {}));
+ var Physics = Phaser.Physics;
+})(Phaser || (Phaser = {}));
+var Phaser;
+(function (Phaser) {
+ (function (Physics) {
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /**
+ * Phaser - Advanced Physics - Shape
+ *
+ * Based on the work Ju Hyung Lee started in JS PhyRus.
+ */
+ (function (Advanced) {
+ var ShapeSegment = (function (_super) {
+ __extends(ShapeSegment, _super);
+ function ShapeSegment(a, b, radius) {
+ _super.call(this, Advanced.Manager.SHAPE_TYPE_SEGMENT);
+ // What types are A and B??!
+ this.a = a.duplicate();
+ this.b = b.duplicate();
+ this.radius = radius;
+ this.normal = Phaser.Vec2Utils.perp(Phaser.Vec2Utils.subtract(b, a));
+ this.normal.normalize();
+ this.ta = new Phaser.Vec2();
+ this.tb = new Phaser.Vec2();
+ this.tn = new Phaser.Vec2();
+ this.finishVerts();
+ }
+ ShapeSegment.prototype.finishVerts = function () {
+ this.normal = Phaser.Vec2Utils.perp(Phaser.Vec2Utils.subtract(this.b, this.a));
+ this.normal.normalize();
+ this.radius = Math.abs(this.radius);
+ };
+ ShapeSegment.prototype.duplicate = function () {
+ return new ShapeSegment(this.a, this.b, this.radius);
+ };
+ ShapeSegment.prototype.recenter = function (c) {
+ this.a.subtract(c);
+ this.b.subtract(c);
+ };
+ ShapeSegment.prototype.transform = function (xf) {
+ this.a = xf.transform(this.a);
+ this.b = xf.transform(this.b);
+ };
+ ShapeSegment.prototype.untransform = function (xf) {
+ this.a = xf.untransform(this.a);
+ this.b = xf.untransform(this.b);
+ };
+ ShapeSegment.prototype.area = function () {
+ return Advanced.Manager.areaForSegment(this.a, this.b, this.radius);
+ };
+ ShapeSegment.prototype.centroid = function () {
+ return Advanced.Manager.centroidForSegment(this.a, this.b);
+ };
+ ShapeSegment.prototype.inertia = function (mass) {
+ return Advanced.Manager.inertiaForSegment(mass, this.a, this.b);
+ };
+ ShapeSegment.prototype.cacheData = function (xf) {
+ this.ta = xf.transform(this.a);
+ this.tb = xf.transform(this.b);
+ this.tn = Phaser.Vec2Utils.perp(Phaser.Vec2Utils.subtract(this.tb, this.ta)).normalize();
+ var l;
+ var r;
+ var t;
+ var b;
+ if(this.ta.x < this.tb.x) {
+ l = this.ta.x;
+ r = this.tb.x;
+ } else {
+ l = this.tb.x;
+ r = this.ta.x;
+ }
+ if(this.ta.y < this.tb.y) {
+ b = this.ta.y;
+ t = this.tb.y;
+ } else {
+ b = this.tb.y;
+ t = this.ta.y;
+ }
+ this.bounds.mins.set(l - this.radius, b - this.radius);
+ this.bounds.maxs.set(r + this.radius, t + this.radius);
+ };
+ ShapeSegment.prototype.pointQuery = function (p) {
+ if(!this.bounds.containPoint(p)) {
+ return false;
+ }
+ var dn = Phaser.Vec2Utils.dot(this.tn, p) - Phaser.Vec2Utils.dot(this.ta, this.tn);
+ var dist = Math.abs(dn);
+ if(dist > this.radius) {
+ return false;
+ }
+ var dt = Phaser.Vec2Utils.cross(p, this.tn);
+ var dta = Phaser.Vec2Utils.cross(this.ta, this.tn);
+ var dtb = Phaser.Vec2Utils.cross(this.tb, this.tn);
+ if(dt <= dta) {
+ if(dt < dta - this.radius) {
+ return false;
+ }
+ return Phaser.Vec2Utils.distanceSq(this.ta, p) < (this.radius * this.radius);
+ } else if(dt > dtb) {
+ if(dt > dtb + this.radius) {
+ return false;
+ }
+ return Phaser.Vec2Utils.distanceSq(this.tb, p) < (this.radius * this.radius);
+ }
+ return true;
+ };
+ ShapeSegment.prototype.findVertexByPoint = function (p, minDist) {
+ var dsq = minDist * minDist;
+ if(Phaser.Vec2Utils.distanceSq(this.ta, p) < dsq) {
+ return 0;
+ }
+ if(Phaser.Vec2Utils.distanceSq(this.tb, p) < dsq) {
+ return 1;
+ }
+ return -1;
+ };
+ ShapeSegment.prototype.distanceOnPlane = function (n, d) {
+ var a = Phaser.Vec2Utils.dot(n, this.ta) - this.radius;
+ var b = Phaser.Vec2Utils.dot(n, this.tb) - this.radius;
+ return Math.min(a, b) - d;
+ };
+ return ShapeSegment;
+ })(Phaser.Physics.Advanced.Shape);
+ Advanced.ShapeSegment = ShapeSegment;
+ })(Physics.Advanced || (Physics.Advanced = {}));
+ var Advanced = Physics.Advanced;
+ })(Phaser.Physics || (Phaser.Physics = {}));
+ var Physics = Phaser.Physics;
+})(Phaser || (Phaser = {}));
+var Phaser;
+(function (Phaser) {
+ (function (Physics) {
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /**
+ * Phaser - Advanced Physics - ShapeTriangle
+ *
+ * Based on the work Ju Hyung Lee started in JS PhyRus.
+ */
+ (function (Advanced) {
+ var ShapeTriangle = (function (_super) {
+ __extends(ShapeTriangle, _super);
+ function ShapeTriangle(p1, p2, p3) {
+ _super.call(this, [
+ new Phaser.Vec2(p1.x, p1.y),
+ new Phaser.Vec2(p2.x, p2.y),
+ new Phaser.Vec2(p3.x, p3.y)
+ ]);
+ }
+ return ShapeTriangle;
+ })(Phaser.Physics.Advanced.ShapePoly);
+ Advanced.ShapeTriangle = ShapeTriangle;
+ })(Physics.Advanced || (Physics.Advanced = {}));
+ var Advanced = Physics.Advanced;
+ })(Phaser.Physics || (Phaser.Physics = {}));
+ var Physics = Phaser.Physics;
+})(Phaser || (Phaser = {}));
///
///
///
diff --git a/build/phaser.d.ts b/build/phaser.d.ts
index b25e9d96..f0037541 100644
--- a/build/phaser.d.ts
+++ b/build/phaser.d.ts
@@ -572,6 +572,12 @@ module Phaser {
*/
public lengthSq(): number;
/**
+ * Normalize this vector.
+ *
+ * @return {Vec2} This for chaining.
+ */
+ public normalize(): Vec2;
+ /**
* The dot product of two 2D vectors.
*
* @param {Vec2} a Reference to a source Vec2 object.
@@ -2396,6 +2402,14 @@ module Phaser {
*/
static multiplyAdd(a: Vec2, b: Vec2, s: number, out?: Vec2): Vec2;
/**
+ * Return a negative vector.
+ *
+ * @param {Vec2} a Reference to a source Vec2 object.
+ * @param {Vec2} out The output Vec2 that is the result of the operation.
+ * @return {Vec2} A Vec2 that is the negative vector.
+ */
+ static negative(a: Vec2, out?: Vec2): Vec2;
+ /**
* Return a perpendicular vector (90 degrees rotation)
*
* @param {Vec2} a Reference to a source Vec2 object.
@@ -2519,7 +2533,17 @@ module Phaser {
* @param {Vec2} out The output Vec2 that is the result of the operation.
* @return {Vec2} A Vec2.
*/
- static rotate(a: Vec2, b: Vec2, theta: number, out?: Vec2): Vec2;
+ static rotateAroundOrigin(a: Vec2, b: Vec2, theta: number, out?: Vec2): Vec2;
+ /**
+ * Rotate a 2D vector to the given angle (theta).
+ *
+ * @param {Vec2} a Reference to a source Vec2 object.
+ * @param {Vec2} b Reference to a source Vec2 object.
+ * @param {Number} theta The angle of rotation in radians.
+ * @param {Vec2} out The output Vec2 that is the result of the operation.
+ * @return {Vec2} A Vec2.
+ */
+ static rotate(a: Vec2, theta: number, out?: Vec2): Vec2;
/**
* Clone a 2D vector.
*
@@ -9579,6 +9603,9 @@ module Phaser.Physics.Advanced {
static JOINT_LIMIT_STATE_AT_LOWER: number;
static JOINT_LIMIT_STATE_AT_UPPER: number;
static JOINT_LIMIT_STATE_EQUAL_LIMITS: number;
+ static CONTACT_SOLVER_COLLISION_SLOP: number;
+ static CONTACT_SOLVER_BAUMGARTE: number;
+ static CONTACT_SOLVER_MAX_LINEAR_CORRECTION: number;
static bodyCounter: number;
static jointCounter: number;
static shapeCounter: number;
@@ -9586,6 +9613,16 @@ module Phaser.Physics.Advanced {
static metersToPixels(value: number): number;
static p2m(value: number): number;
static m2p(value: number): number;
+ static areaForCircle(radius_outer, radius_inner): number;
+ static inertiaForCircle(mass, center, radius_outer, radius_inner): number;
+ static areaForSegment(a, b, radius): number;
+ static centroidForSegment(a, b): Vec2;
+ static inertiaForSegment(mass, a, b): number;
+ static areaForPoly(verts): number;
+ static centroidForPoly(verts): Vec2;
+ static inertiaForPoly(mass, verts, offset): number;
+ static inertiaForBox(mass, w, h): number;
+ static createConvexHull(points): any[];
}
}
/**
@@ -9728,13 +9765,172 @@ module Phaser.Physics.Advanced {
}
}
/**
+* Phaser - Advanced Physics - Contact
+*
+* Based on the work Ju Hyung Lee started in JS PhyRus.
+*/
+module Phaser.Physics.Advanced {
+ class Contact {
+ constructor(p, n, d, hash);
+ public hash;
+ public r1: Vec2;
+ public r2: Vec2;
+ public r1_local;
+ public r2_local;
+ public bounce;
+ public emn;
+ public emt;
+ public point;
+ public normal: Vec2;
+ public depth;
+ public lambdaNormal;
+ public lambdaTangential;
+ }
+}
+/**
* Phaser - Advanced Physics - Shape
*
* Based on the work Ju Hyung Lee started in JS PhyRus.
*/
module Phaser.Physics.Advanced {
class ShapeCircle extends Shape {
+ constructor(radius: number, x?: number, y?: number);
+ public radius: number;
+ public center: Vec2;
+ public tc: Vec2;
+ public finishVerts(): void;
+ public duplicate(): ShapeCircle;
+ public recenter(c): void;
+ public transform(xf): void;
+ public untransform(xf): void;
+ public area(): number;
+ public centroid(): void;
+ public inertia(mass): number;
+ public cacheData(xf): void;
+ public pointQuery(p): bool;
+ public findVertexByPoint(p, minDist): number;
+ public distanceOnPlane(n, d): void;
+ }
+}
+/**
+* Phaser - Advanced Physics - Collision Handlers
+*
+* Based on the work Ju Hyung Lee started in JS PhyRus.
+*/
+module Phaser.Physics.Advanced {
+ class Collision {
constructor();
+ public collide(a, b, contacts: Contact[]);
+ private _circle2Circle(c1, r1, c2, r2, contactArr);
+ public circle2Circle(circ1, circ2, contactArr): number;
+ public circle2Segment(circ: ShapeCircle, seg, contactArr: Contact[]): number;
+ public circle2Poly(circ: ShapeCircle, poly, contactArr: Contact[]): number;
+ public segmentPointDistanceSq(seg, p): number;
+ public segment2Segment(seg1, seg2, contactArr): number;
+ public findPointsBehindSeg(contactArr, seg, poly, dist, coef): void;
+ public segment2Poly(seg, poly, contactArr);
+ public findMSA(poly, planes, num): {
+ dist: number;
+ index: number;
+ };
+ public findVertsFallback(contactArr, poly1, poly2, n, dist): number;
+ public findVerts(contactArr, poly1, poly2, n, dist): number;
+ public poly2Poly(poly1, poly2, contactArr): number;
+ }
+}
+module Phaser.Physics.Advanced {
+ class ContactSolver {
+ constructor(shape1, shape2);
+ public shape1;
+ public shape2;
+ public contacts: Contact[];
+ public elasticity: number;
+ public friction: number;
+ public update(newContactArr: Contact[]): void;
+ public initSolver(dt_inv): void;
+ public warmStart(): void;
+ public solveVelocityConstraints(): void;
+ public solvePositionConstraints(): bool;
+ public clamp(v, min, max);
+ }
+}
+/**
+* Phaser - Advanced Physics - ShapePoly (convex only)
+*
+* Based on the work Ju Hyung Lee started in JS PhyRus.
+*/
+module Phaser.Physics.Advanced {
+ class ShapePoly extends Shape {
+ constructor(verts?: Vec2[]);
+ public verts: Vec2[];
+ public planes;
+ public tverts;
+ public tplanes;
+ public convexity: bool;
+ public finishVerts(): void;
+ public duplicate(): ShapePoly;
+ public recenter(c): void;
+ public transform(xf): void;
+ public untransform(xf): void;
+ public area(): number;
+ public centroid(): Vec2;
+ public inertia(mass): number;
+ public cacheData(xf): void;
+ public pointQuery(p): bool;
+ public findVertexByPoint(p, minDist): number;
+ public findEdgeByPoint(p, minDist): number;
+ public distanceOnPlane(n, d): number;
+ public containPoint(p): bool;
+ public containPointPartial(p, n): bool;
+ }
+}
+/**
+* Phaser - Advanced Physics - ShapeBox
+*
+* Based on the work Ju Hyung Lee started in JS PhyRus.
+*/
+module Phaser.Physics.Advanced {
+ class ShapeBox extends ShapePoly {
+ constructor(x, y, width, height);
+ }
+}
+/**
+* Phaser - Advanced Physics - Shape
+*
+* Based on the work Ju Hyung Lee started in JS PhyRus.
+*/
+module Phaser.Physics.Advanced {
+ class ShapeSegment extends Shape {
+ constructor(a, b, radius: number);
+ public a: Vec2;
+ public b: Vec2;
+ public radius: number;
+ public normal: Vec2;
+ public ta: Vec2;
+ public tb: Vec2;
+ public tn: Vec2;
+ public finishVerts(): void;
+ public duplicate(): ShapeSegment;
+ public recenter(c): void;
+ public transform(xf): void;
+ public untransform(xf): void;
+ public area(): number;
+ public centroid(): Vec2;
+ public inertia(mass): number;
+ public cacheData(xf): void;
+ public pointQuery(p): bool;
+ public findVertexByPoint(p, minDist): number;
+ public distanceOnPlane(n, d): number;
+ }
+}
+/**
+* Phaser - Advanced Physics - ShapeTriangle
+*
+* Based on the work Ju Hyung Lee started in JS PhyRus.
+*/
+module Phaser.Physics.Advanced {
+ class ShapeTriangle extends ShapePoly {
+ constructor(p1, p2, p3);
}
}
/**
diff --git a/build/phaser.js b/build/phaser.js
index 39df09a0..e2525f58 100644
--- a/build/phaser.js
+++ b/build/phaser.js
@@ -833,6 +833,17 @@ var Phaser;
function () {
return (this.x * this.x) + (this.y * this.y);
};
+ Vec2.prototype.normalize = /**
+ * Normalize this vector.
+ *
+ * @return {Vec2} This for chaining.
+ */
+ function () {
+ var inv = (this.x != 0 || this.y != 0) ? 1 / Math.sqrt(this.x * this.x + this.y * this.y) : 0;
+ this.x *= inv;
+ this.y *= inv;
+ return this;
+ };
Vec2.prototype.dot = /**
* The dot product of two 2D vectors.
*
@@ -3986,6 +3997,17 @@ var Phaser;
if (typeof out === "undefined") { out = new Phaser.Vec2(); }
return out.setTo(a.x + b.x * s, a.y + b.y * s);
};
+ Vec2Utils.negative = /**
+ * Return a negative vector.
+ *
+ * @param {Vec2} a Reference to a source Vec2 object.
+ * @param {Vec2} out The output Vec2 that is the result of the operation.
+ * @return {Vec2} A Vec2 that is the negative vector.
+ */
+ function negative(a, out) {
+ if (typeof out === "undefined") { out = new Phaser.Vec2(); }
+ return out.setTo(-a.x, -a.y);
+ };
Vec2Utils.perp = /**
* Return a perpendicular vector (90 degrees rotation)
*
@@ -4147,7 +4169,7 @@ var Phaser;
function angleSq(a, b) {
return a.subtract(b).angle(b.subtract(a));
};
- Vec2Utils.rotate = /**
+ Vec2Utils.rotateAroundOrigin = /**
* Rotate a 2D vector around the origin to the given angle (theta).
*
* @param {Vec2} a Reference to a source Vec2 object.
@@ -4156,12 +4178,27 @@ var Phaser;
* @param {Vec2} out The output Vec2 that is the result of the operation.
* @return {Vec2} A Vec2.
*/
- function rotate(a, b, theta, out) {
+ function rotateAroundOrigin(a, b, theta, out) {
if (typeof out === "undefined") { out = new Phaser.Vec2(); }
var x = a.x - b.x;
var y = a.y - b.y;
return out.setTo(x * Math.cos(theta) - y * Math.sin(theta) + b.x, x * Math.sin(theta) + y * Math.cos(theta) + b.y);
};
+ Vec2Utils.rotate = /**
+ * Rotate a 2D vector to the given angle (theta).
+ *
+ * @param {Vec2} a Reference to a source Vec2 object.
+ * @param {Vec2} b Reference to a source Vec2 object.
+ * @param {Number} theta The angle of rotation in radians.
+ * @param {Vec2} out The output Vec2 that is the result of the operation.
+ * @return {Vec2} A Vec2.
+ */
+ function rotate(a, theta, out) {
+ if (typeof out === "undefined") { out = new Phaser.Vec2(); }
+ var c = Math.cos(theta);
+ var s = Math.sin(theta);
+ return out.setTo(a.x * c - a.y * s, a.x * s + a.y * c);
+ };
Vec2Utils.clone = /**
* Clone a 2D vector.
*
@@ -19097,6 +19134,9 @@ var Phaser;
Manager.JOINT_LIMIT_STATE_AT_LOWER = 1;
Manager.JOINT_LIMIT_STATE_AT_UPPER = 2;
Manager.JOINT_LIMIT_STATE_EQUAL_LIMITS = 3;
+ Manager.CONTACT_SOLVER_COLLISION_SLOP = 0.0008;
+ Manager.CONTACT_SOLVER_BAUMGARTE = 0.28;
+ Manager.CONTACT_SOLVER_MAX_LINEAR_CORRECTION = 1;
Manager.bodyCounter = 0;
Manager.jointCounter = 0;
Manager.shapeCounter = 0;
@@ -19112,6 +19152,107 @@ var Phaser;
Manager.m2p = function m2p(value) {
return value * 50;
};
+ Manager.areaForCircle = function areaForCircle(radius_outer, radius_inner) {
+ return Math.PI * (radius_outer * radius_outer - radius_inner * radius_inner);
+ };
+ Manager.inertiaForCircle = function inertiaForCircle(mass, center, radius_outer, radius_inner) {
+ return mass * ((radius_outer * radius_outer + radius_inner * radius_inner) * 0.5 + center.lengthsq());
+ };
+ Manager.areaForSegment = function areaForSegment(a, b, radius) {
+ return radius * (Math.PI * radius + 2 * Phaser.Vec2Utils.distance(a, b));
+ };
+ Manager.centroidForSegment = function centroidForSegment(a, b) {
+ return Phaser.Vec2Utils.scale(Phaser.Vec2Utils.add(a, b), 0.5);
+ };
+ Manager.inertiaForSegment = function inertiaForSegment(mass, a, b) {
+ var distsq = Phaser.Vec2Utils.distanceSq(b, a);
+ var offset = Phaser.Vec2Utils.scale(Phaser.Vec2Utils.add(a, b), 0.5);
+ return mass * (distsq / 12 + offset.lengthSq());
+ };
+ Manager.areaForPoly = function areaForPoly(verts) {
+ var area = 0;
+ for(var i = 0; i < verts.length; i++) {
+ area += Phaser.Vec2Utils.cross(verts[i], verts[(i + 1) % verts.length]);
+ }
+ return area / 2;
+ };
+ Manager.centroidForPoly = function centroidForPoly(verts) {
+ var area = 0;
+ var vsum = new Phaser.Vec2();
+ for(var i = 0; i < verts.length; i++) {
+ var v1 = verts[i];
+ var v2 = verts[(i + 1) % verts.length];
+ var cross = Phaser.Vec2Utils.cross(v1, v2);
+ area += cross;
+ // SO many vecs created here - unroll these bad boys
+ vsum.add(Phaser.Vec2Utils.scale(Phaser.Vec2Utils.add(v1, v2), cross));
+ }
+ return Phaser.Vec2Utils.scale(vsum, 1 / (3 * area));
+ };
+ Manager.inertiaForPoly = function inertiaForPoly(mass, verts, offset) {
+ var sum1 = 0;
+ var sum2 = 0;
+ for(var i = 0; i < verts.length; i++) {
+ var v1 = Phaser.Vec2Utils.add(verts[i], offset);
+ var v2 = Phaser.Vec2Utils.add(verts[(i + 1) % verts.length], offset);
+ var a = Phaser.Vec2Utils.cross(v2, v1);
+ var b = Phaser.Vec2Utils.dot(v1, v1) + Phaser.Vec2Utils.dot(v1, v2) + Phaser.Vec2Utils.dot(v2, v2);
+ sum1 += a * b;
+ sum2 += a;
+ }
+ return (mass * sum1) / (6 * sum2);
+ };
+ Manager.inertiaForBox = function inertiaForBox(mass, w, h) {
+ return mass * (w * w + h * h) / 12;
+ };
+ Manager.createConvexHull = // Create the convex hull using the Gift wrapping algorithm (http://en.wikipedia.org/wiki/Gift_wrapping_algorithm)
+ function createConvexHull(points) {
+ // Find the right most point on the hull
+ var i0 = 0;
+ var x0 = points[0].x;
+ for(var i = 1; i < points.length; i++) {
+ var x = points[i].x;
+ if(x > x0 || (x == x0 && points[i].y < points[i0].y)) {
+ i0 = i;
+ x0 = x;
+ }
+ }
+ var n = points.length;
+ var hull = [];
+ var m = 0;
+ var ih = i0;
+ while(1) {
+ hull[m] = ih;
+ var ie = 0;
+ for(var j = 1; j < n; j++) {
+ if(ie == ih) {
+ ie = j;
+ continue;
+ }
+ var r = Phaser.Vec2Utils.subtract(points[ie], points[hull[m]]);
+ var v = Phaser.Vec2Utils.subtract(points[j], points[hull[m]]);
+ var c = Phaser.Vec2Utils.cross(r, v);
+ if(c < 0) {
+ ie = j;
+ }
+ // Collinearity check
+ if(c == 0 && v.lengthSq() > r.lengthSq()) {
+ ie = j;
+ }
+ }
+ m++;
+ ih = ie;
+ if(ie == i0) {
+ break;
+ }
+ }
+ // Copy vertices
+ var newPoints = [];
+ for(var i = 0; i < m; ++i) {
+ newPoints.push(points[hull[i]]);
+ }
+ return newPoints;
+ };
return Manager;
})();
Advanced.Manager = Manager;
@@ -19645,6 +19786,38 @@ var Phaser;
var Physics = Phaser.Physics;
})(Phaser || (Phaser = {}));
var Phaser;
+(function (Phaser) {
+ (function (Physics) {
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /**
+ * Phaser - Advanced Physics - Contact
+ *
+ * Based on the work Ju Hyung Lee started in JS PhyRus.
+ */
+ (function (Advanced) {
+ var Contact = (function () {
+ function Contact(p, n, d, hash) {
+ this.hash = hash;
+ this.point = p;
+ this.normal = n;
+ this.depth = d;
+ this.lambdaNormal = 0;
+ this.lambdaTangential = 0;
+ }
+ return Contact;
+ })();
+ Advanced.Contact = Contact;
+ })(Physics.Advanced || (Physics.Advanced = {}));
+ var Advanced = Physics.Advanced;
+ })(Phaser.Physics || (Phaser.Physics = {}));
+ var Physics = Phaser.Physics;
+})(Phaser || (Phaser = {}));
+var Phaser;
(function (Phaser) {
(function (Physics) {
///
@@ -19661,9 +19834,58 @@ var Phaser;
(function (Advanced) {
var ShapeCircle = (function (_super) {
__extends(ShapeCircle, _super);
- function ShapeCircle() {
+ function ShapeCircle(radius, x, y) {
+ if (typeof x === "undefined") { x = 0; }
+ if (typeof y === "undefined") { y = 0; }
_super.call(this, Advanced.Manager.SHAPE_TYPE_CIRCLE);
+ this.center = new Phaser.Vec2(x, y);
+ this.radius = radius;
+ this.tc = new Phaser.Vec2();
+ this.finishVerts();
}
+ ShapeCircle.prototype.finishVerts = function () {
+ this.radius = Math.abs(this.radius);
+ };
+ ShapeCircle.prototype.duplicate = function () {
+ return new ShapeCircle(this.center.x, this.center.y, this.radius);
+ };
+ ShapeCircle.prototype.recenter = function (c) {
+ this.center.subtract(c);
+ };
+ ShapeCircle.prototype.transform = function (xf) {
+ this.center = xf.transform(this.center);
+ };
+ ShapeCircle.prototype.untransform = function (xf) {
+ this.center = xf.untransform(this.center);
+ };
+ ShapeCircle.prototype.area = function () {
+ return Advanced.Manager.areaForCircle(this.radius, 0);
+ };
+ ShapeCircle.prototype.centroid = function () {
+ //return this.center.duplicate();
+ };
+ ShapeCircle.prototype.inertia = function (mass) {
+ return Advanced.Manager.inertiaForCircle(mass, this.center, this.radius, 0);
+ };
+ ShapeCircle.prototype.cacheData = function (xf) {
+ this.tc = xf.transform(this.center);
+ this.bounds.mins.set(this.tc.x - this.radius, this.tc.y - this.radius);
+ this.bounds.maxs.set(this.tc.x + this.radius, this.tc.y + this.radius);
+ };
+ ShapeCircle.prototype.pointQuery = function (p) {
+ //return vec2.distsq(this.tc, p) < (this.r * this.r);
+ return Phaser.Vec2Utils.distanceSq(this.tc, p) < (this.radius * this.radius);
+ };
+ ShapeCircle.prototype.findVertexByPoint = function (p, minDist) {
+ var dsq = minDist * minDist;
+ if(Phaser.Vec2Utils.distanceSq(this.tc, p) < dsq) {
+ return 0;
+ }
+ return -1;
+ };
+ ShapeCircle.prototype.distanceOnPlane = function (n, d) {
+ Phaser.Vec2Utils.dot(n, this.tc) - this.radius - d;
+ };
return ShapeCircle;
})(Phaser.Physics.Advanced.Shape);
Advanced.ShapeCircle = ShapeCircle;
@@ -19672,6 +19894,1023 @@ var Phaser;
})(Phaser.Physics || (Phaser.Physics = {}));
var Physics = Phaser.Physics;
})(Phaser || (Phaser = {}));
+var Phaser;
+(function (Phaser) {
+ (function (Physics) {
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /**
+ * Phaser - Advanced Physics - Collision Handlers
+ *
+ * Based on the work Ju Hyung Lee started in JS PhyRus.
+ */
+ (function (Advanced) {
+ var Collision = (function () {
+ function Collision() {
+ }
+ Collision.prototype.collide = function (a, b, contacts) {
+ // Circle (a is the circle)
+ if(a.type == Advanced.Manager.SHAPE_TYPE_CIRCLE) {
+ if(b.type == Advanced.Manager.SHAPE_TYPE_CIRCLE) {
+ return this.circle2Circle(a, b, contacts);
+ } else if(b.type == Advanced.Manager.SHAPE_TYPE_SEGMENT) {
+ return this.circle2Segment(a, b, contacts);
+ } else if(b.type == Advanced.Manager.SHAPE_TYPE_POLY) {
+ return this.circle2Poly(a, b, contacts);
+ }
+ }
+ // Segment (a is the segment)
+ if(a.type == Advanced.Manager.SHAPE_TYPE_SEGMENT) {
+ if(b.type == Advanced.Manager.SHAPE_TYPE_CIRCLE) {
+ return this.circle2Segment(b, a, contacts);
+ } else if(b.type == Advanced.Manager.SHAPE_TYPE_SEGMENT) {
+ return this.segment2Segment(a, b, contacts);
+ } else if(b.type == Advanced.Manager.SHAPE_TYPE_POLY) {
+ return this.segment2Poly(a, b, contacts);
+ }
+ }
+ // Poly (a is the poly)
+ if(a.type == Advanced.Manager.SHAPE_TYPE_POLY) {
+ if(b.type == Advanced.Manager.SHAPE_TYPE_CIRCLE) {
+ return this.circle2Poly(b, a, contacts);
+ } else if(b.type == Advanced.Manager.SHAPE_TYPE_SEGMENT) {
+ return this.segment2Poly(b, a, contacts);
+ } else if(b.type == Advanced.Manager.SHAPE_TYPE_POLY) {
+ return this.poly2Poly(a, b, contacts);
+ }
+ }
+ };
+ Collision.prototype._circle2Circle = function (c1, r1, c2, r2, contactArr) {
+ var rmax = r1 + r2;
+ var t = new Phaser.Vec2();
+ //var t = vec2.sub(c2, c1);
+ Phaser.Vec2Utils.subtract(c2, c1, t);
+ var distsq = t.lengthSq();
+ if(distsq > rmax * rmax) {
+ return 0;
+ }
+ var dist = Math.sqrt(distsq);
+ var p = new Phaser.Vec2();
+ Phaser.Vec2Utils.multiplyAdd(c1, t, 0.5 + (r1 - r2) * 0.5 / dist, p);
+ //var p = vec2.mad(c1, t, 0.5 + (r1 - r2) * 0.5 / dist);
+ var n = new Phaser.Vec2();
+ //var n = (dist != 0) ? vec2.scale(t, 1 / dist) : vec2.zero;
+ if(dist != 0) {
+ Phaser.Vec2Utils.scale(t, 1 / dist, n);
+ }
+ var d = dist - rmax;
+ contactArr.push(new Advanced.Contact(p, n, d, 0));
+ return 1;
+ };
+ Collision.prototype.circle2Circle = function (circ1, circ2, contactArr) {
+ return this._circle2Circle(circ1.tc, circ1.r, circ2.tc, circ2.r, contactArr);
+ };
+ Collision.prototype.circle2Segment = function (circ, seg, contactArr) {
+ var rsum = circ.radius + seg.r;
+ // Normal distance from segment
+ var dn = Phaser.Vec2Utils.dot(circ.tc, seg.tn) - Phaser.Vec2Utils.dot(seg.ta, seg.tn);
+ var dist = (dn < 0 ? dn * -1 : dn) - rsum;
+ if(dist > 0) {
+ return 0;
+ }
+ // Tangential distance along segment
+ var dt = Phaser.Vec2Utils.cross(circ.tc, seg.tn);
+ var dtMin = Phaser.Vec2Utils.cross(seg.ta, seg.tn);
+ var dtMax = Phaser.Vec2Utils.cross(seg.tb, seg.tn);
+ if(dt < dtMin) {
+ if(dt < dtMin - rsum) {
+ return 0;
+ }
+ return this._circle2Circle(circ.tc, circ.radius, seg.ta, seg.r, contactArr);
+ } else if(dt > dtMax) {
+ if(dt > dtMax + rsum) {
+ return 0;
+ }
+ return this._circle2Circle(circ.tc, circ.radius, seg.tb, seg.r, contactArr);
+ }
+ var n = new Phaser.Vec2();
+ if(dn > 0) {
+ n.copyFrom(seg.tn);
+ } else {
+ Phaser.Vec2Utils.negative(seg.tn, n);
+ }
+ //var n = (dn > 0) ? seg.tn : vec2.neg(seg.tn);
+ var c1 = new Phaser.Vec2();
+ Phaser.Vec2Utils.multiplyAdd(circ.tc, n, -(circ.radius + dist * 0.5), c1);
+ var c2 = new Phaser.Vec2();
+ Phaser.Vec2Utils.negative(n, c2);
+ contactArr.push(new Advanced.Contact(c1, c2, dist, 0));
+ //contactArr.push(new Contact(vec2.mad(circ.tc, n, -(circ.r + dist * 0.5)), vec2.neg(n), dist, 0));
+ return 1;
+ };
+ Collision.prototype.circle2Poly = function (circ, poly, contactArr) {
+ var minDist = -999999;
+ var minIdx = -1;
+ for(var i = 0; i < poly.verts.length; i++) {
+ var plane = poly.tplanes[i];
+ var dist = Phaser.Vec2Utils.dot(circ.tc, plane.n) - plane.d - circ.radius;
+ if(dist > 0) {
+ return 0;
+ } else if(dist > minDist) {
+ minDist = dist;
+ minIdx = i;
+ }
+ }
+ var n = poly.tplanes[minIdx].n;
+ var a = poly.tverts[minIdx];
+ var b = poly.tverts[(minIdx + 1) % poly.verts.length];
+ var dta = Phaser.Vec2Utils.cross(a, n);
+ var dtb = Phaser.Vec2Utils.cross(b, n);
+ var dt = Phaser.Vec2Utils.cross(circ.tc, n);
+ if(dt > dta) {
+ return this._circle2Circle(circ.tc, circ.radius, a, 0, contactArr);
+ } else if(dt < dtb) {
+ return this._circle2Circle(circ.tc, circ.radius, b, 0, contactArr);
+ }
+ var c1 = new Phaser.Vec2();
+ Phaser.Vec2Utils.multiplyAdd(circ.tc, n, -(circ.radius + minDist * 0.5), c1);
+ var c2 = new Phaser.Vec2();
+ Phaser.Vec2Utils.negative(n, c2);
+ contactArr.push(new Advanced.Contact(c1, c2, minDist, 0));
+ //contactArr.push(new Contact(vec2.mad(circ.tc, n, -(circ.r + minDist * 0.5)), vec2.neg(n), minDist, 0));
+ return 1;
+ };
+ Collision.prototype.segmentPointDistanceSq = function (seg, p) {
+ var w = new Phaser.Vec2();
+ var d = new Phaser.Vec2();
+ Phaser.Vec2Utils.subtract(p, seg.ta, w);
+ Phaser.Vec2Utils.subtract(seg.tb, seg.ta, d);
+ //var w = vec2.sub(p, seg.ta);
+ //var d = vec2.sub(seg.tb, seg.ta);
+ var proj = w.dot(d);
+ if(proj <= 0) {
+ return w.dot(w);
+ }
+ var vsq = d.dot(d);
+ if(proj >= vsq) {
+ return w.dot(w) - 2 * proj + vsq;
+ }
+ return w.dot(w) - proj * proj / vsq;
+ };
+ Collision.prototype.segment2Segment = // FIXME and optimise me lots!!!
+ function (seg1, seg2, contactArr) {
+ var d = [];
+ d[0] = this.segmentPointDistanceSq(seg1, seg2.ta);
+ d[1] = this.segmentPointDistanceSq(seg1, seg2.tb);
+ d[2] = this.segmentPointDistanceSq(seg2, seg1.ta);
+ d[3] = this.segmentPointDistanceSq(seg2, seg1.tb);
+ var idx1 = d[0] < d[1] ? 0 : 1;
+ var idx2 = d[2] < d[3] ? 2 : 3;
+ var idxm = d[idx1] < d[idx2] ? idx1 : idx2;
+ var s, t;
+ var u = Phaser.Vec2Utils.subtract(seg1.tb, seg1.ta);
+ var v = Phaser.Vec2Utils.subtract(seg2.tb, seg2.ta);
+ switch(idxm) {
+ case 0:
+ s = Phaser.Vec2Utils.dot(Phaser.Vec2Utils.subtract(seg2.ta, seg1.ta), u) / Phaser.Vec2Utils.dot(u, u);
+ s = s < 0 ? 0 : (s > 1 ? 1 : s);
+ t = 0;
+ break;
+ case 1:
+ s = Phaser.Vec2Utils.dot(Phaser.Vec2Utils.subtract(seg2.tb, seg1.ta), u) / Phaser.Vec2Utils.dot(u, u);
+ s = s < 0 ? 0 : (s > 1 ? 1 : s);
+ t = 1;
+ break;
+ case 2:
+ s = 0;
+ t = Phaser.Vec2Utils.dot(Phaser.Vec2Utils.subtract(seg1.ta, seg2.ta), v) / Phaser.Vec2Utils.dot(v, v);
+ t = t < 0 ? 0 : (t > 1 ? 1 : t);
+ break;
+ case 3:
+ s = 1;
+ t = Phaser.Vec2Utils.dot(Phaser.Vec2Utils.subtract(seg1.tb, seg2.ta), v) / Phaser.Vec2Utils.dot(v, v);
+ t = t < 0 ? 0 : (t > 1 ? 1 : t);
+ break;
+ }
+ var minp1 = Phaser.Vec2Utils.multiplyAdd(seg1.ta, u, s);
+ var minp2 = Phaser.Vec2Utils.multiplyAdd(seg2.ta, v, t);
+ return this._circle2Circle(minp1, seg1.r, minp2, seg2.r, contactArr);
+ };
+ Collision.prototype.findPointsBehindSeg = // Identify vertexes that have penetrated the segment.
+ function (contactArr, seg, poly, dist, coef) {
+ var dta = Phaser.Vec2Utils.cross(seg.tn, seg.ta);
+ var dtb = Phaser.Vec2Utils.cross(seg.tn, seg.tb);
+ var n = new Phaser.Vec2();
+ Phaser.Vec2Utils.scale(seg.tn, coef, n);
+ //var n = vec2.scale(seg.tn, coef);
+ for(var i = 0; i < poly.verts.length; i++) {
+ var v = poly.tverts[i];
+ if(Phaser.Vec2Utils.dot(v, n) < Phaser.Vec2Utils.dot(seg.tn, seg.ta) * coef + seg.r) {
+ var dt = Phaser.Vec2Utils.cross(seg.tn, v);
+ if(dta >= dt && dt >= dtb) {
+ contactArr.push(new Advanced.Contact(v, n, dist, (poly.id << 16) | i));
+ }
+ }
+ }
+ };
+ Collision.prototype.segment2Poly = function (seg, poly, contactArr) {
+ var seg_td = Phaser.Vec2Utils.dot(seg.tn, seg.ta);
+ var seg_d1 = poly.distanceOnPlane(seg.tn, seg_td) - seg.r;
+ if(seg_d1 > 0) {
+ return 0;
+ }
+ var n = new Phaser.Vec2();
+ Phaser.Vec2Utils.negative(seg.tn, n);
+ var seg_d2 = poly.distanceOnPlane(n, -seg_td) - seg.r;
+ //var seg_d2 = poly.distanceOnPlane(vec2.neg(seg.tn), -seg_td) - seg.r;
+ if(seg_d2 > 0) {
+ return 0;
+ }
+ var poly_d = -999999;
+ var poly_i = -1;
+ for(var i = 0; i < poly.verts.length; i++) {
+ var plane = poly.tplanes[i];
+ var dist = seg.distanceOnPlane(plane.n, plane.d);
+ if(dist > 0) {
+ return 0;
+ }
+ if(dist > poly_d) {
+ poly_d = dist;
+ poly_i = i;
+ }
+ }
+ var poly_n = new Phaser.Vec2();
+ Phaser.Vec2Utils.negative(poly.tplanes[poly_i].n, poly_n);
+ //var poly_n = vec2.neg(poly.tplanes[poly_i].n);
+ var va = new Phaser.Vec2();
+ Phaser.Vec2Utils.multiplyAdd(seg.ta, poly_n, seg.r, va);
+ //var va = vec2.mad(seg.ta, poly_n, seg.r);
+ var vb = new Phaser.Vec2();
+ Phaser.Vec2Utils.multiplyAdd(seg.tb, poly_n, seg.r, vb);
+ //var vb = vec2.mad(seg.tb, poly_n, seg.r);
+ if(poly.containPoint(va)) {
+ contactArr.push(new Advanced.Contact(va, poly_n, poly_d, (seg.id << 16) | 0));
+ }
+ if(poly.containPoint(vb)) {
+ contactArr.push(new Advanced.Contact(vb, poly_n, poly_d, (seg.id << 16) | 1));
+ }
+ // Floating point precision problems here.
+ // This will have to do for now.
+ poly_d -= 0.1;
+ if(seg_d1 >= poly_d || seg_d2 >= poly_d) {
+ if(seg_d1 > seg_d2) {
+ this.findPointsBehindSeg(contactArr, seg, poly, seg_d1, 1);
+ } else {
+ this.findPointsBehindSeg(contactArr, seg, poly, seg_d2, -1);
+ }
+ }
+ // If no other collision points are found, try colliding endpoints.
+ if(contactArr.length == 0) {
+ var poly_a = poly.tverts[poly_i];
+ var poly_b = poly.tverts[(poly_i + 1) % poly.verts.length];
+ if(this._circle2Circle(seg.ta, seg.r, poly_a, 0, contactArr)) {
+ return 1;
+ }
+ if(this._circle2Circle(seg.tb, seg.r, poly_a, 0, contactArr)) {
+ return 1;
+ }
+ if(this._circle2Circle(seg.ta, seg.r, poly_b, 0, contactArr)) {
+ return 1;
+ }
+ if(this._circle2Circle(seg.tb, seg.r, poly_b, 0, contactArr)) {
+ return 1;
+ }
+ }
+ return contactArr.length;
+ };
+ Collision.prototype.findMSA = // Find the minimum separating axis for the given poly and plane list.
+ function (poly, planes, num) {
+ var min_dist = -999999;
+ var min_index = -1;
+ for(var i = 0; i < num; i++) {
+ var dist = poly.distanceOnPlane(planes[i].n, planes[i].d);
+ if(dist > 0) {
+ // no collision
+ return {
+ dist: 0,
+ index: -1
+ };
+ } else if(dist > min_dist) {
+ min_dist = dist;
+ min_index = i;
+ }
+ }
+ // new object - see what we can do here
+ return {
+ dist: min_dist,
+ index: min_index
+ };
+ };
+ Collision.prototype.findVertsFallback = function (contactArr, poly1, poly2, n, dist) {
+ var num = 0;
+ for(var i = 0; i < poly1.verts.length; i++) {
+ var v = poly1.tverts[i];
+ if(poly2.containPointPartial(v, n)) {
+ contactArr.push(new Advanced.Contact(v, n, dist, (poly1.id << 16) | i));
+ num++;
+ }
+ }
+ for(var i = 0; i < poly2.verts.length; i++) {
+ var v = poly2.tverts[i];
+ if(poly1.containPointPartial(v, n)) {
+ contactArr.push(new Advanced.Contact(v, n, dist, (poly2.id << 16) | i));
+ num++;
+ }
+ }
+ return num;
+ };
+ Collision.prototype.findVerts = // Find the overlapped vertices.
+ function (contactArr, poly1, poly2, n, dist) {
+ var num = 0;
+ for(var i = 0; i < poly1.verts.length; i++) {
+ var v = poly1.tverts[i];
+ if(poly2.containPoint(v)) {
+ contactArr.push(new Advanced.Contact(v, n, dist, (poly1.id << 16) | i));
+ num++;
+ }
+ }
+ for(var i = 0; i < poly2.verts.length; i++) {
+ var v = poly2.tverts[i];
+ if(poly1.containPoint(v)) {
+ contactArr.push(new Advanced.Contact(v, n, dist, (poly2.id << 16) | i));
+ num++;
+ }
+ }
+ return num > 0 ? num : this.findVertsFallback(contactArr, poly1, poly2, n, dist);
+ };
+ Collision.prototype.poly2Poly = function (poly1, poly2, contactArr) {
+ var msa1 = this.findMSA(poly2, poly1.tplanes, poly1.verts.length);
+ if(msa1.index == -1) {
+ return 0;
+ }
+ var msa2 = this.findMSA(poly1, poly2.tplanes, poly2.verts.length);
+ if(msa2.index == -1) {
+ return 0;
+ }
+ // Penetration normal direction shoud be from poly1 to poly2
+ if(msa1.dist > msa2.dist) {
+ return this.findVerts(contactArr, poly1, poly2, poly1.tplanes[msa1.index].n, msa1.dist);
+ }
+ return this.findVerts(contactArr, poly1, poly2, Phaser.Vec2Utils.negative(poly2.tplanes[msa2.index].n), msa2.dist);
+ };
+ return Collision;
+ })();
+ Advanced.Collision = Collision;
+ })(Physics.Advanced || (Physics.Advanced = {}));
+ var Advanced = Physics.Advanced;
+ })(Phaser.Physics || (Phaser.Physics = {}));
+ var Physics = Phaser.Physics;
+})(Phaser || (Phaser = {}));
+var Phaser;
+(function (Phaser) {
+ (function (Physics) {
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /**
+ * Phaser - Advanced Physics - ContactSolver
+ *
+ * Based on the work Ju Hyung Lee started in JS PhyRus.
+ */
+ //-------------------------------------------------------------------------------------------------
+ // Contact Constraint
+ //
+ // Non-penetration constraint:
+ // C = dot(p2 - p1, n)
+ // Cdot = dot(v2 - v1, n)
+ // J = [ -n, -cross(r1, n), n, cross(r2, n) ]
+ //
+ // impulse = JT * lambda = [ -n * lambda, -cross(r1, n) * lambda, n * lambda, cross(r1, n) * lambda ]
+ //
+ // Friction constraint:
+ // C = dot(p2 - p1, t)
+ // Cdot = dot(v2 - v1, t)
+ // J = [ -t, -cross(r1, t), t, cross(r2, t) ]
+ //
+ // impulse = JT * lambda = [ -t * lambda, -cross(r1, t) * lambda, t * lambda, cross(r1, t) * lambda ]
+ //
+ // NOTE: lambda is an impulse in constraint space.
+ //-------------------------------------------------------------------------------------------------
+ (function (Advanced) {
+ var ContactSolver = (function () {
+ function ContactSolver(shape1, shape2) {
+ this.shape1 = shape1;
+ this.shape2 = shape2;
+ this.contacts = [];
+ this.elasticity = 1;
+ this.friction = 1;
+ }
+ ContactSolver.prototype.update = function (newContactArr) {
+ for(var i = 0; i < newContactArr.length; i++) {
+ var newContact = newContactArr[i];
+ var k = -1;
+ for(var j = 0; j < this.contacts.length; j++) {
+ if(newContact.hash == this.contacts[j].hash) {
+ k = j;
+ break;
+ }
+ }
+ if(k > -1) {
+ newContact.lambdaNormal = this.contacts[k].lambdaNormal;
+ newContact.lambdaTangential = this.contacts[k].lambdaTangential;
+ }
+ }
+ this.contacts = newContactArr;
+ };
+ ContactSolver.prototype.initSolver = function (dt_inv) {
+ var body1 = this.shape1.body;
+ var body2 = this.shape2.body;
+ var sum_m_inv = body1.massInverted + body2.massInverted;
+ for(var i = 0; i < this.contacts.length; i++) {
+ var con = this.contacts[i];
+ // Transformed r1, r2
+ Phaser.Vec2Utils.subtract(con.point, body1.position, con.r1);
+ Phaser.Vec2Utils.subtract(con.point, body2.position, con.r2);
+ //con.r1 = vec2.sub(con.point, body1.p);
+ //con.r2 = vec2.sub(con.point, body2.p);
+ // Local r1, r2
+ con.r1_local = body1.transform.unrotate(con.r1);
+ con.r2_local = body2.transform.unrotate(con.r2);
+ var n = con.normal;
+ var t = Phaser.Vec2Utils.perp(con.normal);
+ // invEMn = J * invM * JT
+ // J = [ -n, -cross(r1, n), n, cross(r2, n) ]
+ var sn1 = Phaser.Vec2Utils.cross(con.r1, n);
+ var sn2 = Phaser.Vec2Utils.cross(con.r2, n);
+ var emn_inv = sum_m_inv + body1.inertiaInverted * sn1 * sn1 + body2.inertiaInverted * sn2 * sn2;
+ con.emn = emn_inv == 0 ? 0 : 1 / emn_inv;
+ // invEMt = J * invM * JT
+ // J = [ -t, -cross(r1, t), t, cross(r2, t) ]
+ var st1 = Phaser.Vec2Utils.cross(con.r1, t);
+ var st2 = Phaser.Vec2Utils.cross(con.r2, t);
+ var emt_inv = sum_m_inv + body1.inertiaInverted * st1 * st1 + body2.inertiaInverted * st2 * st2;
+ con.emt = emt_inv == 0 ? 0 : 1 / emt_inv;
+ // Linear velocities at contact point
+ // in 2D: cross(w, r) = perp(r) * w
+ var v1 = new Phaser.Vec2();
+ var v2 = new Phaser.Vec2();
+ Phaser.Vec2Utils.multiplyAdd(body1.velocity, Phaser.Vec2Utils.perp(con.r1), body1.angularVelocity, v1);
+ Phaser.Vec2Utils.multiplyAdd(body2.velocity, Phaser.Vec2Utils.perp(con.r2), body2.angularVelocity, v2);
+ //var v1 = vec2.mad(body1.v, vec2.perp(con.r1), body1.w);
+ //var v2 = vec2.mad(body2.v, vec2.perp(con.r2), body2.w);
+ // relative velocity at contact point
+ var rv = new Phaser.Vec2();
+ Phaser.Vec2Utils.subtract(v2, v1, rv);
+ //var rv = vec2.sub(v2, v1);
+ // bounce velocity dot n
+ con.bounce = Phaser.Vec2Utils.dot(rv, con.normal) * this.elasticity;
+ }
+ };
+ ContactSolver.prototype.warmStart = function () {
+ var body1 = this.shape1.body;
+ var body2 = this.shape2.body;
+ for(var i = 0; i < this.contacts.length; i++) {
+ var con = this.contacts[i];
+ var n = con.normal;
+ var lambda_n = con.lambdaNormal;
+ var lambda_t = con.lambdaTangential;
+ // Apply accumulated impulses
+ //var impulse = vec2.rotate_vec(new vec2(lambda_n, lambda_t), n);
+ //var impulse = new vec2(lambda_n * n.x - lambda_t * n.y, lambda_t * n.x + lambda_n * n.y);
+ var impulse = new Phaser.Vec2(lambda_n * n.x - lambda_t * n.y, lambda_t * n.x + lambda_n * n.y);
+ body1.velocity.multiplyAddByScalar(impulse, -body1.massInverted);
+ //body1.v.mad(impulse, -body1.m_inv);
+ body1.angularVelocity -= Phaser.Vec2Utils.cross(con.r1, impulse) * body1.inertiaInverted;
+ //body1.w -= vec2.cross(con.r1, impulse) * body1.i_inv;
+ body2.velocity.multiplyAddByScalar(impulse, -body2.massInverted);
+ //body2.v.mad(impulse, body2.m_inv);
+ body2.angularVelocity -= Phaser.Vec2Utils.cross(con.r2, impulse) * body2.inertiaInverted;
+ //body2.w += vec2.cross(con.r2, impulse) * body2.i_inv;
+ }
+ };
+ ContactSolver.prototype.solveVelocityConstraints = function () {
+ var body1 = this.shape1.body;
+ var body2 = this.shape2.body;
+ var m1_inv = body1.massInverted;
+ var i1_inv = body1.inertiaInverted;
+ var m2_inv = body2.massInverted;
+ var i2_inv = body2.inertiaInverted;
+ for(var i = 0; i < this.contacts.length; i++) {
+ var con = this.contacts[i];
+ var n = con.normal;
+ var t = Phaser.Vec2Utils.perp(n);
+ var r1 = con.r1;
+ var r2 = con.r2;
+ // Linear velocities at contact point
+ // in 2D: cross(w, r) = perp(r) * w
+ var v1 = new Phaser.Vec2();
+ var v2 = new Phaser.Vec2();
+ Phaser.Vec2Utils.multiplyAdd(body1.velocity, Phaser.Vec2Utils.perp(r1), body1.angularVelocity, v1);
+ //var v1 = vec2.mad(body1.v, vec2.perp(r1), body1.w);
+ Phaser.Vec2Utils.multiplyAdd(body2.velocity, Phaser.Vec2Utils.perp(r2), body2.angularVelocity, v2);
+ //var v2 = vec2.mad(body2.v, vec2.perp(r2), body2.w);
+ // Relative velocity at contact point
+ var rv = new Phaser.Vec2();
+ Phaser.Vec2Utils.subtract(v2, v1, rv);
+ //var rv = vec2.sub(v2, v1);
+ // Compute normal constraint impulse + adding bounce as a velocity bias
+ // lambda_n = -EMn * J * V
+ var lambda_n = -con.emn * (Phaser.Vec2Utils.dot(n, rv) + con.bounce);
+ // Accumulate and clamp
+ var lambda_n_old = con.lambdaNormal;
+ con.lambdaNormal = Math.max(lambda_n_old + lambda_n, 0);
+ lambda_n = con.lambdaNormal - lambda_n_old;
+ // Compute frictional constraint impulse
+ // lambda_t = -EMt * J * V
+ var lambda_t = -con.emt * Phaser.Vec2Utils.dot(t, rv);
+ // Max friction constraint impulse (Coulomb's Law)
+ var lambda_t_max = con.lambdaNormal * this.friction;
+ // Accumulate and clamp
+ var lambda_t_old = con.lambdaTangential;
+ con.lambdaTangential = this.clamp(lambda_t_old + lambda_t, -lambda_t_max, lambda_t_max);
+ lambda_t = con.lambdaTangential - lambda_t_old;
+ // Apply the final impulses
+ //var impulse = vec2.rotate_vec(new vec2(lambda_n, lambda_t), n);
+ var impulse = new Phaser.Vec2(lambda_n * n.x - lambda_t * n.y, lambda_t * n.x + lambda_n * n.y);
+ body1.velocity.multiplyAddByScalar(impulse, -m1_inv);
+ //body1.v.mad(impulse, -m1_inv);
+ body1.angularVelocity -= Phaser.Vec2Utils.cross(r1, impulse) * i1_inv;
+ //body1.w -= vec2.cross(r1, impulse) * i1_inv;
+ body2.velocity.multiplyAddByScalar(impulse, m2_inv);
+ //body2.v.mad(impulse, m2_inv);
+ body1.angularVelocity += Phaser.Vec2Utils.cross(r2, impulse) * i2_inv;
+ //body2.w += vec2.cross(r2, impulse) * i2_inv;
+ }
+ };
+ ContactSolver.prototype.solvePositionConstraints = function () {
+ var body1 = this.shape1.body;
+ var body2 = this.shape2.body;
+ var m1_inv = body1.massInverted;
+ var i1_inv = body1.inertiaInverted;
+ var m2_inv = body2.massInverted;
+ var i2_inv = body2.inertiaInverted;
+ var sum_m_inv = m1_inv + m2_inv;
+ var max_penetration = 0;
+ for(var i = 0; i < this.contacts.length; i++) {
+ var con = this.contacts[i];
+ var n = con.normal;
+ var r1 = new Phaser.Vec2();
+ var r2 = new Phaser.Vec2();
+ // Transformed r1, r2
+ Phaser.Vec2Utils.rotate(con.r1_local, body1.angle, r1);
+ //var r1 = vec2.rotate(con.r1_local, body1.a);
+ Phaser.Vec2Utils.rotate(con.r2_local, body2.angle, r2);
+ //var r2 = vec2.rotate(con.r2_local, body2.a);
+ // Contact points (corrected)
+ var p1 = new Phaser.Vec2();
+ var p2 = new Phaser.Vec2();
+ Phaser.Vec2Utils.add(body1.position, r1, p1);
+ //var p1 = vec2.add(body1.p, r1);
+ Phaser.Vec2Utils.add(body2.position, r2, p2);
+ //var p2 = vec2.add(body2.p, r2);
+ // Corrected delta vector
+ var dp = new Phaser.Vec2();
+ Phaser.Vec2Utils.subtract(p2, p1);
+ //var dp = vec2.sub(p2, p1);
+ // Position constraint
+ var c = Phaser.Vec2Utils.dot(dp, n) + con.depth;
+ var correction = this.clamp(Advanced.Manager.CONTACT_SOLVER_BAUMGARTE * (c + Advanced.Manager.CONTACT_SOLVER_COLLISION_SLOP), -Advanced.Manager.CONTACT_SOLVER_MAX_LINEAR_CORRECTION, 0);
+ if(correction == 0) {
+ continue;
+ }
+ // We don't need max_penetration less than or equal slop
+ max_penetration = Math.max(max_penetration, -c);
+ // Compute lambda for position constraint
+ // Solve (J * invM * JT) * lambda = -C / dt
+ var sn1 = Phaser.Vec2Utils.cross(r1, n);
+ var sn2 = Phaser.Vec2Utils.cross(r2, n);
+ var em_inv = sum_m_inv + body1.inertiaInverted * sn1 * sn1 + body2.inertiaInverted * sn2 * sn2;
+ var lambda_dt = em_inv == 0 ? 0 : -correction / em_inv;
+ // Apply correction impulses
+ var impulse_dt = new Phaser.Vec2();
+ Phaser.Vec2Utils.scale(n, lambda_dt, impulse_dt);
+ //var impulse_dt = vec2.scale(n, lambda_dt);
+ body1.position.multiplyAddByScalar(impulse_dt, -m1_inv);
+ //body1.p.mad(impulse_dt, -m1_inv);
+ body1.angle -= sn1 * lambda_dt * i1_inv;
+ body2.position.multiplyAddByScalar(impulse_dt, m2_inv);
+ //body2.p.mad(impulse_dt, m2_inv);
+ body2.angle += sn2 * lambda_dt * i2_inv;
+ }
+ return max_penetration <= Advanced.Manager.CONTACT_SOLVER_COLLISION_SLOP * 3;
+ };
+ ContactSolver.prototype.clamp = function (v, min, max) {
+ return v < min ? min : (v > max ? max : v);
+ };
+ return ContactSolver;
+ })();
+ Advanced.ContactSolver = ContactSolver;
+ })(Physics.Advanced || (Physics.Advanced = {}));
+ var Advanced = Physics.Advanced;
+ })(Phaser.Physics || (Phaser.Physics = {}));
+ var Physics = Phaser.Physics;
+})(Phaser || (Phaser = {}));
+var Phaser;
+(function (Phaser) {
+ (function (Physics) {
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /**
+ * Phaser - Advanced Physics - ShapePoly (convex only)
+ *
+ * Based on the work Ju Hyung Lee started in JS PhyRus.
+ */
+ (function (Advanced) {
+ var ShapePoly = (function (_super) {
+ __extends(ShapePoly, _super);
+ function ShapePoly(verts) {
+ _super.call(this, Advanced.Manager.SHAPE_TYPE_POLY);
+ this.verts = [];
+ this.planes = [];
+ this.tverts = [];
+ this.tplanes = [];
+ if(verts) {
+ for(var i = 0; i < verts.length; i++) {
+ Phaser.Vec2Utils.clone(verts[i], this.verts[i]);
+ this.tverts[i] = this.verts[i];
+ this.tplanes[i] = {
+ };
+ this.tplanes[i].n = new Phaser.Vec2();
+ this.tplanes[i].d = 0;
+ }
+ }
+ this.finishVerts();
+ }
+ ShapePoly.prototype.finishVerts = function () {
+ if(this.verts.length < 2) {
+ this.convexity = false;
+ this.planes = [];
+ return;
+ }
+ this.convexity = true;
+ this.tverts = [];
+ this.tplanes = [];
+ // Must be counter-clockwise verts
+ for(var i = 0; i < this.verts.length; i++) {
+ var a = this.verts[i];
+ var b = this.verts[(i + 1) % this.verts.length];
+ var n = Phaser.Vec2Utils.normalize(Phaser.Vec2Utils.perp(Phaser.Vec2Utils.subtract(a, b)));
+ this.planes[i] = {
+ };
+ this.planes[i].n = n;
+ this.planes[i].d = Phaser.Vec2Utils.dot(n, a);
+ this.tverts[i] = this.verts[i];
+ this.tplanes[i] = {
+ };
+ this.tplanes[i].n = new Phaser.Vec2();
+ this.tplanes[i].d = 0;
+ }
+ for(var i = 0; i < this.verts.length; i++) {
+ var b = this.verts[(i + 2) % this.verts.length];
+ var n = this.planes[i].n;
+ var d = this.planes[i].d;
+ if(Phaser.Vec2Utils.dot(n, b) - d > 0) {
+ this.convexity = false;
+ }
+ }
+ };
+ ShapePoly.prototype.duplicate = function () {
+ return new ShapePoly(this.verts);
+ };
+ ShapePoly.prototype.recenter = function (c) {
+ for(var i = 0; i < this.verts.length; i++) {
+ this.verts[i].subtract(c);
+ }
+ };
+ ShapePoly.prototype.transform = function (xf) {
+ for(var i = 0; i < this.verts.length; i++) {
+ this.verts[i] = xf.transform(this.verts[i]);
+ }
+ };
+ ShapePoly.prototype.untransform = function (xf) {
+ for(var i = 0; i < this.verts.length; i++) {
+ this.verts[i] = xf.untransform(this.verts[i]);
+ }
+ };
+ ShapePoly.prototype.area = function () {
+ return Advanced.Manager.areaForPoly(this.verts);
+ };
+ ShapePoly.prototype.centroid = function () {
+ return Advanced.Manager.centroidForPoly(this.verts);
+ };
+ ShapePoly.prototype.inertia = function (mass) {
+ return Advanced.Manager.inertiaForPoly(mass, this.verts, new Phaser.Vec2());
+ };
+ ShapePoly.prototype.cacheData = function (xf) {
+ this.bounds.clear();
+ var numVerts = this.verts.length;
+ if(numVerts == 0) {
+ return;
+ }
+ for(var i = 0; i < numVerts; i++) {
+ this.tverts[i] = xf.transform(this.verts[i]);
+ }
+ if(numVerts < 2) {
+ this.bounds.addPoint(this.tverts[0]);
+ return;
+ }
+ for(var i = 0; i < numVerts; i++) {
+ var a = this.tverts[i];
+ var b = this.tverts[(i + 1) % numVerts];
+ var n = Phaser.Vec2Utils.normalize(Phaser.Vec2Utils.perp(Phaser.Vec2Utils.subtract(a, b)));
+ this.tplanes[i].n = n;
+ this.tplanes[i].d = Phaser.Vec2Utils.dot(n, a);
+ this.bounds.addPoint(a);
+ }
+ };
+ ShapePoly.prototype.pointQuery = function (p) {
+ if(!this.bounds.containPoint(p)) {
+ return false;
+ }
+ return this.containPoint(p);
+ };
+ ShapePoly.prototype.findVertexByPoint = function (p, minDist) {
+ var dsq = minDist * minDist;
+ for(var i = 0; i < this.tverts.length; i++) {
+ if(Phaser.Vec2Utils.distanceSq(this.tverts[i], p) < dsq) {
+ return i;
+ }
+ }
+ return -1;
+ };
+ ShapePoly.prototype.findEdgeByPoint = function (p, minDist) {
+ var dsq = minDist * minDist;
+ var numVerts = this.tverts.length;
+ for(var i = 0; i < this.tverts.length; i++) {
+ var v1 = this.tverts[i];
+ var v2 = this.tverts[(i + 1) % numVerts];
+ var n = this.tplanes[i].n;
+ var dtv1 = Phaser.Vec2Utils.cross(v1, n);
+ var dtv2 = Phaser.Vec2Utils.cross(v2, n);
+ var dt = Phaser.Vec2Utils.cross(p, n);
+ if(dt > dtv1) {
+ if(Phaser.Vec2Utils.distanceSq(v1, p) < dsq) {
+ return i;
+ }
+ } else if(dt < dtv2) {
+ if(Phaser.Vec2Utils.distanceSq(v2, p) < dsq) {
+ return i;
+ }
+ } else {
+ var dist = Phaser.Vec2Utils.dot(n, p) - Phaser.Vec2Utils.dot(n, v1);
+ if(dist * dist < dsq) {
+ return i;
+ }
+ }
+ }
+ return -1;
+ };
+ ShapePoly.prototype.distanceOnPlane = function (n, d) {
+ var min = 999999;
+ for(var i = 0; i < this.verts.length; i++) {
+ min = Math.min(min, Phaser.Vec2Utils.dot(n, this.tverts[i]));
+ }
+ return min - d;
+ };
+ ShapePoly.prototype.containPoint = function (p) {
+ for(var i = 0; i < this.verts.length; i++) {
+ var plane = this.tplanes[i];
+ if(Phaser.Vec2Utils.dot(plane.n, p) - plane.d > 0) {
+ return false;
+ }
+ }
+ return true;
+ };
+ ShapePoly.prototype.containPointPartial = function (p, n) {
+ for(var i = 0; i < this.verts.length; i++) {
+ var plane = this.tplanes[i];
+ if(Phaser.Vec2Utils.dot(plane.n, n) < 0.0001) {
+ continue;
+ }
+ if(Phaser.Vec2Utils.dot(plane.n, p) - plane.d > 0) {
+ return false;
+ }
+ }
+ return true;
+ };
+ return ShapePoly;
+ })(Phaser.Physics.Advanced.Shape);
+ Advanced.ShapePoly = ShapePoly;
+ })(Physics.Advanced || (Physics.Advanced = {}));
+ var Advanced = Physics.Advanced;
+ })(Phaser.Physics || (Phaser.Physics = {}));
+ var Physics = Phaser.Physics;
+})(Phaser || (Phaser = {}));
+var Phaser;
+(function (Phaser) {
+ (function (Physics) {
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /**
+ * Phaser - Advanced Physics - ShapeBox
+ *
+ * Based on the work Ju Hyung Lee started in JS PhyRus.
+ */
+ (function (Advanced) {
+ var ShapeBox = (function (_super) {
+ __extends(ShapeBox, _super);
+ function ShapeBox(x, y, width, height) {
+ var hw = width * 0.5;
+ var hh = height * 0.5;
+ _super.call(this, [
+ new Phaser.Vec2(-hw + x, +hh + y),
+ new Phaser.Vec2(-hw + x, -hh + y),
+ new Phaser.Vec2(+hw + x, -hh + y),
+ new Phaser.Vec2(+hw + x, +hh + y)
+ ]);
+ }
+ return ShapeBox;
+ })(Phaser.Physics.Advanced.ShapePoly);
+ Advanced.ShapeBox = ShapeBox;
+ })(Physics.Advanced || (Physics.Advanced = {}));
+ var Advanced = Physics.Advanced;
+ })(Phaser.Physics || (Phaser.Physics = {}));
+ var Physics = Phaser.Physics;
+})(Phaser || (Phaser = {}));
+var Phaser;
+(function (Phaser) {
+ (function (Physics) {
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /**
+ * Phaser - Advanced Physics - Shape
+ *
+ * Based on the work Ju Hyung Lee started in JS PhyRus.
+ */
+ (function (Advanced) {
+ var ShapeSegment = (function (_super) {
+ __extends(ShapeSegment, _super);
+ function ShapeSegment(a, b, radius) {
+ _super.call(this, Advanced.Manager.SHAPE_TYPE_SEGMENT);
+ // What types are A and B??!
+ this.a = a.duplicate();
+ this.b = b.duplicate();
+ this.radius = radius;
+ this.normal = Phaser.Vec2Utils.perp(Phaser.Vec2Utils.subtract(b, a));
+ this.normal.normalize();
+ this.ta = new Phaser.Vec2();
+ this.tb = new Phaser.Vec2();
+ this.tn = new Phaser.Vec2();
+ this.finishVerts();
+ }
+ ShapeSegment.prototype.finishVerts = function () {
+ this.normal = Phaser.Vec2Utils.perp(Phaser.Vec2Utils.subtract(this.b, this.a));
+ this.normal.normalize();
+ this.radius = Math.abs(this.radius);
+ };
+ ShapeSegment.prototype.duplicate = function () {
+ return new ShapeSegment(this.a, this.b, this.radius);
+ };
+ ShapeSegment.prototype.recenter = function (c) {
+ this.a.subtract(c);
+ this.b.subtract(c);
+ };
+ ShapeSegment.prototype.transform = function (xf) {
+ this.a = xf.transform(this.a);
+ this.b = xf.transform(this.b);
+ };
+ ShapeSegment.prototype.untransform = function (xf) {
+ this.a = xf.untransform(this.a);
+ this.b = xf.untransform(this.b);
+ };
+ ShapeSegment.prototype.area = function () {
+ return Advanced.Manager.areaForSegment(this.a, this.b, this.radius);
+ };
+ ShapeSegment.prototype.centroid = function () {
+ return Advanced.Manager.centroidForSegment(this.a, this.b);
+ };
+ ShapeSegment.prototype.inertia = function (mass) {
+ return Advanced.Manager.inertiaForSegment(mass, this.a, this.b);
+ };
+ ShapeSegment.prototype.cacheData = function (xf) {
+ this.ta = xf.transform(this.a);
+ this.tb = xf.transform(this.b);
+ this.tn = Phaser.Vec2Utils.perp(Phaser.Vec2Utils.subtract(this.tb, this.ta)).normalize();
+ var l;
+ var r;
+ var t;
+ var b;
+ if(this.ta.x < this.tb.x) {
+ l = this.ta.x;
+ r = this.tb.x;
+ } else {
+ l = this.tb.x;
+ r = this.ta.x;
+ }
+ if(this.ta.y < this.tb.y) {
+ b = this.ta.y;
+ t = this.tb.y;
+ } else {
+ b = this.tb.y;
+ t = this.ta.y;
+ }
+ this.bounds.mins.set(l - this.radius, b - this.radius);
+ this.bounds.maxs.set(r + this.radius, t + this.radius);
+ };
+ ShapeSegment.prototype.pointQuery = function (p) {
+ if(!this.bounds.containPoint(p)) {
+ return false;
+ }
+ var dn = Phaser.Vec2Utils.dot(this.tn, p) - Phaser.Vec2Utils.dot(this.ta, this.tn);
+ var dist = Math.abs(dn);
+ if(dist > this.radius) {
+ return false;
+ }
+ var dt = Phaser.Vec2Utils.cross(p, this.tn);
+ var dta = Phaser.Vec2Utils.cross(this.ta, this.tn);
+ var dtb = Phaser.Vec2Utils.cross(this.tb, this.tn);
+ if(dt <= dta) {
+ if(dt < dta - this.radius) {
+ return false;
+ }
+ return Phaser.Vec2Utils.distanceSq(this.ta, p) < (this.radius * this.radius);
+ } else if(dt > dtb) {
+ if(dt > dtb + this.radius) {
+ return false;
+ }
+ return Phaser.Vec2Utils.distanceSq(this.tb, p) < (this.radius * this.radius);
+ }
+ return true;
+ };
+ ShapeSegment.prototype.findVertexByPoint = function (p, minDist) {
+ var dsq = minDist * minDist;
+ if(Phaser.Vec2Utils.distanceSq(this.ta, p) < dsq) {
+ return 0;
+ }
+ if(Phaser.Vec2Utils.distanceSq(this.tb, p) < dsq) {
+ return 1;
+ }
+ return -1;
+ };
+ ShapeSegment.prototype.distanceOnPlane = function (n, d) {
+ var a = Phaser.Vec2Utils.dot(n, this.ta) - this.radius;
+ var b = Phaser.Vec2Utils.dot(n, this.tb) - this.radius;
+ return Math.min(a, b) - d;
+ };
+ return ShapeSegment;
+ })(Phaser.Physics.Advanced.Shape);
+ Advanced.ShapeSegment = ShapeSegment;
+ })(Physics.Advanced || (Physics.Advanced = {}));
+ var Advanced = Physics.Advanced;
+ })(Phaser.Physics || (Phaser.Physics = {}));
+ var Physics = Phaser.Physics;
+})(Phaser || (Phaser = {}));
+var Phaser;
+(function (Phaser) {
+ (function (Physics) {
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ ///
+ /**
+ * Phaser - Advanced Physics - ShapeTriangle
+ *
+ * Based on the work Ju Hyung Lee started in JS PhyRus.
+ */
+ (function (Advanced) {
+ var ShapeTriangle = (function (_super) {
+ __extends(ShapeTriangle, _super);
+ function ShapeTriangle(p1, p2, p3) {
+ _super.call(this, [
+ new Phaser.Vec2(p1.x, p1.y),
+ new Phaser.Vec2(p2.x, p2.y),
+ new Phaser.Vec2(p3.x, p3.y)
+ ]);
+ }
+ return ShapeTriangle;
+ })(Phaser.Physics.Advanced.ShapePoly);
+ Advanced.ShapeTriangle = ShapeTriangle;
+ })(Physics.Advanced || (Physics.Advanced = {}));
+ var Advanced = Physics.Advanced;
+ })(Phaser.Physics || (Phaser.Physics = {}));
+ var Physics = Phaser.Physics;
+})(Phaser || (Phaser = {}));
///
///
///