mirror of
https://github.com/wassname/rl_2d_walker.js.git
synced 2026-10-03 12:52:06 +08:00
11583 lines
468 KiB
JavaScript
11583 lines
468 KiB
JavaScript
/** https://github.com/kripken/box2d.js v2.3.1 */
|
|
(function () {
|
|
var performance = {
|
|
now: function () {
|
|
return +new Date()
|
|
}
|
|
}
|
|
Function.prototype._extend = function (parent) {
|
|
this.prototype.parent = parent;
|
|
for (var x in parent.prototype) {
|
|
if (!this.prototype[x]) {
|
|
this.prototype[x] = parent.prototype[x]
|
|
}
|
|
}
|
|
};
|
|
Function.prototype._implement = function (parent) {
|
|
return this._extend(parent)
|
|
};
|
|
var b2Profiler = (function () {
|
|
|
|
function profileStruct(name, parent) {
|
|
this.name = name;
|
|
this.parent = parent;
|
|
this.children = {};
|
|
this.startTime = 0;
|
|
this.elapsedTime = 0;
|
|
this.totalTime = 0;
|
|
this.running = false;
|
|
this.childrenCount = 0
|
|
}
|
|
profileStruct.prototype = {
|
|
start: function () {
|
|
this.startTime = performance.now();
|
|
this.running = true
|
|
},
|
|
stop: function (reset) {
|
|
if (!this.running) {
|
|
return
|
|
}
|
|
this.running = false;
|
|
this.elapsedTime += performance.now() - this.startTime;
|
|
if (reset) {
|
|
this.start()
|
|
}
|
|
for (var x in this.children) {
|
|
this.children[x].stop()
|
|
}
|
|
},
|
|
reset: function (dontRun) {
|
|
if (!dontRun) {
|
|
this.running = true;
|
|
this.totalTime += this.elapsedTime;
|
|
this.start()
|
|
}
|
|
this.elapsedTime = 0;
|
|
for (var x in this.children) {
|
|
this.children[x].reset(true)
|
|
}
|
|
}
|
|
};
|
|
var profiles = [];
|
|
var root = new profileStruct("root");
|
|
|
|
function create(name, parent) {
|
|
if (!profiles) {
|
|
throw new Error("late profile creation not allowed")
|
|
}
|
|
var s = new profileStruct(name, parent || "root");
|
|
profiles.push(s);
|
|
return s
|
|
}
|
|
|
|
function destroy(profile) {
|
|
profile.childrenCount--;
|
|
delete profile.children[profile.name]
|
|
}
|
|
|
|
function recursiveParentCheck(node, profile) {
|
|
if (node.name === profile.parent) {
|
|
return node
|
|
}
|
|
for (var x in node.children) {
|
|
var n;
|
|
if (n = recursiveParentCheck(node.children[x], profile)) {
|
|
return n
|
|
}
|
|
}
|
|
return null
|
|
}
|
|
|
|
function init() {
|
|
while (profiles.length) {
|
|
var p = profiles.pop();
|
|
if (!(p.parentNode = recursiveParentCheck(root, p))) {
|
|
profiles.unshift(p)
|
|
} else {
|
|
p.parentNode.children[p.name] = p;
|
|
p.parentNode.childrenCount++
|
|
}
|
|
}
|
|
profiles = null
|
|
}
|
|
|
|
function resetAll() {
|
|
root.reset(true)
|
|
}
|
|
return {
|
|
create: create,
|
|
destroy: destroy,
|
|
init: init,
|
|
reset: resetAll,
|
|
profileRoot: root
|
|
}
|
|
}());
|
|
"use strict";
|
|
var b2_maxFloat = Number.MAX_VALUE;
|
|
var b2_epsilon = 2.220446049250313e-16;
|
|
var b2_pi = Math.PI;
|
|
var b2_maxManifoldPoints = 2;
|
|
var b2_maxPolygonVertices = 8;
|
|
var b2_aabbExtension = 0.1;
|
|
var b2_aabbMultiplier = 2;
|
|
var b2_linearSlop = 0.005;
|
|
var b2_angularSlop = (2 / 180 * b2_pi);
|
|
var b2_polygonRadius = (2 * b2_linearSlop);
|
|
var b2_maxSubSteps = 8;
|
|
var b2_maxTOIContacts = 32;
|
|
var b2_velocityThreshold = 1;
|
|
var b2_maxLinearCorrection = 0.2;
|
|
var b2_maxAngularCorrection = (8 / 180 * b2_pi);
|
|
var b2_maxTranslation = 2;
|
|
var b2_maxTranslationSquared = (b2_maxTranslation * b2_maxTranslation);
|
|
var b2_maxRotation = (0.5 * b2_pi);
|
|
var b2_maxRotationSquared = (b2_maxRotation * b2_maxRotation);
|
|
var b2_baumgarte = 0.2;
|
|
var b2_toiBaugarte = 0.75;
|
|
var b2_timeToSleep = 0.5;
|
|
var b2_linearSleepTolerance = 0.01;
|
|
var b2_angularSleepTolerance = (2 / 180 * b2_pi);
|
|
|
|
function b2Version(ma, mi, re) {
|
|
this.major = ma;
|
|
this.minor = mi;
|
|
this.revision = re
|
|
}
|
|
b2Version.prototype = {
|
|
toString: function () {
|
|
return this.major + "." + this.minor + "." + this.revision
|
|
}
|
|
};
|
|
var b2_version = new b2Version(2, 3, 1);
|
|
"use strict";
|
|
|
|
function b2IsValid(x) {
|
|
return isFinite(x) && !isNaN(x)
|
|
}
|
|
var sqrtf = Math.sqrt;
|
|
var atan2f = Math.atan2;
|
|
var sinf = Math.sin;
|
|
var cosf = Math.cos;
|
|
var floorf = Math.floor;
|
|
var ceilf = Math.ceil;
|
|
var b2Sqrt = sqrtf;
|
|
var b2Atan2 = atan2f;
|
|
|
|
function b2InvSqrt(x) {
|
|
return 1 / sqrtf(x)
|
|
}
|
|
|
|
function b2Vec2(x, y) {
|
|
if (typeof (x) !== "undefined") {
|
|
this.x = x;
|
|
this.y = y
|
|
} else {
|
|
this.x = this.y = 0
|
|
}
|
|
}
|
|
b2Vec2.prototype = {
|
|
Clone: function () {
|
|
return new b2Vec2(this.x, this.y)
|
|
},
|
|
SetZero: function () {
|
|
this.x = 0;
|
|
this.y = 0;
|
|
return this
|
|
},
|
|
Set: function (x_, y_) {
|
|
this.x = x_;
|
|
this.y = y_;
|
|
return this
|
|
},
|
|
Assign: function (l) {
|
|
this.x = l.x;
|
|
this.y = l.y;
|
|
return this
|
|
},
|
|
Negate: function () {
|
|
var v = new b2Vec2();
|
|
v.Set(-this.x, -this.y);
|
|
return v
|
|
},
|
|
get_i: function (i) {
|
|
switch (i) {
|
|
case 0:
|
|
return this.x;
|
|
case 1:
|
|
return this.y
|
|
}
|
|
},
|
|
set_i: function (i, v) {
|
|
switch (i) {
|
|
case 0:
|
|
return this.x = v;
|
|
case 1:
|
|
return this.y = v
|
|
}
|
|
},
|
|
Add: function (v) {
|
|
this.x += v.x;
|
|
this.y += v.y;
|
|
return this
|
|
},
|
|
Subtract: function (v) {
|
|
this.x -= v.x;
|
|
this.y -= v.y;
|
|
return this
|
|
},
|
|
Multiply: function (a) {
|
|
this.x *= a;
|
|
this.y *= a;
|
|
return this
|
|
},
|
|
Length: function () {
|
|
return b2Sqrt(this.x * this.x + this.y * this.y)
|
|
},
|
|
LengthSquared: function () {
|
|
return this.x * this.x + this.y * this.y
|
|
},
|
|
Normalize: function () {
|
|
var length = this.Length();
|
|
if (length < b2_epsilon) {
|
|
return 0
|
|
}
|
|
var invLength = 1 / length;
|
|
this.x *= invLength;
|
|
this.y *= invLength;
|
|
return length
|
|
},
|
|
IsValid: function () {
|
|
return b2IsValid(this.x) && b2IsValid(this.y)
|
|
},
|
|
Skew: function () {
|
|
return new b2Vec2(-this.y, this.x)
|
|
},
|
|
_serialize: function (out) {
|
|
var obj = out || [];
|
|
obj[0] = this.x;
|
|
obj[1] = this.y;
|
|
return obj
|
|
},
|
|
_deserialize: function (data) {
|
|
this.x = data[0];
|
|
this.y = data[1]
|
|
}
|
|
};
|
|
b2Vec2.Add = function (a, b) {
|
|
return new b2Vec2(a.x + b.x, a.y + b.y)
|
|
};
|
|
b2Vec2.Subtract = function (a, b) {
|
|
return new b2Vec2(a.x - b.x, a.y - b.y)
|
|
};
|
|
b2Vec2.Equals = function (a, b) {
|
|
return a.x == b.x && a.y == b.y
|
|
};
|
|
b2Vec2.Multiply = function (s, a) {
|
|
return new b2Vec2(s * a.x, s * a.y)
|
|
};
|
|
b2Vec2.Negate = function (a) {
|
|
return new b2Vec2(-a.x, -a.y)
|
|
};
|
|
|
|
function b2Vec3(x, y, z) {
|
|
if (typeof (x) !== "undefined") {
|
|
this.x = x;
|
|
this.y = y;
|
|
this.z = z
|
|
}
|
|
}
|
|
b2Vec3.prototype = {
|
|
Clone: function () {
|
|
return new b2Vec3(this.x, this.y, this.z)
|
|
},
|
|
SetZero: function () {
|
|
this.x = 0;
|
|
this.y = 0;
|
|
this.z = 0
|
|
},
|
|
Set: function (x_, y_, z_) {
|
|
this.x = x_;
|
|
this.y = y_;
|
|
this.z = z_
|
|
},
|
|
Negate: function () {
|
|
var v = new b2Vec3();
|
|
v.Set(-this.x, -this.y, -this.z);
|
|
return v
|
|
},
|
|
Add: function (v) {
|
|
this.x += v.x;
|
|
this.y += v.y;
|
|
this.z += v.z
|
|
},
|
|
Subtract: function (v) {
|
|
this.x -= v.x;
|
|
this.y -= v.y;
|
|
this.z -= v.z
|
|
},
|
|
Multiply: function (s) {
|
|
this.x *= s;
|
|
this.y *= s;
|
|
this.z *= s
|
|
},
|
|
x: 0,
|
|
y: 0,
|
|
z: 0
|
|
};
|
|
b2Vec3.Multiply = function (s, a) {
|
|
return new b2Vec3(s * a.x, s * a.y, s * a.z)
|
|
};
|
|
b2Vec3.Add = function (a, b) {
|
|
return new b2Vec3(a.x + b.x, a.y + b.y, a.z + b.z)
|
|
};
|
|
b2Vec3.Subtract = function (a, b) {
|
|
return new b2Vec3(a.x - b.x, a.y - b.y, a.z - b.z)
|
|
};
|
|
|
|
function b2Mat22(c1, c2) {
|
|
this.ex = c1 ? c1.Clone() : new b2Vec2();
|
|
this.ey = c2 ? c2.Clone() : new b2Vec2()
|
|
}
|
|
b2Mat22.prototype = {
|
|
Set: function (c1, c2) {
|
|
this.ex.Assign(c1);
|
|
this.ey.Assign(c2)
|
|
},
|
|
Assign: function (mat) {
|
|
this.ex.Assign(mat.ex);
|
|
this.ey.Assign(mat.ey)
|
|
},
|
|
SetIdentity: function () {
|
|
this.ex.x = 1;
|
|
this.ey.x = 0;
|
|
this.ex.y = 0;
|
|
this.ey.y = 1
|
|
},
|
|
SetZero: function () {
|
|
this.ex.x = 0;
|
|
this.ey.x = 0;
|
|
this.ex.y = 0;
|
|
this.ey.y = 0
|
|
},
|
|
GetInverse: function () {
|
|
var a = this.ex.x,
|
|
b = this.ey.x,
|
|
c = this.ex.y,
|
|
d = this.ey.y;
|
|
var B = new b2Mat22();
|
|
var det = a * d - b * c;
|
|
if (det != 0) {
|
|
det = 1 / det
|
|
}
|
|
B.ex.x = det * d;
|
|
B.ey.x = -det * b;
|
|
B.ex.y = -det * c;
|
|
B.ey.y = det * a;
|
|
return B
|
|
},
|
|
Solve: function (b) {
|
|
var a11 = this.ex.x,
|
|
a12 = this.ey.x,
|
|
a21 = this.ex.y,
|
|
a22 = this.ey.y;
|
|
var det = a11 * a22 - a12 * a21;
|
|
if (det != 0) {
|
|
det = 1 / det
|
|
}
|
|
var x = new b2Vec2();
|
|
x.x = det * (a22 * b.x - a12 * b.y);
|
|
x.y = det * (a11 * b.y - a21 * b.x);
|
|
return x
|
|
}
|
|
};
|
|
b2Mat22.Add = function (A, B) {
|
|
return new b2Mat22(b2Vec2.Add(A.ex, B.ex), b2Vec2.Add(A.ey, B.ey))
|
|
};
|
|
|
|
function b2Mat33(c1, c2, c3) {
|
|
this.ex = c1 ? c1.Clone() : new b2Vec3();
|
|
this.ey = c2 ? c2.Clone() : new b2Vec3();
|
|
this.ez = c3 ? c3.Clone() : new b2Vec3()
|
|
}
|
|
b2Mat33.prototype = {
|
|
SetZero: function () {
|
|
this.ex.SetZero();
|
|
this.ey.SetZero();
|
|
this.ez.SetZero()
|
|
},
|
|
Solve33: function (b) {
|
|
var det = b2Dot_v3_v3(this.ex, b2Cross_v3_v3(this.ey, this.ez));
|
|
if (det != 0) {
|
|
det = 1 / det
|
|
}
|
|
var x = new b2Vec3();
|
|
x.x = det * b2Dot_v3_v3(b, b2Cross_v3_v3(this.ey, this.ez));
|
|
x.y = det * b2Dot_v3_v3(this.ex, b2Cross_v3_v3(b, this.ez));
|
|
x.z = det * b2Dot_v3_v3(this.ex, b2Cross_v3_v3(this.ey, b));
|
|
return x
|
|
},
|
|
Solve22: function (b) {
|
|
var a11 = this.ex.x,
|
|
a12 = this.ey.x,
|
|
a21 = this.ex.y,
|
|
a22 = this.ey.y;
|
|
var det = a11 * a22 - a12 * a21;
|
|
if (det != 0) {
|
|
det = 1 / det
|
|
}
|
|
var x = new b2Vec2();
|
|
x.x = det * (a22 * b.x - a12 * b.y);
|
|
x.y = det * (a11 * b.y - a21 * b.x);
|
|
return x
|
|
},
|
|
GetInverse22: function (M) {
|
|
var a = this.ex.x,
|
|
b = this.ey.x,
|
|
c = this.ex.y,
|
|
d = this.ey.y;
|
|
var det = a * d - b * c;
|
|
if (det != 0) {
|
|
det = 1 / det
|
|
}
|
|
M.ex.x = det * d;
|
|
M.ey.x = -det * b;
|
|
M.ex.z = 0;
|
|
M.ex.y = -det * c;
|
|
M.ey.y = det * a;
|
|
M.ey.z = 0;
|
|
M.ez.x = 0;
|
|
M.ez.y = 0;
|
|
M.ez.z = 0
|
|
},
|
|
GetSymInverse33: function (M) {
|
|
var det = b2Dot_v3_v3(this.ex, b2Cross_v3_v3(this.ey, this.ez));
|
|
if (det != 0) {
|
|
det = 1 / det
|
|
}
|
|
var a11 = this.ex.x,
|
|
a12 = this.ey.x,
|
|
a13 = this.ez.x;
|
|
var a22 = this.ey.y,
|
|
a23 = this.ez.y;
|
|
var a33 = this.ez.z;
|
|
M.ex.x = det * (a22 * a33 - a23 * a23);
|
|
M.ex.y = det * (a13 * a23 - a12 * a33);
|
|
M.ex.z = det * (a12 * a23 - a13 * a22);
|
|
M.ey.x = M.ex.y;
|
|
M.ey.y = det * (a11 * a33 - a13 * a13);
|
|
M.ey.z = det * (a13 * a12 - a11 * a23);
|
|
M.ez.x = M.ex.z;
|
|
M.ez.y = M.ey.z;
|
|
M.ez.z = det * (a11 * a22 - a12 * a12)
|
|
}
|
|
};
|
|
|
|
function b2Rot(angle, c) {
|
|
if (typeof (c) !== "undefined") {
|
|
this.s = angle;
|
|
this.c = c
|
|
} else {
|
|
if (typeof (angle) !== "undefined") {
|
|
this.Set(angle)
|
|
}
|
|
}
|
|
}
|
|
b2Rot.prototype = {
|
|
Clone: function () {
|
|
return new b2Rot(this.s, this.c)
|
|
},
|
|
Assign: function (l) {
|
|
this.s = l.s;
|
|
this.c = l.c
|
|
},
|
|
Set: function (x) {
|
|
this.s = sinf(x);
|
|
this.c = cosf(x)
|
|
},
|
|
SetIdentity: function () {
|
|
this.s = 0;
|
|
this.c = 1
|
|
},
|
|
GetAngle: function () {
|
|
return b2Atan2(this.s, this.c)
|
|
},
|
|
GetXAxis: function () {
|
|
return new b2Vec2(this.c, this.s)
|
|
},
|
|
GetYAxis: function () {
|
|
return new b2Vec2(-this.s, this.c)
|
|
},
|
|
s: 0,
|
|
c: 1
|
|
};
|
|
|
|
function b2Transform(position, rotation) {
|
|
this.p = new b2Vec2();
|
|
this.q = new b2Rot();
|
|
if (position) {
|
|
this.p.Assign(position);
|
|
this.q.Assign(rotation)
|
|
}
|
|
}
|
|
b2Transform.prototype = {
|
|
Clone: function () {
|
|
var xf = new b2Transform(this.p, this.q);
|
|
return xf
|
|
},
|
|
Assign: function (xf) {
|
|
this.p.Assign(xf.p);
|
|
this.q.Assign(xf.q)
|
|
},
|
|
SetIdentity: function () {
|
|
this.p.SetZero();
|
|
this.q.SetIdentity()
|
|
},
|
|
Set: function (position, angle) {
|
|
this.p.Assign(position);
|
|
this.q.Set(angle)
|
|
}
|
|
};
|
|
|
|
function b2Sweep() {
|
|
this.localCenter = new b2Vec2();
|
|
this.c0 = new b2Vec2();
|
|
this.c = new b2Vec2()
|
|
}
|
|
b2Sweep.prototype = {
|
|
Assign: function (sweep) {
|
|
this.localCenter.Assign(sweep.localCenter);
|
|
this.c0.Assign(sweep.c0);
|
|
this.c.Assign(sweep.c);
|
|
this.a = sweep.a;
|
|
this.a0 = sweep.a0;
|
|
this.alpha0 = sweep.alpha0
|
|
},
|
|
Clone: function () {
|
|
var sweep = new b2Sweep();
|
|
sweep.localCenter.Assign(this.localCenter);
|
|
sweep.c0.Assign(this.c0);
|
|
sweep.c.Assign(this.c);
|
|
sweep.a = this.a;
|
|
sweep.a0 = this.a0;
|
|
sweep.alpha0 = this.alpha0;
|
|
return sweep
|
|
},
|
|
GetTransform: function (xf, beta) {
|
|
xf.p.x = ((1 - beta) * this.c0.x) + (beta * this.c.x);
|
|
xf.p.y = ((1 - beta) * this.c0.y) + (beta * this.c.y);
|
|
var angle = (1 - beta) * this.a0 + beta * this.a;
|
|
xf.q.Set(angle);
|
|
xf.p.x -= xf.q.c * this.localCenter.x - xf.q.s * this.localCenter.y;
|
|
xf.p.y -= xf.q.s * this.localCenter.x + xf.q.c * this.localCenter.y
|
|
},
|
|
Advance: function (alpha) {
|
|
var beta = (alpha - this.alpha0) / (1 - this.alpha0);
|
|
this.c0.Add(b2Vec2.Multiply(beta, b2Vec2.Subtract(this.c, this.c0)));
|
|
this.a0 += beta * (this.a - this.a0);
|
|
this.alpha0 = alpha
|
|
},
|
|
Normalize: function () {
|
|
var twoPi = 2 * b2_pi;
|
|
var d = twoPi * floorf(this.a0 / twoPi);
|
|
this.a0 -= d;
|
|
this.a -= d
|
|
},
|
|
a0: 0,
|
|
a: 0,
|
|
alpha0: 0
|
|
};
|
|
|
|
function b2Dot_v2_v2(a, b) {
|
|
return a.x * b.x + a.y * b.y
|
|
}
|
|
|
|
function b2Cross_v2_v2(a, b) {
|
|
return a.x * b.y - a.y * b.x
|
|
}
|
|
|
|
function b2Cross_v2_f(a, s) {
|
|
return new b2Vec2(s * a.y, -s * a.x)
|
|
}
|
|
|
|
function b2Cross_f_v2(s, a) {
|
|
return new b2Vec2(-s * a.y, s * a.x)
|
|
}
|
|
|
|
function b2Mul_m22_v2(A, v) {
|
|
return new b2Vec2(A.ex.x * v.x + A.ey.x * v.y, A.ex.y * v.x + A.ey.y * v.y)
|
|
}
|
|
|
|
function b2MulT_m22_v2(A, v) {
|
|
return new b2Vec2(b2Dot_v2_v2(v, A.ex), b2Dot_v2_v2(v, A.ey))
|
|
}
|
|
|
|
function b2Distance(a, b) {
|
|
var c = b2Vec2.Subtract(a, b);
|
|
return c.Length()
|
|
}
|
|
|
|
function b2DistanceSquared(a, b) {
|
|
var c = b2Vec2.Subtract(a, b);
|
|
return b2Dot_v2_v2(c, c)
|
|
}
|
|
|
|
function b2Dot_v3_v3(a, b) {
|
|
return a.x * b.x + a.y * b.y + a.z * b.z
|
|
}
|
|
|
|
function b2Cross_v3_v3(a, b) {
|
|
return new b2Vec3(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x)
|
|
}
|
|
|
|
function b2Mul_m22_m22(A, B) {
|
|
return new b2Mat22(b2Mul_m22_v2(A, B.ex), b2Mul_m22_v2(A, B.ey))
|
|
}
|
|
|
|
function b2MulT_m22_m22(A, B) {
|
|
var c1 = new b2Vec2(b2Dot_v2_v2(A.ex, B.ex), b2Dot_v2_v2(A.ey, B.ex));
|
|
var c2 = new b2Vec2(b2Dot_v2_v2(A.ex, B.ey), b2Dot_v2_v2(A.ey, B.ey));
|
|
return new b2Mat22(c1, c2)
|
|
}
|
|
|
|
function b2Mul_m33_v3(A, v) {
|
|
return b2Vec3.Add(b2Vec3.Add(b2Vec3.Multiply(v.x, A.ex), b2Vec3.Multiply(v.y, A.ey)), b2Vec3.Multiply(v.z, A.ez))
|
|
}
|
|
|
|
function b2Mul22_m33_v2(A, v) {
|
|
return new b2Vec2(A.ex.x * v.x + A.ey.x * v.y, A.ex.y * v.x + A.ey.y * v.y)
|
|
}
|
|
|
|
function b2Mul_r_r(q, r) {
|
|
var qr = new b2Rot();
|
|
qr.s = q.s * r.c + q.c * r.s;
|
|
qr.c = q.c * r.c - q.s * r.s;
|
|
return qr
|
|
}
|
|
|
|
function b2MulT_r_r(q, r) {
|
|
var qr = new b2Rot();
|
|
qr.s = q.c * r.s - q.s * r.c;
|
|
qr.c = q.c * r.c + q.s * r.s;
|
|
return qr
|
|
}
|
|
|
|
function b2Mul_r_v2(q, v) {
|
|
return new b2Vec2(q.c * v.x - q.s * v.y, q.s * v.x + q.c * v.y)
|
|
}
|
|
|
|
function b2MulT_r_v2(q, v) {
|
|
return new b2Vec2(q.c * v.x + q.s * v.y, -q.s * v.x + q.c * v.y)
|
|
}
|
|
|
|
function b2Mul_t_v2(T, v) {
|
|
return new b2Vec2((T.q.c * v.x - T.q.s * v.y) + T.p.x, (T.q.s * v.x + T.q.c * v.y) + T.p.y)
|
|
}
|
|
|
|
function b2MulT_t_v2(T, v) {
|
|
var px = v.x - T.p.x;
|
|
var py = v.y - T.p.y;
|
|
var x = (T.q.c * px + T.q.s * py);
|
|
var y = (-T.q.s * px + T.q.c * py);
|
|
return new b2Vec2(x, y)
|
|
}
|
|
|
|
function b2Mul_t_t(A, B) {
|
|
var C = new b2Transform();
|
|
C.q = b2Mul_r_r(A.q, B.q);
|
|
C.p = b2Vec2.Add(b2Mul_r_v2(A.q, B.p), A.p);
|
|
return C
|
|
}
|
|
|
|
function b2MulT_t_t(A, B) {
|
|
var C = new b2Transform();
|
|
C.q = b2MulT_r_r(A.q, B.q);
|
|
var tvx = B.p.x - A.p.x;
|
|
var tvy = B.p.y - A.p.y;
|
|
C.p.x = A.q.c * tvx + A.q.s * tvy;
|
|
C.p.y = -A.q.s * tvx + A.q.c * tvy;
|
|
return C
|
|
}
|
|
var b2Abs = Math.abs;
|
|
|
|
function b2Abs_v2(a) {
|
|
return new b2Vec2(b2Abs(a.x), b2Abs(a.y))
|
|
}
|
|
|
|
function b2Abs_m22(A) {
|
|
return new b2Mat22(b2Abs_v2(A.ex), b2Abs_v2(A.ey))
|
|
}
|
|
var b2Min = Math.min;
|
|
|
|
function b2Min_v2(a, b) {
|
|
return new b2Vec2(b2Min(a.x, b.x), b2Min(a.y, b.y))
|
|
}
|
|
var b2Max = Math.max;
|
|
|
|
function b2Max_v2(a, b) {
|
|
return new b2Vec2(b2Max(a.x, b.x), b2Max(a.y, b.y))
|
|
}
|
|
|
|
function b2Clamp(a, low, high) {
|
|
return b2Max(low, b2Min(a, high))
|
|
}
|
|
|
|
function b2Clamp_v2(a, low, high) {
|
|
return b2Max_v2(low, b2Min_v2(a, high))
|
|
}
|
|
|
|
function b2NextPowerOfTwo(x) {
|
|
x |= (x >> 1);
|
|
x |= (x >> 2);
|
|
x |= (x >> 4);
|
|
x |= (x >> 8);
|
|
x |= (x >> 16);
|
|
return x + 1
|
|
}
|
|
|
|
function b2IsPowerOfTwo(x) {
|
|
var result = x > 0 && (x & (x - 1)) == 0;
|
|
return result
|
|
}
|
|
var RAND_LIMIT = 32767;
|
|
|
|
function b2RandomFloat(lo, hi) {
|
|
var r = Math.random();
|
|
if (typeof (lo) !== "undefined") {
|
|
r = (hi - lo) * r + lo
|
|
} else {
|
|
r = 2 * r - 1
|
|
}
|
|
return r
|
|
}
|
|
"use strict";
|
|
|
|
function b2Color(r, g, b) {
|
|
this.r = r || 0;
|
|
this.g = g || 0;
|
|
this.b = b || 0
|
|
}
|
|
b2Color.prototype = {
|
|
Set: function (r, g, b) {
|
|
this.r = r;
|
|
this.g = g;
|
|
this.b = b
|
|
}
|
|
};
|
|
|
|
function b2Draw() {}
|
|
b2Draw.prototype = {
|
|
SetFlags: function (flags) {
|
|
this.m_drawFlags = flags
|
|
},
|
|
GetFlags: function () {
|
|
return this.m_drawFlags
|
|
},
|
|
AppendFlags: function (flags) {
|
|
this.m_drawFlags |= flags
|
|
},
|
|
ClearFlags: function (flags) {
|
|
this.m_drawFlags &= ~flags
|
|
},
|
|
ToggleFlags: function (flags) {
|
|
this.m_drawFlags ^= flags
|
|
},
|
|
DrawPolygon: function (vertices, vertexCount, color) {},
|
|
DrawSolidPolygon: function (vertices, vertexCount, color) {},
|
|
DrawCircle: function (center, radius, color) {},
|
|
DrawSolidCircle: function (center, radius, axis, color) {},
|
|
DrawSegment: function (p1, p2, color) {},
|
|
DrawTransform: function (xf) {},
|
|
m_drawFlags: 0
|
|
};
|
|
b2Draw.e_shapeBit = 1;
|
|
b2Draw.e_jointBit = 2;
|
|
b2Draw.e_aabbBit = 4;
|
|
b2Draw.e_centerOfMassBit = 8;
|
|
b2Draw.e_contactPoints = 16;
|
|
b2Draw.e_contactNormals = 32;
|
|
b2Draw.e_contactImpulses = 64;
|
|
b2Draw.e_frictionImpulses = 128;
|
|
b2Draw.e_statistics = 256;
|
|
b2Draw.e_profile = 512;
|
|
b2Draw.e_pairBit = 1024;
|
|
|
|
"use strict";
|
|
function b2Timer() {
|
|
this.Reset()
|
|
}
|
|
b2Timer.prototype = {
|
|
Reset: function () {
|
|
this.m_start = performance.now()
|
|
},
|
|
GetMilliseconds: function () {
|
|
return performance.now() - this.m_start
|
|
}
|
|
};
|
|
"use strict";
|
|
|
|
function b2MassData() {
|
|
this.mass = 0;
|
|
this.center = new b2Vec2();
|
|
this.I = 0
|
|
}
|
|
|
|
function b2Shape() {
|
|
this.m_type = 0;
|
|
this.m_radius = 0
|
|
}
|
|
b2Shape.prototype = {
|
|
Clone: function () {},
|
|
GetType: function () {
|
|
return this.m_type
|
|
},
|
|
GetChildCount: function () {},
|
|
TestPoint: function (xf, p) {},
|
|
RayCast: function (output, input, transform, childIndex) {},
|
|
ComputeAABB: function (aabb, xf, childIndex) {},
|
|
ComputeMass: function (massData, density) {},
|
|
_serialize: function (out) {
|
|
var obj = out || {};
|
|
obj.m_type = this.m_type;
|
|
obj.m_radius = this.m_radius;
|
|
return obj
|
|
},
|
|
_deserialize: function (data) {
|
|
this.m_radius = data.m_radius
|
|
}
|
|
};
|
|
b2Shape.e_circle = 0;
|
|
b2Shape.e_edge = 1;
|
|
b2Shape.e_polygon = 2;
|
|
b2Shape.e_chain = 3;
|
|
b2Shape.e_typeCount = 4;
|
|
"use strict";
|
|
|
|
function b2CircleShape() {
|
|
this.parent.call(this);
|
|
this.m_type = b2Shape.e_circle;
|
|
this.m_radius = 0;
|
|
this.m_p = new b2Vec2();
|
|
Object.seal(this)
|
|
}
|
|
b2CircleShape.prototype = {
|
|
Clone: function () {
|
|
var shape = new b2CircleShape();
|
|
shape.m_radius = this.m_radius;
|
|
shape.m_p = this.m_p.Clone();
|
|
return shape
|
|
},
|
|
GetChildCount: function () {
|
|
return 1
|
|
},
|
|
TestPoint: function (transform, p) {
|
|
var center = b2Vec2.Add(transform.p, b2Mul_r_v2(transform.q, this.m_p));
|
|
var d = b2Vec2.Subtract(p, center);
|
|
return b2Dot_v2_v2(d, d) <= this.m_radius * this.m_radius
|
|
},
|
|
RayCast: function (output, input, transform, childIndex) {
|
|
var position = b2Vec2.Add(transform.p, b2Mul_r_v2(transform.q, this.m_p));
|
|
var s = b2Vec2.Subtract(input.p1, position);
|
|
var b = b2Dot_v2_v2(s, s) - this.m_radius * this.m_radius;
|
|
var r = b2Vec2.Subtract(input.p2, input.p1);
|
|
var c = b2Dot_v2_v2(s, r);
|
|
var rr = b2Dot_v2_v2(r, r);
|
|
var sigma = c * c - rr * b;
|
|
if (sigma < 0 || rr < b2_epsilon) {
|
|
return false
|
|
}
|
|
var a = -(c + b2Sqrt(sigma));
|
|
if (0 <= a && a <= input.maxFraction * rr) {
|
|
a /= rr;
|
|
output.fraction = a;
|
|
output.normal = b2Vec2.Add(s, b2Vec2.Multiply(a, r));
|
|
output.normal.Normalize();
|
|
return true
|
|
}
|
|
return false
|
|
},
|
|
ComputeAABB: function (aabb, transform, childIndex) {
|
|
var px = transform.p.x + (transform.q.c * this.m_p.x - transform.q.s * this.m_p.y);
|
|
var py = transform.p.y + (transform.q.s * this.m_p.x + transform.q.c * this.m_p.y);
|
|
aabb.lowerBound.x = px - this.m_radius;
|
|
aabb.lowerBound.y = py - this.m_radius;
|
|
aabb.upperBound.x = px + this.m_radius;
|
|
aabb.upperBound.y = py + this.m_radius
|
|
},
|
|
ComputeMass: function (massData, density) {
|
|
massData.mass = density * b2_pi * this.m_radius * this.m_radius;
|
|
massData.center = this.m_p;
|
|
massData.I = massData.mass * (0.5 * this.m_radius * this.m_radius + b2Dot_v2_v2(this.m_p, this.m_p))
|
|
},
|
|
GetSupport: function (d) {
|
|
return 0
|
|
},
|
|
GetSupportVertex: function (d) {
|
|
return this.m_p
|
|
},
|
|
GetVertexCount: function () {
|
|
return 1
|
|
},
|
|
GetVertex: function (index) {
|
|
return this.m_p
|
|
},
|
|
_serialize: function (out) {
|
|
var obj = out || {};
|
|
this.parent.prototype._serialize.call(this, obj);
|
|
obj.m_p = this.m_p._serialize();
|
|
return obj
|
|
},
|
|
_deserialize: function (data) {
|
|
this.parent.prototype._deserialize.call(this, data);
|
|
this.m_p._deserialize(data.m_p)
|
|
}
|
|
};
|
|
b2CircleShape._extend(b2Shape);
|
|
"use strict";
|
|
|
|
function b2EdgeShape() {
|
|
this.parent.call(this);
|
|
this.m_type = b2Shape.e_edge;
|
|
this.m_radius = b2_polygonRadius;
|
|
this.m_vertex0 = new b2Vec2();
|
|
this.m_vertex1 = new b2Vec2();
|
|
this.m_vertex2 = new b2Vec2();
|
|
this.m_vertex3 = new b2Vec2();
|
|
this.m_hasVertex0 = false;
|
|
this.m_hasVertex3 = false;
|
|
Object.seal(this)
|
|
}
|
|
b2EdgeShape.prototype = {
|
|
Set: function (v1, v2) {
|
|
this.m_vertex1.Assign(v1);
|
|
this.m_vertex2.Assign(v2);
|
|
this.m_hasVertex0 = false;
|
|
this.m_hasVertex3 = false
|
|
},
|
|
Clone: function () {
|
|
var shape = new b2EdgeShape();
|
|
shape.m_vertex0 = this.m_vertex0.Clone();
|
|
shape.m_vertex1 = this.m_vertex1.Clone();
|
|
shape.m_vertex2 = this.m_vertex2.Clone();
|
|
shape.m_vertex3 = this.m_vertex3.Clone();
|
|
shape.m_hasVertex0 = this.m_hasVertex0;
|
|
shape.m_hasVertex3 = this.m_hasVertex3;
|
|
return shape
|
|
},
|
|
GetChildCount: function () {
|
|
return 1
|
|
},
|
|
TestPoint: function (transform, p) {
|
|
return false
|
|
},
|
|
RayCast: function (output, input, xf, childIndex) {
|
|
var p1 = b2MulT_r_v2(xf.q, b2Vec2.Subtract(input.p1, xf.p));
|
|
var p2 = b2MulT_r_v2(xf.q, b2Vec2.Subtract(input.p2, xf.p));
|
|
var d = b2Vec2.Subtract(p2, p1);
|
|
var v1 = this.m_vertex1;
|
|
var v2 = this.m_vertex2;
|
|
var e = b2Vec2.Subtract(v2, v1);
|
|
var normal = new b2Vec2(e.y, -e.x);
|
|
normal.Normalize();
|
|
var numerator = b2Dot_v2_v2(normal, b2Vec2.Subtract(v1, p1));
|
|
var denominator = b2Dot_v2_v2(normal, d);
|
|
if (denominator == 0) {
|
|
return false
|
|
}
|
|
var t = numerator / denominator;
|
|
if (t < 0 || input.maxFraction < t) {
|
|
return false
|
|
}
|
|
var q = b2Vec2.Add(p1, b2Vec2.Multiply(t, d));
|
|
var r = b2Vec2.Subtract(v2, v1);
|
|
var rr = b2Dot_v2_v2(r, r);
|
|
if (rr == 0) {
|
|
return false
|
|
}
|
|
var s = b2Dot_v2_v2(b2Vec2.Subtract(q, v1), r) / rr;
|
|
if (s < 0 || 1 < s) {
|
|
return false
|
|
}
|
|
output.fraction = t;
|
|
if (numerator > 0) {
|
|
output.normal = b2Mul_r_v2(xf.q, normal).Negate()
|
|
} else {
|
|
output.normal = b2Mul_r_v2(xf.q, normal)
|
|
}
|
|
return true
|
|
},
|
|
ComputeAABB: function (aabb, xf, childIndex) {
|
|
var v1x = (xf.q.c * this.m_vertex1.x - xf.q.s * this.m_vertex1.y) + xf.p.x;
|
|
var v1y = (xf.q.s * this.m_vertex1.x + xf.q.c * this.m_vertex1.y) + xf.p.y;
|
|
var v2x = (xf.q.c * this.m_vertex2.x - xf.q.s * this.m_vertex2.y) + xf.p.x;
|
|
var v2y = (xf.q.s * this.m_vertex2.x + xf.q.c * this.m_vertex2.y) + xf.p.y;
|
|
var lowerx = b2Min(v1x, v2x);
|
|
var lowery = b2Min(v1y, v2y);
|
|
var upperx = b2Max(v1x, v2x);
|
|
var uppery = b2Max(v1y, v2y);
|
|
aabb.lowerBound.x = lowerx - this.m_radius;
|
|
aabb.lowerBound.y = lowery - this.m_radius;
|
|
aabb.upperBound.x = upperx + this.m_radius;
|
|
aabb.upperBound.y = uppery + this.m_radius
|
|
},
|
|
ComputeMass: function (massData, density) {
|
|
massData.mass = 0;
|
|
massData.center = b2Vec2.Multiply(0.5, b2Vec2.Add(this.m_vertex1, this.m_vertex2));
|
|
massData.I = 0
|
|
},
|
|
_serialize: function (out) {
|
|
var obj = out || {};
|
|
this.parent.prototype._serialize.call(this, obj);
|
|
obj.m_vertex1 = this.m_vertex1._serialize();
|
|
obj.m_vertex2 = this.m_vertex2._serialize();
|
|
obj.m_hasVertex0 = this.m_hasVertex0;
|
|
if (this.m_hasVertex0) {
|
|
obj.m_vertex0 = this.m_vertex0._serialize()
|
|
}
|
|
obj.m_hasVertex3 = this.m_hasVertex3;
|
|
if (this.m_hasVertex3) {
|
|
obj.m_vertex3 = this.m_vertex3._serialize()
|
|
}
|
|
return obj
|
|
},
|
|
_deserialize: function (data) {
|
|
this.parent.prototype._deserialize.call(this, data);
|
|
this.m_vertex1._deserialize(data.m_vertex1);
|
|
this.m_vertex2._deserialize(data.m_vertex2);
|
|
this.m_hasVertex0 = data.m_hasVertex0;
|
|
if (this.m_hasVertex0) {
|
|
this.m_vertex0._deserialize(data.m_vertex0)
|
|
}
|
|
this.m_hasVertex3 = data.m_hasVertex3;
|
|
if (this.m_hasVertex3) {
|
|
this.m_vertex3._deserialize(data.m_vertex3)
|
|
}
|
|
}
|
|
};
|
|
b2EdgeShape._extend(b2Shape);
|
|
"use strict";
|
|
|
|
function b2ChainShape() {
|
|
this.parent.call(this);
|
|
this.m_type = b2Shape.e_chain;
|
|
this.m_radius = b2_polygonRadius;
|
|
this.m_vertices = null;
|
|
this.m_count = 0;
|
|
this.m_prevVertex = new b2Vec2();
|
|
this.m_nextVertex = new b2Vec2();
|
|
this.m_hasPrevVertex = false;
|
|
this.m_hasNextVertex = false;
|
|
Object.seal(this)
|
|
}
|
|
b2ChainShape.prototype = {
|
|
CreateLoop: function (vertices, count) {
|
|
for (var i = 1; i < count; ++i) {
|
|
var v1 = vertices[i - 1];
|
|
var v2 = vertices[i]
|
|
}
|
|
this.m_count = count + 1;
|
|
this.m_vertices = new Array(this.m_count);
|
|
for (var i = 0; i < count; ++i) {
|
|
this.m_vertices[i] = vertices[i].Clone()
|
|
}
|
|
this.m_vertices[count] = this.m_vertices[0].Clone();
|
|
this.m_prevVertex.Assign(this.m_vertices[this.m_count - 2]);
|
|
this.m_nextVertex.Assign(this.m_vertices[1]);
|
|
this.m_hasPrevVertex = true;
|
|
this.m_hasNextVertex = true
|
|
},
|
|
CreateChain: function (vertices, count) {
|
|
for (var i = 1; i < count; ++i) {
|
|
var v1 = vertices[i - 1];
|
|
var v2 = vertices[i]
|
|
}
|
|
this.m_count = count;
|
|
this.m_vertices = new Array(count);
|
|
for (var i = 0; i < count; ++i) {
|
|
this.m_vertices[i] = vertices[i].Clone()
|
|
}
|
|
this.m_hasPrevVertex = false;
|
|
this.m_hasNextVertex = false;
|
|
this.m_prevVertex.SetZero();
|
|
this.m_nextVertex.SetZero()
|
|
},
|
|
SetPrevVertex: function (prevVertex) {
|
|
this.m_prevVertex.Assign(prevVertex);
|
|
this.m_hasPrevVertex = true
|
|
},
|
|
SetNextVertex: function (nextVertex) {
|
|
this.m_nextVertex.Assign(nextVertex);
|
|
this.m_hasNextVertex = true
|
|
},
|
|
Clone: function () {
|
|
var shape = new b2ChainShape();
|
|
shape.m_count = this.m_count;
|
|
shape.m_vertices = new Array(this.m_count);
|
|
for (var i = 0; i < this.m_count; ++i) {
|
|
shape.m_vertices[i] = this.m_vertices[i].Clone()
|
|
}
|
|
shape.m_prevVertex = this.m_prevVertex.Clone();
|
|
shape.m_nextVertex = this.m_nextVertex.Clone();
|
|
shape.m_hasPrevVertex = this.m_hasPrevVertex;
|
|
shape.m_hasNextVertex = this.m_hasNextVertex;
|
|
return shape
|
|
},
|
|
GetChildCount: function () {
|
|
return this.m_count - 1
|
|
},
|
|
GetChildEdge: function (edge, index) {
|
|
edge.m_type = b2Shape.e_edge;
|
|
edge.m_radius = this.m_radius;
|
|
edge.m_vertex1 = this.m_vertices[index + 0];
|
|
edge.m_vertex2 = this.m_vertices[index + 1];
|
|
if (index > 0) {
|
|
edge.m_vertex0 = this.m_vertices[index - 1];
|
|
edge.m_hasVertex0 = true
|
|
} else {
|
|
edge.m_vertex0 = this.m_prevVertex;
|
|
edge.m_hasVertex0 = this.m_hasPrevVertex
|
|
}
|
|
if (index < this.m_count - 2) {
|
|
edge.m_vertex3 = this.m_vertices[index + 2];
|
|
edge.m_hasVertex3 = true
|
|
} else {
|
|
edge.m_vertex3 = this.m_nextVertex;
|
|
edge.m_hasVertex3 = this.m_hasNextVertex
|
|
}
|
|
},
|
|
TestPoint: function (transform, p) {
|
|
return false
|
|
},
|
|
RayCast: function (output, input, xf, childIndex) {
|
|
var edgeShape = new b2EdgeShape();
|
|
var i1 = childIndex;
|
|
var i2 = childIndex + 1;
|
|
if (i2 == this.m_count) {
|
|
i2 = 0
|
|
}
|
|
edgeShape.m_vertex1 = this.m_vertices[i1].Clone();
|
|
edgeShape.m_vertex2 = this.m_vertices[i2].Clone();
|
|
return edgeShape.RayCast(output, input, xf, 0)
|
|
},
|
|
ComputeAABB: function (aabb, xf, childIndex) {
|
|
var i1 = childIndex;
|
|
var i2 = childIndex + 1;
|
|
if (i2 == this.m_count) {
|
|
i2 = 0
|
|
}
|
|
var v1x = (xf.q.c * this.m_vertices[i1].x - xf.q.s * this.m_vertices[i1].y) + xf.p.x;
|
|
var v1y = (xf.q.s * this.m_vertices[i1].x + xf.q.c * this.m_vertices[i1].y) + xf.p.y;
|
|
var v2x = (xf.q.c * this.m_vertices[i2].x - xf.q.s * this.m_vertices[i2].y) + xf.p.x;
|
|
var v2y = (xf.q.s * this.m_vertices[i2].x + xf.q.c * this.m_vertices[i2].y) + xf.p.y;
|
|
aabb.lowerBound.x = b2Min(v1x, v2x);
|
|
aabb.lowerBound.y = b2Min(v1y, v2y);
|
|
aabb.upperBound.x = b2Max(v1x, v2x);
|
|
aabb.upperBound.y = b2Max(v1y, v2y)
|
|
},
|
|
ComputeMass: function (massData, density) {
|
|
massData.mass = 0;
|
|
massData.center.SetZero();
|
|
massData.I = 0
|
|
},
|
|
_serialize: function (out) {
|
|
var obj = out || {};
|
|
this.parent.prototype._serialize.call(this, obj);
|
|
obj.m_count = this.m_count;
|
|
obj.m_vertices = [];
|
|
for (var i = 0; i < this.m_count; ++i) {
|
|
obj.m_vertices.push(this.m_vertices[i]._serialize())
|
|
}
|
|
obj.m_hasPrevVertex = this.m_hasPrevVertex;
|
|
if (this.m_hasPrevVertex) {
|
|
obj.m_prevVertex = this.m_prevVertex._serialize()
|
|
}
|
|
obj.m_hasNextVertex = this.m_hasNextVertex;
|
|
if (this.m_hasNextVertex) {
|
|
obj.m_nextVertex = this.m_nextVertex._serialize()
|
|
}
|
|
return obj
|
|
},
|
|
_deserialize: function (data) {
|
|
this.parent.prototype._deserialize.call(this, data);
|
|
this.m_count = data.m_count;
|
|
this.m_vertices = [];
|
|
for (var i = 0; i < this.m_count; ++i) {
|
|
this.m_vertices[i] = new b2Vec2();
|
|
this.m_vertices[i]._deserialize(data.m_vertices[i])
|
|
}
|
|
this.m_hasPrevVertex = data.m_hasPrevVertex;
|
|
if (this.m_hasPrevVertex) {
|
|
this.m_prevVertex._deserialize(data.m_prevVertex)
|
|
}
|
|
this.m_hasNextVertex = data.m_hasNextVertex;
|
|
if (this.m_hasNextVertex) {
|
|
this.m_nextVertex._deserialize(data.m_nextVertex)
|
|
}
|
|
}
|
|
};
|
|
b2ChainShape._extend(b2Shape);
|
|
"use strict";
|
|
|
|
function b2PolygonShape() {
|
|
this.parent.call(this);
|
|
this.m_type = b2Shape.e_polygon;
|
|
this.m_radius = b2_polygonRadius;
|
|
this.m_count = 0;
|
|
this.m_centroid = new b2Vec2();
|
|
this.m_vertices = new Array(b2_maxPolygonVertices);
|
|
this.m_normals = new Array(b2_maxPolygonVertices);
|
|
Object.seal(this)
|
|
}
|
|
b2PolygonShape.prototype = {
|
|
Clone: function () {
|
|
var shape = new b2PolygonShape();
|
|
shape.m_count = this.m_count;
|
|
shape.m_centroid = this.m_centroid.Clone();
|
|
for (var i = 0; i < this.m_count; ++i) {
|
|
shape.m_vertices[i] = this.m_vertices[i].Clone();
|
|
shape.m_normals[i] = this.m_normals[i].Clone()
|
|
}
|
|
return shape
|
|
},
|
|
GetChildCount: function () {
|
|
return 1
|
|
},
|
|
Set: function (vertices, count) {
|
|
if (count < 3) {
|
|
this.SetAsBox(1, 1);
|
|
return
|
|
}
|
|
var n = b2Min(count, b2_maxPolygonVertices);
|
|
var ps = new Array(b2_maxPolygonVertices);
|
|
var tempCount = 0;
|
|
for (var i = 0; i < n; ++i) {
|
|
var v = vertices[i];
|
|
var unique = true;
|
|
for (var j = 0; j < tempCount; ++j) {
|
|
if (b2DistanceSquared(v, ps[j]) < 0.5 * b2_linearSlop) {
|
|
unique = false;
|
|
break
|
|
}
|
|
}
|
|
if (unique) {
|
|
ps[tempCount++] = v.Clone()
|
|
}
|
|
}
|
|
n = tempCount;
|
|
if (n < 3) {
|
|
this.SetAsBox(1, 1);
|
|
return
|
|
}
|
|
var i0 = 0;
|
|
var x0 = ps[0].x;
|
|
for (i = 1; i < n; ++i) {
|
|
var x = ps[i].x;
|
|
if (x > x0 || (x == x0 && ps[i].y < ps[i0].y)) {
|
|
i0 = i;
|
|
x0 = x
|
|
}
|
|
}
|
|
var hull = new Array(b2_maxPolygonVertices);
|
|
var m = 0;
|
|
var ih = i0;
|
|
for (;;) {
|
|
hull[m] = ih;
|
|
var ie = 0;
|
|
for (j = 1; j < n; ++j) {
|
|
if (ie == ih) {
|
|
ie = j;
|
|
continue
|
|
}
|
|
var r = b2Vec2.Subtract(ps[ie], ps[hull[m]]);
|
|
var v = b2Vec2.Subtract(ps[j], ps[hull[m]]);
|
|
var c = b2Cross_v2_v2(r, v);
|
|
if (c < 0) {
|
|
ie = j
|
|
}
|
|
if (c == 0 && v.LengthSquared() > r.LengthSquared()) {
|
|
ie = j
|
|
}
|
|
}++m;
|
|
ih = ie;
|
|
if (ie == i0) {
|
|
break
|
|
}
|
|
}
|
|
this.m_count = m;
|
|
for (i = 0; i < m; ++i) {
|
|
this.m_vertices[i] = ps[hull[i]].Clone()
|
|
}
|
|
for (i = 0; i < m; ++i) {
|
|
var i1 = i;
|
|
var i2 = i + 1 < m ? i + 1 : 0;
|
|
var edge = b2Vec2.Subtract(this.m_vertices[i2], this.m_vertices[i1]);
|
|
this.m_normals[i] = b2Cross_v2_f(edge, 1).Clone();
|
|
this.m_normals[i].Normalize()
|
|
}
|
|
this.m_centroid = b2PolygonShape.ComputeCentroid(this.m_vertices, m)
|
|
},
|
|
SetAsBox: function (hx, hy, center, angle) {
|
|
this.m_count = 4;
|
|
this.m_vertices[0] = new b2Vec2(-hx, -hy);
|
|
this.m_vertices[1] = new b2Vec2(hx, -hy);
|
|
this.m_vertices[2] = new b2Vec2(hx, hy);
|
|
this.m_vertices[3] = new b2Vec2(-hx, hy);
|
|
this.m_normals[0] = new b2Vec2(0, -1);
|
|
this.m_normals[1] = new b2Vec2(1, 0);
|
|
this.m_normals[2] = new b2Vec2(0, 1);
|
|
this.m_normals[3] = new b2Vec2(-1, 0);
|
|
if (!center) {
|
|
return
|
|
}
|
|
this.m_centroid.Assign(center);
|
|
var xf = new b2Transform();
|
|
xf.p = center;
|
|
xf.q.Set(angle);
|
|
for (var i = 0; i < this.m_count; ++i) {
|
|
this.m_vertices[i].Assign(b2Mul_t_v2(xf, this.m_vertices[i]));
|
|
this.m_normals[i].Assign(b2Mul_r_v2(xf.q, this.m_normals[i]))
|
|
}
|
|
},
|
|
TestPoint: function (xf, p) {
|
|
var pLocal = b2MulT_r_v2(xf.q, b2Vec2.Subtract(p, xf.p));
|
|
for (var i = 0; i < this.m_count; ++i) {
|
|
var dot = b2Dot_v2_v2(this.m_normals[i], b2Vec2.Subtract(pLocal, this.m_vertices[i]));
|
|
if (dot > 0) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
},
|
|
RayCast: function (output, input, xf, childIndex) {
|
|
var p1 = b2MulT_r_v2(xf.q, b2Vec2.Subtract(input.p1, xf.p));
|
|
var p2 = b2MulT_r_v2(xf.q, b2Vec2.Subtract(input.p2, xf.p));
|
|
var d = b2Vec2.Subtract(p2, p1);
|
|
var lower = 0,
|
|
upper = input.maxFraction;
|
|
var index = -1;
|
|
for (var i = 0; i < this.m_count; ++i) {
|
|
var numerator = b2Dot_v2_v2(this.m_normals[i], b2Vec2.Subtract(this.m_vertices[i], p1));
|
|
var denominator = b2Dot_v2_v2(this.m_normals[i], d);
|
|
if (denominator == 0) {
|
|
if (numerator < 0) {
|
|
return false
|
|
}
|
|
} else {
|
|
if (denominator < 0 && numerator < lower * denominator) {
|
|
lower = numerator / denominator;
|
|
index = i
|
|
} else {
|
|
if (denominator > 0 && numerator < upper * denominator) {
|
|
upper = numerator / denominator
|
|
}
|
|
}
|
|
}
|
|
if (upper < lower) {
|
|
return false
|
|
}
|
|
}
|
|
if (index >= 0) {
|
|
output.fraction = lower;
|
|
output.normal = b2Mul_r_v2(xf.q, this.m_normals[index]);
|
|
return true
|
|
}
|
|
return false
|
|
},
|
|
ComputeAABB: function (aabb, xf, childIndex) {
|
|
var lowerx = (xf.q.c * this.m_vertices[0].x - xf.q.s * this.m_vertices[0].y) + xf.p.x;
|
|
var lowery = (xf.q.s * this.m_vertices[0].x + xf.q.c * this.m_vertices[0].y) + xf.p.y;
|
|
var upperx = lowerx;
|
|
var uppery = lowery;
|
|
for (var i = 1; i < this.m_count; ++i) {
|
|
var vx = (xf.q.c * this.m_vertices[i].x - xf.q.s * this.m_vertices[i].y) + xf.p.x;
|
|
var vy = (xf.q.s * this.m_vertices[i].x + xf.q.c * this.m_vertices[i].y) + xf.p.y;
|
|
lowerx = b2Min(lowerx, vx);
|
|
lowery = b2Min(lowery, vy);
|
|
upperx = b2Max(upperx, vx);
|
|
uppery = b2Max(uppery, vy)
|
|
}
|
|
aabb.lowerBound.x = lowerx - this.m_radius;
|
|
aabb.lowerBound.y = lowery - this.m_radius;
|
|
aabb.upperBound.x = upperx + this.m_radius;
|
|
aabb.upperBound.y = uppery + this.m_radius
|
|
},
|
|
ComputeMass: function (massData, density) {
|
|
var center = new b2Vec2(0, 0);
|
|
var area = 0;
|
|
var I = 0;
|
|
var s = new b2Vec2(0, 0);
|
|
for (var i = 0; i < this.m_count; ++i) {
|
|
s.Add(this.m_vertices[i])
|
|
}
|
|
s.Multiply(1 / this.m_count);
|
|
var k_inv3 = 1 / 3;
|
|
for (var i = 0; i < this.m_count; ++i) {
|
|
var e1 = b2Vec2.Subtract(this.m_vertices[i], s);
|
|
var e2 = i + 1 < this.m_count ? b2Vec2.Subtract(this.m_vertices[i + 1], s) : b2Vec2.Subtract(this.m_vertices[0], s);
|
|
var D = b2Cross_v2_v2(e1, e2);
|
|
var triangleArea = 0.5 * D;
|
|
area += triangleArea;
|
|
center.Add(b2Vec2.Multiply(triangleArea * k_inv3, b2Vec2.Add(e1, e2)));
|
|
var ex1 = e1.x,
|
|
ey1 = e1.y;
|
|
var ex2 = e2.x,
|
|
ey2 = e2.y;
|
|
var intx2 = ex1 * ex1 + ex2 * ex1 + ex2 * ex2;
|
|
var inty2 = ey1 * ey1 + ey2 * ey1 + ey2 * ey2;
|
|
I += (0.25 * k_inv3 * D) * (intx2 + inty2)
|
|
}
|
|
massData.mass = density * area;
|
|
center.Multiply(1 / area);
|
|
massData.center = b2Vec2.Add(center, s);
|
|
massData.I = density * I;
|
|
massData.I += massData.mass * (b2Dot_v2_v2(massData.center, massData.center) - b2Dot_v2_v2(center, center))
|
|
},
|
|
GetVertexCount: function () {
|
|
return this.m_count
|
|
},
|
|
GetVertex: function (index) {
|
|
return this.m_vertices[index]
|
|
},
|
|
Validate: function () {
|
|
for (var i = 0; i < this.m_count; ++i) {
|
|
var i1 = i;
|
|
var i2 = i < this.m_count - 1 ? i1 + 1 : 0;
|
|
var p = this.m_vertices[i1];
|
|
var e = b2Vec2.Subtract(this.m_vertices[i2], p);
|
|
for (var j = 0; j < this.m_count; ++j) {
|
|
if (j == i1 || j == i2) {
|
|
continue
|
|
}
|
|
var v = b2Vec2.Subtract(this.m_vertices[j], p);
|
|
var c = b2Cross_v2_v2(e, v);
|
|
if (c < 0) {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
return true
|
|
},
|
|
_serialize: function (out) {
|
|
var obj = out || {};
|
|
this.parent.prototype._serialize.call(this, obj);
|
|
obj.m_count = this.m_count;
|
|
obj.m_centroid = this.m_centroid._serialize();
|
|
obj.m_vertices = [];
|
|
obj.m_normals = [];
|
|
for (var i = 0; i < this.m_count; ++i) {
|
|
obj.m_vertices.push(this.m_vertices[i]._serialize());
|
|
obj.m_normals.push(this.m_normals[i]._serialize())
|
|
}
|
|
return obj
|
|
},
|
|
_deserialize: function (data) {
|
|
this.parent.prototype._deserialize.call(this, data);
|
|
this.m_count = data.m_count;
|
|
this.m_centroid._deserialize(data.m_centroid);
|
|
this.m_vertices = [];
|
|
this.m_normals = [];
|
|
for (var i = 0; i < this.m_count; ++i) {
|
|
this.m_vertices[i] = new b2Vec2();
|
|
this.m_vertices[i]._deserialize(data.m_vertices[i]);
|
|
this.m_normals[i] = new b2Vec2();
|
|
this.m_normals[i]._deserialize(data.m_normals[i])
|
|
}
|
|
}
|
|
};
|
|
b2PolygonShape.ComputeCentroid = function (vs, count) {
|
|
var c = new b2Vec2();
|
|
var area = 0;
|
|
var pRef = new b2Vec2(0, 0);
|
|
var inv3 = 1 / 3;
|
|
for (var i = 0; i < count; ++i) {
|
|
var p1 = pRef;
|
|
var p2 = vs[i];
|
|
var p3 = i + 1 < count ? vs[i + 1] : vs[0];
|
|
var e1 = b2Vec2.Subtract(p2, p1);
|
|
var e2 = b2Vec2.Subtract(p3, p1);
|
|
var D = b2Cross_v2_v2(e1, e2);
|
|
var triangleArea = 0.5 * D;
|
|
area += triangleArea;
|
|
c.Add(b2Vec2.Multiply(triangleArea, b2Vec2.Multiply(inv3, b2Vec2.Add(b2Vec2.Add(p1, p2), p3))))
|
|
}
|
|
c.Multiply(1 / area);
|
|
return c
|
|
};
|
|
b2PolygonShape._extend(b2Shape);
|
|
"use strict";
|
|
|
|
function b2Pair() {
|
|
this.proxyIdA = 0;
|
|
this.proxyIdB = 0
|
|
}
|
|
|
|
function b2PairLessThan(pair1, pair2) {
|
|
if (pair1.proxyIdA == pair2.proxyIdA) {
|
|
return pair1.proxyIdB - pair2.proxyIdB
|
|
}
|
|
return pair1.proxyIdA - pair2.proxyIdA
|
|
}
|
|
|
|
function b2BroadPhase() {
|
|
this.m_tree = new b2DynamicTree();
|
|
this.m_queryProxyId = 0;
|
|
this.m_proxyCount = 0;
|
|
this.m_pairCount = 0;
|
|
this.m_pairBuffer = [];
|
|
this.m_moveCount = 0;
|
|
this.m_moveBuffer = []
|
|
}
|
|
b2BroadPhase.prototype = {
|
|
CreateProxy: function (aabb, userData) {
|
|
var proxyId = this.m_tree.CreateProxy(aabb, userData);
|
|
++this.m_proxyCount;
|
|
this.BufferMove(proxyId);
|
|
return proxyId
|
|
},
|
|
DestroyProxy: function (proxyId) {
|
|
this.UnBufferMove(proxyId);
|
|
--this.m_proxyCount;
|
|
this.m_tree.DestroyProxy(proxyId)
|
|
},
|
|
MoveProxy: function (proxyId, aabb, displacement) {
|
|
var buffer = this.m_tree.MoveProxy(proxyId, aabb, displacement);
|
|
if (buffer) {
|
|
this.BufferMove(proxyId)
|
|
}
|
|
},
|
|
TouchProxy: function (proxyId) {
|
|
this.BufferMove(proxyId)
|
|
},
|
|
GetFatAABB: function (proxyId) {
|
|
return this.m_tree.GetFatAABB(proxyId)
|
|
},
|
|
GetUserData: function (proxyId) {
|
|
return this.m_tree.GetUserData(proxyId)
|
|
},
|
|
TestOverlap: function (proxyIdA, proxyIdB) {
|
|
var aabbA = this.m_tree.GetFatAABB(proxyIdA);
|
|
var aabbB = this.m_tree.GetFatAABB(proxyIdB);
|
|
return b2TestOverlap(aabbA, aabbB)
|
|
},
|
|
GetProxyCount: function () {
|
|
return this.m_proxyCount
|
|
},
|
|
UpdatePairs: function (callback) {
|
|
this.m_pairCount = 0;
|
|
this.m_pairBuffer.length = 0;
|
|
for (var i = 0; i < this.m_moveCount; ++i) {
|
|
this.m_queryProxyId = this.m_moveBuffer[i];
|
|
if (this.m_queryProxyId == b2BroadPhase.e_nullProxy) {
|
|
continue
|
|
}
|
|
var fatAABB = this.m_tree.GetFatAABB(this.m_queryProxyId);
|
|
this.m_tree.Query(this, fatAABB)
|
|
}
|
|
this.m_moveCount = 0;
|
|
this.m_pairBuffer.sort(b2PairLessThan);
|
|
var i = 0;
|
|
while (i < this.m_pairCount) {
|
|
var primaryPair = this.m_pairBuffer[i];
|
|
var userDataA = this.m_tree.GetUserData(primaryPair.proxyIdA);
|
|
var userDataB = this.m_tree.GetUserData(primaryPair.proxyIdB);
|
|
callback.AddPair(userDataA, userDataB);
|
|
++i;
|
|
while (i < this.m_pairCount) {
|
|
var pair = this.m_pairBuffer[i];
|
|
if (pair.proxyIdA != primaryPair.proxyIdA || pair.proxyIdB != primaryPair.proxyIdB) {
|
|
break
|
|
}++i
|
|
}
|
|
}
|
|
},
|
|
Query: function (callback, aabb) {
|
|
this.m_tree.Query(callback, aabb)
|
|
},
|
|
RayCast: function (callback, input) {
|
|
this.m_tree.RayCast(callback, input)
|
|
},
|
|
GetTreeHeight: function () {
|
|
return this.m_tree.GetHeight()
|
|
},
|
|
GetTreeBalance: function () {
|
|
return this.m_tree.GetMaxBalance()
|
|
},
|
|
GetTreeQuality: function () {
|
|
return this.m_tree.GetAreaRatio()
|
|
},
|
|
ShiftOrigin: function (newOrigin) {
|
|
this.m_tree.ShiftOrigin(newOrigin)
|
|
},
|
|
BufferMove: function (proxyId) {
|
|
this.m_moveBuffer[this.m_moveCount] = proxyId;
|
|
++this.m_moveCount
|
|
},
|
|
UnBufferMove: function (proxyId) {
|
|
for (var i = 0; i < this.m_moveCount; ++i) {
|
|
if (this.m_moveBuffer[i] == proxyId) {
|
|
this.m_moveBuffer[i] = b2BroadPhase.e_nullProxy
|
|
}
|
|
}
|
|
},
|
|
QueryCallback: function (proxyId) {
|
|
if (proxyId == this.m_queryProxyId) {
|
|
return true
|
|
}
|
|
this.m_pairBuffer[this.m_pairCount] = new b2Pair();
|
|
this.m_pairBuffer[this.m_pairCount].proxyIdA = b2Min(proxyId, this.m_queryProxyId);
|
|
this.m_pairBuffer[this.m_pairCount].proxyIdB = b2Max(proxyId, this.m_queryProxyId);
|
|
++this.m_pairCount;
|
|
return true
|
|
}
|
|
};
|
|
b2BroadPhase.e_nullProxy = -1;
|
|
"use strict";
|
|
|
|
function b2DistanceProxy() {
|
|
this.m_vertices = null;
|
|
this.m_count = 0;
|
|
this.m_radius = 0
|
|
}
|
|
b2DistanceProxy.prototype = {
|
|
Assign: function (l) {
|
|
this.m_vertices = l.m_vertices;
|
|
this.m_count = l.m_count;
|
|
this.m_radius = l.m_radius
|
|
},
|
|
Set: function (shape, index) {
|
|
switch (shape.GetType()) {
|
|
case b2Shape.e_circle:
|
|
var circle = shape;
|
|
this.m_vertices = [circle.m_p];
|
|
this.m_count = 1;
|
|
this.m_radius = circle.m_radius;
|
|
break;
|
|
case b2Shape.e_polygon:
|
|
var polygon = shape;
|
|
this.m_vertices = polygon.m_vertices;
|
|
this.m_count = polygon.m_count;
|
|
this.m_radius = polygon.m_radius;
|
|
break;
|
|
case b2Shape.e_chain:
|
|
var chain = shape;
|
|
this.m_vertices = [chain.m_vertices[index]];
|
|
if (index + 1 < chain.m_count) {
|
|
this.m_vertices[1] = chain.m_vertices[index + 1]
|
|
} else {
|
|
this.m_vertices[1] = chain.m_vertices[0]
|
|
}
|
|
this.m_count = 2;
|
|
this.m_radius = chain.m_radius;
|
|
break;
|
|
case b2Shape.e_edge:
|
|
var edge = shape;
|
|
this.m_vertices = [edge.m_vertex1, edge.m_vertex2];
|
|
this.m_count = 2;
|
|
this.m_radius = edge.m_radius;
|
|
break
|
|
}
|
|
},
|
|
GetSupport: function (dx, dy) {
|
|
var bestIndex = 0;
|
|
var bestValue = this.m_vertices[0].x * dx + this.m_vertices[0].y * dy;
|
|
for (var i = 1; i < this.m_count; ++i) {
|
|
var value = this.m_vertices[i].x * dx + this.m_vertices[i].y * dy;
|
|
if (value > bestValue) {
|
|
bestIndex = i;
|
|
bestValue = value
|
|
}
|
|
}
|
|
return bestIndex
|
|
},
|
|
GetSupportVertex: function (dx, dy) {
|
|
return this.m_vertices[this.GetSupport(dx, dy)]
|
|
},
|
|
GetVertexCount: function () {
|
|
return this.m_count
|
|
},
|
|
GetVertex: function (index) {
|
|
return this.m_vertices[index]
|
|
}
|
|
};
|
|
|
|
function b2SimplexCache() {
|
|
this.metric = 0;
|
|
this.count = 0;
|
|
this.indexA = [0, 0, 0];
|
|
this.indexB = [0, 0, 0]
|
|
}
|
|
|
|
function b2DistanceInput() {
|
|
this.proxyA = new b2DistanceProxy();
|
|
this.proxyB = new b2DistanceProxy();
|
|
this.transformA = new b2Transform();
|
|
this.transformB = new b2Transform();
|
|
this.useRadii = false
|
|
}
|
|
|
|
function b2DistanceOutput() {
|
|
this.pointA = new b2Vec2();
|
|
this.pointB = new b2Vec2();
|
|
this.distance = 0;
|
|
this.iterations = 0
|
|
}
|
|
|
|
function b2SimplexVertex() {
|
|
this.wA = new b2Vec2();
|
|
this.wB = new b2Vec2();
|
|
this.w = new b2Vec2();
|
|
this.a = 0;
|
|
this.indexA = 0;
|
|
this.indexB = 0
|
|
}
|
|
b2SimplexVertex.prototype = {
|
|
Assign: function (l) {
|
|
this.wA.x = l.wA.x;
|
|
this.wA.y = l.wA.y;
|
|
this.wB.x = l.wB.x;
|
|
this.wB.y = l.wB.y;
|
|
this.w.x = l.w.x;
|
|
this.w.y = l.w.y;
|
|
this.a = l.a;
|
|
this.indexA = l.indexA;
|
|
this.indexB = l.indexB
|
|
}
|
|
};
|
|
|
|
function b2Simplex() {
|
|
this.m_v = [new b2SimplexVertex(), new b2SimplexVertex(), new b2SimplexVertex()];
|
|
this.m_count = 0
|
|
}
|
|
b2Simplex.prototype = {
|
|
ReadCache: function (cache, proxyA, transformA, proxyB, transformB) {
|
|
this.m_count = cache.count;
|
|
var vertices = this.m_v;
|
|
for (var i = 0; i < this.m_count; ++i) {
|
|
var v = vertices[i];
|
|
v.indexA = cache.indexA[i];
|
|
v.indexB = cache.indexB[i];
|
|
var wALocal = proxyA.GetVertex(v.indexA);
|
|
var wBLocal = proxyB.GetVertex(v.indexB);
|
|
v.wA.x = (transformA.q.c * wALocal.x - transformA.q.s * wALocal.y) + transformA.p.x;
|
|
v.wA.y = (transformA.q.s * wALocal.x + transformA.q.c * wALocal.y) + transformA.p.y;
|
|
v.wB.x = (transformB.q.c * wBLocal.x - transformB.q.s * wBLocal.y) + transformB.p.x;
|
|
v.wB.y = (transformB.q.s * wBLocal.x + transformB.q.c * wBLocal.y) + transformB.p.y;
|
|
v.w.x = v.wB.x - v.wA.x;
|
|
v.w.y = v.wB.y - v.wA.y;
|
|
v.a = 0
|
|
}
|
|
if (this.m_count > 1) {
|
|
var metric1 = cache.metric;
|
|
var metric2 = this.GetMetric();
|
|
if (metric2 < 0.5 * metric1 || 2 * metric1 < metric2 || metric2 < b2_epsilon) {
|
|
this.m_count = 0
|
|
}
|
|
}
|
|
if (this.m_count == 0) {
|
|
var v = vertices[0];
|
|
v.indexA = 0;
|
|
v.indexB = 0;
|
|
var wALocal = proxyA.GetVertex(0);
|
|
var wBLocal = proxyB.GetVertex(0);
|
|
v.wA.x = (transformA.q.c * wALocal.x - transformA.q.s * wALocal.y) + transformA.p.x;
|
|
v.wA.y = (transformA.q.s * wALocal.x + transformA.q.c * wALocal.y) + transformA.p.y;
|
|
v.wB.x = (transformB.q.c * wBLocal.x - transformB.q.s * wBLocal.y) + transformB.p.x;
|
|
v.wB.y = (transformB.q.s * wBLocal.x + transformB.q.c * wBLocal.y) + transformB.p.y;
|
|
v.w.x = v.wB.x - v.wA.x;
|
|
v.w.y = v.wB.y - v.wA.y;
|
|
v.a = 1;
|
|
this.m_count = 1
|
|
}
|
|
},
|
|
WriteCache: function (cache) {
|
|
cache.metric = this.GetMetric();
|
|
cache.count = this.m_count;
|
|
var vertices = this.m_v;
|
|
for (var i = 0; i < this.m_count; ++i) {
|
|
cache.indexA[i] = vertices[i].indexA;
|
|
cache.indexB[i] = vertices[i].indexB
|
|
}
|
|
},
|
|
GetSearchDirection: function (p) {
|
|
switch (this.m_count) {
|
|
case 1:
|
|
p.x = -this.m_v[0].w.x;
|
|
p.y = -this.m_v[0].w.y;
|
|
break;
|
|
case 2:
|
|
var e12x = this.m_v[1].w.x - this.m_v[0].w.x;
|
|
var e12y = this.m_v[1].w.y - this.m_v[0].w.y;
|
|
var sgn = e12x * -this.m_v[0].w.y - e12y * -this.m_v[0].w.x;
|
|
if (sgn > 0) {
|
|
p.x = -1 * e12y;
|
|
p.y = 1 * e12x
|
|
} else {
|
|
p.x = 1 * e12y;
|
|
p.y = -1 * e12x
|
|
}
|
|
break
|
|
}
|
|
},
|
|
GetClosestPoint: function (p) {
|
|
switch (this.m_count) {
|
|
case 1:
|
|
p.x = this.m_v[0].w.x;
|
|
p.y = this.m_v[0].w.y;
|
|
break;
|
|
case 2:
|
|
p.x = (this.m_v[0].a * this.m_v[0].w.x) + (this.m_v[1].a * this.m_v[1].w.x);
|
|
p.y = (this.m_v[0].a * this.m_v[0].w.y) + (this.m_v[1].a * this.m_v[1].w.y);
|
|
break;
|
|
case 3:
|
|
p.x = p.y = 0;
|
|
break
|
|
}
|
|
},
|
|
GetWitnessPoints: function (pA, pB) {
|
|
switch (this.m_count) {
|
|
case 1:
|
|
pA.x = this.m_v[0].wA.x;
|
|
pA.y = this.m_v[0].wA.y;
|
|
pB.x = this.m_v[0].wB.x;
|
|
pB.y = this.m_v[0].wB.y;
|
|
break;
|
|
case 2:
|
|
pA.x = (this.m_v[0].a * this.m_v[0].wA.x) + (this.m_v[1].a * this.m_v[1].wA.x);
|
|
pA.y = (this.m_v[0].a * this.m_v[0].wA.y) + (this.m_v[1].a * this.m_v[1].wA.y);
|
|
pB.x = (this.m_v[0].a * this.m_v[0].wB.x) + (this.m_v[1].a * this.m_v[1].wB.x);
|
|
pB.y = (this.m_v[0].a * this.m_v[0].wB.y) + (this.m_v[1].a * this.m_v[1].wB.y);
|
|
break;
|
|
case 3:
|
|
pA.x = (this.m_v[0].a, this.m_v[0].wA.x) + (this.m_v[1].a, this.m_v[1].wA.x) + (this.m_v[2].a, this.m_v[2].wA.x);
|
|
pA.y = (this.m_v[0].a, this.m_v[0].wA.y) + (this.m_v[1].a, this.m_v[1].wA.y) + (this.m_v[2].a, this.m_v[2].wA.y);
|
|
pB.x = pA.x;
|
|
pB.y = pA.y;
|
|
break
|
|
}
|
|
},
|
|
GetMetric: function () {
|
|
switch (this.m_count) {
|
|
case 1:
|
|
return 0;
|
|
case 2:
|
|
return b2Distance(this.m_v[0].w, this.m_v[1].w);
|
|
case 3:
|
|
return (this.m_v[1].w.x - this.m_v[0].w.x) * (this.m_v[2].w.y - this.m_v[0].w.y) - (this.m_v[1].w.y - this.m_v[0].w.y) * (this.m_v[2].w.x - this.m_v[0].w.x)
|
|
}
|
|
},
|
|
Solve2: function () {
|
|
var w1 = this.m_v[0].w;
|
|
var w2 = this.m_v[1].w;
|
|
var e12x = w2.x - w1.x;
|
|
var e12y = w2.y - w1.y;
|
|
var d12_2 = -(w1.x * e12x + w1.y * e12y);
|
|
if (d12_2 <= 0) {
|
|
this.m_v[0].a = 1;
|
|
this.m_count = 1;
|
|
return
|
|
}
|
|
var d12_1 = w2.x * e12x + w2.y * e12y;
|
|
if (d12_1 <= 0) {
|
|
this.m_v[1].a = 1;
|
|
this.m_count = 1;
|
|
this.m_v[0].Assign(this.m_v[1]);
|
|
return
|
|
}
|
|
var inv_d12 = 1 / (d12_1 + d12_2);
|
|
this.m_v[0].a = d12_1 * inv_d12;
|
|
this.m_v[1].a = d12_2 * inv_d12;
|
|
this.m_count = 2
|
|
},
|
|
Solve3: function () {
|
|
var w1 = this.m_v[0].w;
|
|
var w2 = this.m_v[1].w;
|
|
var w3 = this.m_v[2].w;
|
|
var e12x = w2.x - w1.x;
|
|
var e12y = w2.y - w1.y;
|
|
var w1e12 = w1.x * e12x + w1.y * e12y;
|
|
var w2e12 = w2.x * e12x + w2.y * e12y;
|
|
var d12_1 = w2e12;
|
|
var d12_2 = -w1e12;
|
|
var e13x = w3.x - w1.x;
|
|
var e13y = w3.y - w1.y;
|
|
var w1e13 = w1.x * e13x + w1.y * e13y;
|
|
var w3e13 = w3.x * e13x + w3.y * e13y;
|
|
var d13_1 = w3e13;
|
|
var d13_2 = -w1e13;
|
|
var e23x = w3.x - w2.x;
|
|
var e23y = w3.y - w2.y;
|
|
var w2e23 = w2.x * e23x + w2.y * e23y;
|
|
var w3e23 = w3.x * e23x + w3.y * e23y;
|
|
var d23_1 = w3e23;
|
|
var d23_2 = -w2e23;
|
|
var n123 = e12x * e13y - e12y * e13x;
|
|
var d123_1 = n123 * (w2.x * w3.y - w2.y * w3.x);
|
|
var d123_2 = n123 * (w3.x * w1.y - w3.y * w1.x);
|
|
var d123_3 = n123 * (w1.x * w2.y - w1.y * w2.x);
|
|
if (d12_2 <= 0 && d13_2 <= 0) {
|
|
this.m_v[0].a = 1;
|
|
this.m_count = 1;
|
|
return
|
|
}
|
|
if (d12_1 > 0 && d12_2 > 0 && d123_3 <= 0) {
|
|
var inv_d12 = 1 / (d12_1 + d12_2);
|
|
this.m_v[0].a = d12_1 * inv_d12;
|
|
this.m_v[1].a = d12_2 * inv_d12;
|
|
this.m_count = 2;
|
|
return
|
|
}
|
|
if (d13_1 > 0 && d13_2 > 0 && d123_2 <= 0) {
|
|
var inv_d13 = 1 / (d13_1 + d13_2);
|
|
this.m_v[0].a = d13_1 * inv_d13;
|
|
this.m_v[2].a = d13_2 * inv_d13;
|
|
this.m_count = 2;
|
|
this.m_v[1].Assign(this.m_v[2]);
|
|
return
|
|
}
|
|
if (d12_1 <= 0 && d23_2 <= 0) {
|
|
this.m_v[1].a = 1;
|
|
this.m_count = 1;
|
|
this.m_v[0].Assign(this.m_v[1]);
|
|
return
|
|
}
|
|
if (d13_1 <= 0 && d23_1 <= 0) {
|
|
this.m_v[2].a = 1;
|
|
this.m_count = 1;
|
|
this.m_v[0].Assign(this.m_v[2]);
|
|
return
|
|
}
|
|
if (d23_1 > 0 && d23_2 > 0 && d123_1 <= 0) {
|
|
var inv_d23 = 1 / (d23_1 + d23_2);
|
|
this.m_v[1].a = d23_1 * inv_d23;
|
|
this.m_v[2].a = d23_2 * inv_d23;
|
|
this.m_count = 2;
|
|
this.m_v[0].Assign(this.m_v[2]);
|
|
return
|
|
}
|
|
var inv_d123 = 1 / (d123_1 + d123_2 + d123_3);
|
|
this.m_v[0].a = d123_1 * inv_d123;
|
|
this.m_v[1].a = d123_2 * inv_d123;
|
|
this.m_v[2].a = d123_3 * inv_d123;
|
|
this.m_count = 3
|
|
}
|
|
};
|
|
var _b2Distance_simplex = new b2Simplex();
|
|
var _b2Distance_normal = new b2Vec2();
|
|
var _b2Distance_p = new b2Vec2();
|
|
|
|
function b2DistanceFunc(output, cache, input) {
|
|
++b2DistanceFunc.b2_gjkCalls;
|
|
var proxyA = input.proxyA;
|
|
var proxyB = input.proxyB;
|
|
var transformA = input.transformA;
|
|
var transformB = input.transformB;
|
|
_b2Distance_simplex.ReadCache(cache, proxyA, transformA, proxyB, transformB);
|
|
var vertices = _b2Distance_simplex.m_v;
|
|
var k_maxIters = 20;
|
|
var saveA = [0, 0, 0],
|
|
saveB = [0, 0, 0];
|
|
var saveCount = 0;
|
|
var distanceSqr1 = b2_maxFloat;
|
|
var distanceSqr2 = distanceSqr1;
|
|
var iter = 0;
|
|
while (iter < k_maxIters) {
|
|
saveCount = _b2Distance_simplex.m_count;
|
|
for (var i = 0; i < saveCount; ++i) {
|
|
saveA[i] = vertices[i].indexA;
|
|
saveB[i] = vertices[i].indexB
|
|
}
|
|
switch (_b2Distance_simplex.m_count) {
|
|
case 1:
|
|
break;
|
|
case 2:
|
|
_b2Distance_simplex.Solve2();
|
|
break;
|
|
case 3:
|
|
_b2Distance_simplex.Solve3();
|
|
break
|
|
}
|
|
if (_b2Distance_simplex.m_count == 3) {
|
|
break
|
|
}
|
|
_b2Distance_simplex.GetClosestPoint(_b2Distance_p);
|
|
distanceSqr2 = _b2Distance_p.LengthSquared();
|
|
if (distanceSqr2 >= distanceSqr1) {}
|
|
distanceSqr1 = distanceSqr2;
|
|
_b2Distance_simplex.GetSearchDirection(_b2Distance_p);
|
|
if (_b2Distance_p.LengthSquared() < b2_epsilon * b2_epsilon) {
|
|
break
|
|
}
|
|
var vertex = vertices[_b2Distance_simplex.m_count];
|
|
vertex.indexA = proxyA.GetSupport(transformA.q.c * -_b2Distance_p.x + transformA.q.s * -_b2Distance_p.y, -transformA.q.s * -_b2Distance_p.x + transformA.q.c * -_b2Distance_p.y);
|
|
var pva = proxyA.GetVertex(vertex.indexA);
|
|
vertex.wA.x = (transformA.q.c * pva.x - transformA.q.s * pva.y) + transformA.p.x;
|
|
vertex.wA.y = (transformA.q.s * pva.x + transformA.q.c * pva.y) + transformA.p.y;
|
|
vertex.indexB = proxyB.GetSupport(transformB.q.c * _b2Distance_p.x + transformB.q.s * _b2Distance_p.y, -transformB.q.s * _b2Distance_p.x + transformB.q.c * _b2Distance_p.y);
|
|
var pvb = proxyB.GetVertex(vertex.indexB);
|
|
vertex.wB.x = (transformB.q.c * pvb.x - transformB.q.s * pvb.y) + transformB.p.x;
|
|
vertex.wB.y = (transformB.q.s * pvb.x + transformB.q.c * pvb.y) + transformB.p.y;
|
|
vertex.w.x = vertex.wB.x - vertex.wA.x;
|
|
vertex.w.y = vertex.wB.y - vertex.wA.y;
|
|
++iter;
|
|
++b2DistanceFunc.b2_gjkIters;
|
|
var duplicate = false;
|
|
for (var i = 0; i < saveCount; ++i) {
|
|
if (vertex.indexA == saveA[i] && vertex.indexB == saveB[i]) {
|
|
duplicate = true;
|
|
break
|
|
}
|
|
}
|
|
if (duplicate) {
|
|
break
|
|
}++_b2Distance_simplex.m_count
|
|
}
|
|
b2DistanceFunc.b2_gjkMaxIters = b2Max(b2DistanceFunc.b2_gjkMaxIters, iter);
|
|
_b2Distance_simplex.GetWitnessPoints(output.pointA, output.pointB);
|
|
output.distance = b2Distance(output.pointA, output.pointB);
|
|
output.iterations = iter;
|
|
_b2Distance_simplex.WriteCache(cache);
|
|
if (input.useRadii) {
|
|
var rA = proxyA.m_radius;
|
|
var rB = proxyB.m_radius;
|
|
if (output.distance > rA + rB && output.distance > b2_epsilon) {
|
|
output.distance -= rA + rB;
|
|
_b2Distance_normal.x = output.pointB.x - output.pointA.x;
|
|
_b2Distance_normal.y = output.pointB.y - output.pointA.y;
|
|
_b2Distance_normal.Normalize();
|
|
output.pointA.x += (rA * _b2Distance_normal.x);
|
|
output.pointA.y += (rA * _b2Distance_normal.y);
|
|
output.pointB.x -= (rB * _b2Distance_normal.x);
|
|
output.pointB.y -= (rB * _b2Distance_normal.y)
|
|
} else {
|
|
var px = (0.5 * (output.pointA.x + output.pointB.x));
|
|
var py = (0.5 * (output.pointA.y + output.pointB.y));
|
|
output.pointA.x = px;
|
|
output.pointA.y = py;
|
|
output.pointB.x = px;
|
|
output.pointB.y = py;
|
|
output.distance = 0
|
|
}
|
|
}
|
|
}
|
|
b2DistanceFunc.b2_gjkCalls = 0;
|
|
b2DistanceFunc.b2_gjkIters = 0;
|
|
b2DistanceFunc.b2_gjkMaxIters = 0;
|
|
"use strict";
|
|
var b2_nullFeature = 255;
|
|
|
|
function b2ContactID() {}
|
|
b2ContactID.prototype = {
|
|
indexA: 0,
|
|
indexB: 0,
|
|
typeA: 0,
|
|
typeB: 0,
|
|
Reset: function () {
|
|
this.indexA = this.indexB = this.typeA = this.typeB = 0
|
|
},
|
|
Get: function () {
|
|
return this.indexA | (this.indexB << 8) | (this.typeA << 16) | (this.typeB << 24)
|
|
},
|
|
Assign: function (k) {
|
|
this.indexA = k.indexA;
|
|
this.indexB = k.indexB;
|
|
this.typeA = k.typeA;
|
|
this.typeB = k.typeB
|
|
}
|
|
};
|
|
b2ContactID.e_vertex = 0;
|
|
b2ContactID.e_face = 1;
|
|
|
|
function b2ManifoldPoint() {
|
|
this.localPoint = new b2Vec2();
|
|
this.normalImpulse = 0;
|
|
this.tangentImpulse = 0;
|
|
this.id = new b2ContactID()
|
|
}
|
|
b2ManifoldPoint.prototype = {
|
|
Clone: function () {
|
|
var point = new b2ManifoldPoint();
|
|
point.localPoint.x = this.localPoint.x;
|
|
point.localPoint.y = this.localPoint.y;
|
|
point.normalImpulse = this.normalImpulse;
|
|
point.tangentImpulse = this.tangentImpulse;
|
|
point.id.Assign(this.id);
|
|
return point
|
|
}
|
|
};
|
|
|
|
function b2Manifold() {
|
|
this.points = new Array(b2_maxManifoldPoints);
|
|
this.localNormal = new b2Vec2();
|
|
this.localPoint = new b2Vec2();
|
|
this.type = 0;
|
|
this.pointCount = 0
|
|
}
|
|
b2Manifold.prototype = {
|
|
Clone: function () {
|
|
var manifold = new b2Manifold();
|
|
manifold.pointCount = this.pointCount;
|
|
manifold.type = this.type;
|
|
manifold.localPoint.x = this.localPoint.x;
|
|
manifold.localPoint.y = this.localPoint.y;
|
|
manifold.localNormal.x = this.localNormal.x;
|
|
manifold.localNormal.y = this.localNormal.y;
|
|
for (var i = 0; i < this.pointCount; ++i) {
|
|
manifold.points[i] = this.points[i].Clone()
|
|
}
|
|
return manifold
|
|
},
|
|
Assign: function (manifold) {
|
|
this.pointCount = manifold.pointCount;
|
|
this.type = manifold.type;
|
|
this.localPoint.x = manifold.localPoint.x;
|
|
this.localPoint.y = manifold.localPoint.y;
|
|
this.localNormal.x = manifold.localNormal.x;
|
|
this.localNormal.y = manifold.localNormal.y;
|
|
for (var i = 0; i < this.pointCount; ++i) {
|
|
this.points[i] = manifold.points[i].Clone()
|
|
}
|
|
}
|
|
};
|
|
b2Manifold.e_circles = 0;
|
|
b2Manifold.e_faceA = 1;
|
|
b2Manifold.e_faceB = 2;
|
|
b2Manifold.b2_nullState = 0;
|
|
b2Manifold.b2_addState = 1;
|
|
b2Manifold.b2_persistState = 2;
|
|
b2Manifold.b2_removeState = 3;
|
|
|
|
function b2WorldManifold() {
|
|
this.normal = new b2Vec2();
|
|
this.points = new Array(b2_maxManifoldPoints);
|
|
this.separations = new Array(b2_maxManifoldPoints)
|
|
}
|
|
b2WorldManifold.prototype = {
|
|
Initialize: function (manifold, xfA, radiusA, xfB, radiusB) {
|
|
if (manifold.pointCount == 0) {
|
|
return
|
|
}
|
|
switch (manifold.type) {
|
|
case b2Manifold.e_circles:
|
|
this.normal.x = 1;
|
|
this.normal.y = 0;
|
|
var pointAx = (xfA.q.c * manifold.localPoint.x - xfA.q.s * manifold.localPoint.y) + xfA.p.x;
|
|
var pointAy = (xfA.q.s * manifold.localPoint.x + xfA.q.c * manifold.localPoint.y) + xfA.p.y;
|
|
var pointBx = (xfB.q.c * manifold.points[0].localPoint.x - xfB.q.s * manifold.points[0].localPoint.y) + xfB.p.x;
|
|
var pointBy = (xfB.q.s * manifold.points[0].localPoint.x + xfB.q.c * manifold.points[0].localPoint.y) + xfB.p.y;
|
|
var cx = pointAx - pointBx;
|
|
var cy = pointAy - pointBy;
|
|
if ((cx * cx + cy * cy) > b2_epsilon * b2_epsilon) {
|
|
this.normal.x = pointBx - pointAx;
|
|
this.normal.y = pointBy - pointAy;
|
|
this.normal.Normalize()
|
|
}
|
|
var cAx = pointAx + (radiusA * this.normal.x);
|
|
var cAy = pointAy + (radiusA * this.normal.y);
|
|
var cBx = pointBx - (radiusB * this.normal.x);
|
|
var cBy = pointBy - (radiusB * this.normal.y);
|
|
this.points[0] = new b2Vec2(0.5 * (cAx + cBx), 0.5 * (cAy + cBy));
|
|
this.separations[0] = (cBx - cAx) * this.normal.x + (cBy - cAy) * this.normal.y;
|
|
break;
|
|
case b2Manifold.e_faceA:
|
|
this.normal.x = xfA.q.c * manifold.localNormal.x - xfA.q.s * manifold.localNormal.y;
|
|
this.normal.y = xfA.q.s * manifold.localNormal.x + xfA.q.c * manifold.localNormal.y;
|
|
var planePointx = (xfA.q.c * manifold.localPoint.x - xfA.q.s * manifold.localPoint.y) + xfA.p.x;
|
|
var planePointy = (xfA.q.s * manifold.localPoint.x + xfA.q.c * manifold.localPoint.y) + xfA.p.y;
|
|
for (var i = 0; i < manifold.pointCount; ++i) {
|
|
var clipPointx = (xfB.q.c * manifold.points[i].localPoint.x - xfB.q.s * manifold.points[i].localPoint.y) + xfB.p.x;
|
|
var clipPointy = (xfB.q.s * manifold.points[i].localPoint.x + xfB.q.c * manifold.points[i].localPoint.y) + xfB.p.y;
|
|
var d = (clipPointx - planePointx) * this.normal.x + (clipPointy - planePointy) * this.normal.y;
|
|
var cAx = clipPointx + ((radiusA - d) * this.normal.x);
|
|
var cAy = clipPointy + ((radiusA - d) * this.normal.y);
|
|
var cBx = (clipPointx - (radiusB * this.normal.x));
|
|
var cBy = (clipPointy - (radiusB * this.normal.y));
|
|
this.points[i] = new b2Vec2(0.5 * (cAx + cBx), 0.5 * (cAy + cBy));
|
|
this.separations[i] = (cBx - cAx) * this.normal.x + (cBy - cAy) * this.normal.y
|
|
}
|
|
break;
|
|
case b2Manifold.e_faceB:
|
|
this.normal.x = xfB.q.c * manifold.localNormal.x - xfB.q.s * manifold.localNormal.y;
|
|
this.normal.y = xfB.q.s * manifold.localNormal.x + xfB.q.c * manifold.localNormal.y;
|
|
var planePointx = (xfB.q.c * manifold.localPoint.x - xfB.q.s * manifold.localPoint.y) + xfB.p.x;
|
|
var planePointy = (xfB.q.s * manifold.localPoint.x + xfB.q.c * manifold.localPoint.y) + xfB.p.y;
|
|
for (var i = 0; i < manifold.pointCount; ++i) {
|
|
var clipPointx = (xfA.q.c * manifold.points[i].localPoint.x - xfA.q.s * manifold.points[i].localPoint.y) + xfA.p.x;
|
|
var clipPointy = (xfA.q.s * manifold.points[i].localPoint.x + xfA.q.c * manifold.points[i].localPoint.y) + xfA.p.y;
|
|
var d = (clipPointx - planePointx) * this.normal.x + (clipPointy - planePointy) * this.normal.y;
|
|
var cBx = clipPointx + ((radiusB - d) * this.normal.x);
|
|
var cBy = clipPointy + ((radiusB - d) * this.normal.y);
|
|
var cAx = (clipPointx - (radiusA * this.normal.x));
|
|
var cAy = (clipPointy - (radiusA * this.normal.y));
|
|
this.points[i] = new b2Vec2(0.5 * (cAx + cBx), 0.5 * (cAy + cBy));
|
|
this.separations[i] = (cAx - cBx) * this.normal.x + (cAy - cBy) * this.normal.y
|
|
}
|
|
this.normal.x = -this.normal.x;
|
|
this.normal.y = -this.normal.y;
|
|
break
|
|
}
|
|
}
|
|
};
|
|
|
|
function b2GetPointStates(state1, state2, manifold1, manifold2) {
|
|
for (var i = 0; i < b2_maxManifoldPoints; ++i) {
|
|
state1[i] = b2Manifold.b2_nullState;
|
|
state2[i] = b2Manifold.b2_nullState
|
|
}
|
|
for (var i = 0; i < manifold1.pointCount; ++i) {
|
|
var id = manifold1.points[i].id;
|
|
state1[i] = b2Manifold.b2_removeState;
|
|
for (var j = 0; j < manifold2.pointCount; ++j) {
|
|
if (manifold2.points[j].id.Get() == id.Get()) {
|
|
state1[i] = b2Manifold.b2_persistState;
|
|
break
|
|
}
|
|
}
|
|
}
|
|
for (var i = 0; i < manifold2.pointCount; ++i) {
|
|
var id = manifold2.points[i].id;
|
|
state2[i] = b2Manifold.b2_addState;
|
|
for (var j = 0; j < manifold1.pointCount; ++j) {
|
|
if (manifold1.points[j].id.Get() == id.Get()) {
|
|
state2[i] = b2Manifold.b2_persistState;
|
|
break
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
function b2ClipVertex() {
|
|
this.v = new b2Vec2();
|
|
this.id = new b2ContactID()
|
|
}
|
|
|
|
function b2RayCastInput() {
|
|
this.p1 = new b2Vec2(), this.p2 = new b2Vec2();
|
|
this.maxFraction = 0
|
|
}
|
|
|
|
function b2RayCastOutput() {
|
|
this.normal = new b2Vec2();
|
|
this.fraction = 0
|
|
}
|
|
|
|
function b2AABB() {
|
|
this.lowerBound = new b2Vec2();
|
|
this.upperBound = new b2Vec2()
|
|
}
|
|
b2AABB.prototype = {
|
|
Assign: function (other) {
|
|
this.lowerBound.x = other.lowerBound.x;
|
|
this.lowerBound.y = other.lowerBound.y;
|
|
this.upperBound.x = other.upperBound.x;
|
|
this.upperBound.y = other.upperBound.y
|
|
},
|
|
Clone: function () {
|
|
var clone = new b2AABB();
|
|
clone.lowerBound.x = this.lowerBound.x;
|
|
clone.lowerBound.y = this.lowerBound.y;
|
|
clone.lowerBound.x = this.lowerBound.x;
|
|
clone.lowerBound.y = this.lowerBound.y;
|
|
return clone
|
|
},
|
|
IsValid: function () {
|
|
return (this.upperBound.x - this.lowerBound.x) >= 0 && (this.upperBound.y - this.lowerBound.y) >= 0 && this.lowerBound.IsValid() && this.upperBound.IsValid()
|
|
},
|
|
GetCenter: function () {
|
|
return new b2Vec2(0.5 * (this.lowerBound.x + this.upperBound.x), 0.5 * (this.lowerBound.y + this.upperBound.y))
|
|
},
|
|
GetExtents: function () {
|
|
return new b2Vec2(0.5 * (this.upperBound.x - this.lowerBound.x), 0.5 * (this.upperBound.y - this.lowerBound.y))
|
|
},
|
|
GetPerimeter: function () {
|
|
return 2 * ((this.upperBound.x - this.lowerBound.x) + (this.upperBound.y - this.lowerBound.y))
|
|
},
|
|
Combine: function (aabb1, aabb2) {
|
|
if (aabb2) {
|
|
this.lowerBound.x = b2Min(aabb1.lowerBound.x, aabb2.lowerBound.x);
|
|
this.lowerBound.y = b2Min(aabb1.lowerBound.y, aabb2.lowerBound.y);
|
|
this.upperBound.x = b2Max(aabb1.upperBound.x, aabb2.upperBound.x);
|
|
this.upperBound.y = b2Max(aabb1.upperBound.y, aabb2.upperBound.y)
|
|
} else {
|
|
this.lowerBound.x = b2Min(this.lowerBound.x, aabb1.lowerBound.x);
|
|
this.lowerBound.y = b2Min(this.lowerBound.y, aabb1.lowerBound.y);
|
|
this.upperBound.x = b2Max(this.upperBound.x, aabb1.upperBound.x);
|
|
this.upperBound.y = b2Max(this.upperBound.y, aabb1.upperBound.y)
|
|
}
|
|
},
|
|
Contains: function (aabb) {
|
|
return this.lowerBound.x <= aabb.lowerBound.x && this.lowerBound.y <= aabb.lowerBound.y && aabb.upperBound.x <= this.upperBound.x && aabb.upperBound.y <= this.upperBound.y
|
|
},
|
|
RayCast: function (output, input) {
|
|
var tmin = -b2_maxFloat;
|
|
var tmax = b2_maxFloat;
|
|
var p = input.p1;
|
|
var d = b2Vec2.Subtract(input.p2, input.p1);
|
|
var absD = b2Abs_v2(d);
|
|
var normal = new b2Vec2();
|
|
for (var i = 0; i < 2; ++i) {
|
|
if (absD.get_i(i) < b2_epsilon) {
|
|
if (p.get_i(i) < this.lowerBound.get_i(i) || this.upperBound.get_i(i) < p.get_i(i)) {
|
|
return false
|
|
}
|
|
} else {
|
|
var inv_d = 1 / d.get_i(i);
|
|
var t1 = (this.lowerBound.get_i(i) - p.get_i(i)) * inv_d;
|
|
var t2 = (this.upperBound.get_i(i) - p.get_i(i)) * inv_d;
|
|
var s = -1;
|
|
if (t1 > t2) {
|
|
var temp = t2;
|
|
t2 = t1;
|
|
t1 = temp;
|
|
s = 1
|
|
}
|
|
if (t1 > tmin) {
|
|
normal.x = normal.y = 0;
|
|
normal.set_i(i, s);
|
|
tmin = t1
|
|
}
|
|
tmax = b2Min(tmax, t2);
|
|
if (tmin > tmax) {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
if (tmin < 0 || input.maxFraction < tmin) {
|
|
return false
|
|
}
|
|
output.fraction = tmin;
|
|
output.normal.x = normal.x;
|
|
output.normal.y = normal.y;
|
|
return true
|
|
}
|
|
};
|
|
|
|
function b2CollideCircles(manifold, circleA, xfA, circleB, xfB) {
|
|
manifold.pointCount = 0;
|
|
var pA = b2Mul_t_v2(xfA, circleA.m_p);
|
|
var pB = b2Mul_t_v2(xfB, circleB.m_p);
|
|
var dx = pB.x - pA.x;
|
|
var dy = pB.y - pA.y;
|
|
var distSqr = dx * dx + dy * dy;
|
|
var rA = circleA.m_radius,
|
|
rB = circleB.m_radius;
|
|
var radius = rA + rB;
|
|
if (distSqr > radius * radius) {
|
|
return
|
|
}
|
|
manifold.type = b2Manifold.e_circles;
|
|
manifold.localPoint.x = circleA.m_p.x;
|
|
manifold.localPoint.y = circleA.m_p.y;
|
|
manifold.localNormal.x = manifold.localNormal.y = 0;
|
|
manifold.pointCount = 1;
|
|
manifold.points[0] = new b2ManifoldPoint();
|
|
manifold.points[0].localPoint.x = circleB.m_p.x;
|
|
manifold.points[0].localPoint.y = circleB.m_p.y;
|
|
manifold.points[0].id.Reset()
|
|
}
|
|
|
|
function b2CollidePolygonAndCircle(manifold, polygonA, xfA, circleB, xfB) {
|
|
manifold.pointCount = 0;
|
|
var c = b2Mul_t_v2(xfB, circleB.m_p);
|
|
var cLocal = b2MulT_t_v2(xfA, c);
|
|
var normalIndex = 0;
|
|
var separation = -b2_maxFloat;
|
|
var radius = polygonA.m_radius + circleB.m_radius;
|
|
var vertexCount = polygonA.m_count;
|
|
var vertices = polygonA.m_vertices;
|
|
var normals = polygonA.m_normals;
|
|
for (var i = 0; i < vertexCount; ++i) {
|
|
var s = normals[i].x * (cLocal.x - vertices[i].x) + normals[i].y * (cLocal.y - vertices[i].y);
|
|
if (s > radius) {
|
|
return
|
|
}
|
|
if (s > separation) {
|
|
separation = s;
|
|
normalIndex = i
|
|
}
|
|
}
|
|
var vertIndex1 = normalIndex;
|
|
var vertIndex2 = vertIndex1 + 1 < vertexCount ? vertIndex1 + 1 : 0;
|
|
var v1 = vertices[vertIndex1];
|
|
var v2 = vertices[vertIndex2];
|
|
if (separation < b2_epsilon) {
|
|
manifold.pointCount = 1;
|
|
manifold.type = b2Manifold.e_faceA;
|
|
manifold.localNormal.x = normals[normalIndex].x;
|
|
manifold.localNormal.y = normals[normalIndex].y;
|
|
manifold.localPoint.x = 0.5 * (v1.x + v2.x);
|
|
manifold.localPoint.y = 0.5 * (v1.y + v2.y);
|
|
manifold.points[0] = new b2ManifoldPoint();
|
|
manifold.points[0].localPoint.x = circleB.m_p.x;
|
|
manifold.points[0].localPoint.y = circleB.m_p.y;
|
|
manifold.points[0].id.Reset();
|
|
return
|
|
}
|
|
var u1 = (cLocal.x - v1.x) * (v2.x - v1.x) + (cLocal.y - v1.y) * (v2.y - v1.y);
|
|
var u2 = (cLocal.x - v2.x) * (v1.x - v2.x) + (cLocal.y - v2.y) * (v1.y - v2.y);
|
|
if (u1 <= 0) {
|
|
if (b2DistanceSquared(cLocal, v1) > radius * radius) {
|
|
return
|
|
}
|
|
manifold.pointCount = 1;
|
|
manifold.type = b2Manifold.e_faceA;
|
|
manifold.localNormal.x = cLocal.x - v1.x;
|
|
manifold.localNormal.y = cLocal.y - v1.y;
|
|
manifold.localNormal.Normalize();
|
|
manifold.localPoint.x = v1.x;
|
|
manifold.localPoint.y = v1.y;
|
|
manifold.points[0] = new b2ManifoldPoint();
|
|
manifold.points[0].localPoint.x = circleB.m_p.x;
|
|
manifold.points[0].localPoint.y = circleB.m_p.y;
|
|
manifold.points[0].id.Reset()
|
|
} else {
|
|
if (u2 <= 0) {
|
|
if (b2DistanceSquared(cLocal, v2) > radius * radius) {
|
|
return
|
|
}
|
|
manifold.pointCount = 1;
|
|
manifold.type = b2Manifold.e_faceA;
|
|
manifold.localNormal.x = cLocal.x - v2.x;
|
|
manifold.localNormal.y = cLocal.y - v2.y;
|
|
manifold.localNormal.Normalize();
|
|
manifold.localPoint.x = v2.x;
|
|
manifold.localPoint.y = v2.y;
|
|
manifold.points[0] = new b2ManifoldPoint();
|
|
manifold.points[0].localPoint.x = circleB.m_p.x;
|
|
manifold.points[0].localPoint.y = circleB.m_p.y;
|
|
manifold.points[0].id.Reset()
|
|
} else {
|
|
var faceCenterx = 0.5 * (v1.x + v2.x);
|
|
var faceCentery = 0.5 * (v1.y + v2.y);
|
|
var separation = (cLocal.x - faceCenterx) * normals[vertIndex1].x + (cLocal.y - faceCentery) * normals[vertIndex1].y;
|
|
if (separation > radius) {
|
|
return
|
|
}
|
|
manifold.pointCount = 1;
|
|
manifold.type = b2Manifold.e_faceA;
|
|
manifold.localNormal.x = normals[vertIndex1].x;
|
|
manifold.localNormal.y = normals[vertIndex1].y;
|
|
manifold.localPoint.x = faceCenterx;
|
|
manifold.localPoint.y = faceCentery;
|
|
manifold.points[0] = new b2ManifoldPoint();
|
|
manifold.points[0].localPoint.x = circleB.m_p.x;
|
|
manifold.points[0].localPoint.y = circleB.m_p.y;
|
|
manifold.points[0].id.Reset()
|
|
}
|
|
}
|
|
}
|
|
|
|
function b2FindMaxSeparation(edgeIndex, poly1, xf1, poly2, xf2) {
|
|
var count1 = poly1.m_count;
|
|
var count2 = poly2.m_count;
|
|
var n1s = poly1.m_normals;
|
|
var v1s = poly1.m_vertices;
|
|
var v2s = poly2.m_vertices;
|
|
var xf = b2MulT_t_t(xf2, xf1);
|
|
var bestIndex = 0;
|
|
var maxSeparation = -b2_maxFloat;
|
|
for (var i = 0; i < count1; ++i) {
|
|
var nx = xf.q.c * n1s[i].x - xf.q.s * n1s[i].y;
|
|
var ny = xf.q.s * n1s[i].x + xf.q.c * n1s[i].y;
|
|
var v1x = (xf.q.c * v1s[i].x - xf.q.s * v1s[i].y) + xf.p.x;
|
|
var v1y = (xf.q.s * v1s[i].x + xf.q.c * v1s[i].y) + xf.p.y;
|
|
var si = b2_maxFloat;
|
|
for (var j = 0; j < count2; ++j) {
|
|
var sij = nx * (v2s[j].x - v1x) + ny * (v2s[j].y - v1y);
|
|
if (sij < si) {
|
|
si = sij
|
|
}
|
|
}
|
|
if (si > maxSeparation) {
|
|
maxSeparation = si;
|
|
bestIndex = i
|
|
}
|
|
}
|
|
edgeIndex[0] = bestIndex;
|
|
return maxSeparation
|
|
}
|
|
|
|
function b2FindIncidentEdge(c, poly1, xf1, edge1, poly2, xf2) {
|
|
var normals1 = poly1.m_normals;
|
|
var count2 = poly2.m_count;
|
|
var vertices2 = poly2.m_vertices;
|
|
var normals2 = poly2.m_normals;
|
|
var t1x = xf1.q.c * normals1[edge1].x - xf1.q.s * normals1[edge1].y;
|
|
var t1y = xf1.q.s * normals1[edge1].x + xf1.q.c * normals1[edge1].y;
|
|
var normal1x = xf2.q.c * t1x + xf2.q.s * t1y;
|
|
var normal1y = -xf2.q.s * t1x + xf2.q.c * t1y;
|
|
var index = 0;
|
|
var minDot = b2_maxFloat;
|
|
for (var i = 0; i < count2; ++i) {
|
|
var dot = normal1x * normals2[i].x + normal1y * normals2[i].y;
|
|
if (dot < minDot) {
|
|
minDot = dot;
|
|
index = i
|
|
}
|
|
}
|
|
var i1 = index;
|
|
var i2 = i1 + 1 < count2 ? i1 + 1 : 0;
|
|
c[0].v.x = (xf2.q.c * vertices2[i1].x - xf2.q.s * vertices2[i1].y) + xf2.p.x;
|
|
c[0].v.y = (xf2.q.s * vertices2[i1].x + xf2.q.c * vertices2[i1].y) + xf2.p.y;
|
|
c[0].id.indexA = edge1;
|
|
c[0].id.indexB = i1;
|
|
c[0].id.typeA = b2ContactID.e_face;
|
|
c[0].id.typeB = b2ContactID.e_vertex;
|
|
c[1].v.x = (xf2.q.c * vertices2[i2].x - xf2.q.s * vertices2[i2].y) + xf2.p.x;
|
|
c[1].v.y = (xf2.q.s * vertices2[i2].x + xf2.q.c * vertices2[i2].y) + xf2.p.y;
|
|
c[1].id.indexA = edge1;
|
|
c[1].id.indexB = i2;
|
|
c[1].id.typeA = b2ContactID.e_face;
|
|
c[1].id.typeB = b2ContactID.e_vertex
|
|
}
|
|
|
|
function b2CollidePolygons(manifold, polyA, xfA, polyB, xfB) {
|
|
manifold.pointCount = 0;
|
|
var totalRadius = polyA.m_radius + polyB.m_radius;
|
|
var edgeA = [0];
|
|
var separationA = b2FindMaxSeparation(edgeA, polyA, xfA, polyB, xfB);
|
|
if (separationA > totalRadius) {
|
|
return
|
|
}
|
|
var edgeB = [0];
|
|
var separationB = b2FindMaxSeparation(edgeB, polyB, xfB, polyA, xfA);
|
|
if (separationB > totalRadius) {
|
|
return
|
|
}
|
|
var poly1;
|
|
var poly2;
|
|
var xf1, xf2;
|
|
var edge1 = 0;
|
|
var flip = 0;
|
|
var k_tol = 0.1 * b2_linearSlop;
|
|
if (separationB > separationA + k_tol) {
|
|
poly1 = polyB;
|
|
poly2 = polyA;
|
|
xf1 = xfB;
|
|
xf2 = xfA;
|
|
edge1 = edgeB[0];
|
|
manifold.type = b2Manifold.e_faceB;
|
|
flip = 1
|
|
} else {
|
|
poly1 = polyA;
|
|
poly2 = polyB;
|
|
xf1 = xfA;
|
|
xf2 = xfB;
|
|
edge1 = edgeA[0];
|
|
manifold.type = b2Manifold.e_faceA;
|
|
flip = 0
|
|
}
|
|
b2FindIncidentEdge(b2CollidePolygons._local_incidentEdges, poly1, xf1, edge1, poly2, xf2);
|
|
var count1 = poly1.m_count;
|
|
var vertices1 = poly1.m_vertices;
|
|
var iv1 = edge1;
|
|
var iv2 = edge1 + 1 < count1 ? edge1 + 1 : 0;
|
|
var v11 = vertices1[iv1];
|
|
var v12 = vertices1[iv2];
|
|
b2CollidePolygons._localTangent.x = v12.x - v11.x;
|
|
b2CollidePolygons._localTangent.y = v12.y - v11.y;
|
|
b2CollidePolygons._localTangent.Normalize();
|
|
var localNormalx = 1 * b2CollidePolygons._localTangent.y;
|
|
var localNormaly = -1 * b2CollidePolygons._localTangent.x;
|
|
var planePointx = 0.5 * (v11.x + v12.x);
|
|
var planePointy = 0.5 * (v11.y + v12.y);
|
|
var tangentx = xf1.q.c * b2CollidePolygons._localTangent.x - xf1.q.s * b2CollidePolygons._localTangent.y;
|
|
var tangenty = xf1.q.s * b2CollidePolygons._localTangent.x + xf1.q.c * b2CollidePolygons._localTangent.y;
|
|
var normalx = 1 * tangenty;
|
|
var normaly = -1 * tangentx;
|
|
v11 = b2Mul_t_v2(xf1, v11);
|
|
v12 = b2Mul_t_v2(xf1, v12);
|
|
var frontOffset = normalx * v11.x + normaly * v11.y;
|
|
var sideOffset1 = -(tangentx * v11.x + tangenty * v11.y) + totalRadius;
|
|
var sideOffset2 = (tangentx * v12.x + tangenty * v12.y) + totalRadius;
|
|
var clipPoints1 = new Array(2);
|
|
var clipPoints2 = new Array(2);
|
|
var np;
|
|
np = b2ClipSegmentToLine(clipPoints1, b2CollidePolygons._local_incidentEdges, -tangentx, -tangenty, sideOffset1, iv1);
|
|
if (np < 2) {
|
|
return
|
|
}
|
|
np = b2ClipSegmentToLine(clipPoints2, clipPoints1, tangentx, tangenty, sideOffset2, iv2);
|
|
if (np < 2) {
|
|
return
|
|
}
|
|
manifold.localNormal.x = localNormalx;
|
|
manifold.localNormal.y = localNormaly;
|
|
manifold.localPoint.x = planePointx;
|
|
manifold.localPoint.y = planePointy;
|
|
var pointCount = 0;
|
|
for (var i = 0; i < b2_maxManifoldPoints; ++i) {
|
|
var separation = (normalx * clipPoints2[i].v.x + normaly * clipPoints2[i].v.y) - frontOffset;
|
|
if (separation <= totalRadius) {
|
|
var cp = manifold.points[pointCount] = new b2ManifoldPoint();
|
|
cp.localPoint.Assign(b2MulT_t_v2(xf2, clipPoints2[i].v));
|
|
cp.id.Assign(clipPoints2[i].id);
|
|
if (flip) {
|
|
var cf = new b2ContactID();
|
|
cf.Assign(cp.id);
|
|
cp.id.indexA = cf.indexB;
|
|
cp.id.indexB = cf.indexA;
|
|
cp.id.typeA = cf.typeB;
|
|
cp.id.typeB = cf.typeA
|
|
}++pointCount
|
|
}
|
|
}
|
|
manifold.pointCount = pointCount
|
|
}
|
|
b2CollidePolygons._localTangent = new b2Vec2();
|
|
b2CollidePolygons._local_incidentEdges = [new b2ClipVertex(), new b2ClipVertex()];
|
|
|
|
function b2CollideEdgeAndCircle(manifold, edgeA, xfA, circleB, xfB) {
|
|
manifold.pointCount = 0;
|
|
var Q = b2MulT_t_v2(xfA, b2Mul_t_v2(xfB, circleB.m_p));
|
|
var A = edgeA.m_vertex1,
|
|
B = edgeA.m_vertex2;
|
|
var ex = B.x - A.x;
|
|
var ey = B.y - A.y;
|
|
var u = ex * (B.x - Q.x) + ey * (B.y - Q.y);
|
|
var v = ex * (Q.x - A.x) + ey * (Q.y - A.y);
|
|
var radius = edgeA.m_radius + circleB.m_radius;
|
|
var cf = new b2ContactID();
|
|
cf.indexB = 0;
|
|
cf.typeB = b2ContactID.e_vertex;
|
|
if (v <= 0) {
|
|
var P = A;
|
|
var dx = Q.x - P.x;
|
|
var dy = Q.y - P.y;
|
|
var dd = dx * dx + dy * dy;
|
|
if (dd > radius * radius) {
|
|
return
|
|
}
|
|
if (edgeA.m_hasVertex0) {
|
|
var A1 = edgeA.m_vertex0;
|
|
var B1 = A;
|
|
var e1x = B1.x - A1.x;
|
|
var e1y = B1.y - A1.y;
|
|
var u1 = e1x * (B1.x - Q.x) + e1y * (B1.y - Q.y);
|
|
if (u1 > 0) {
|
|
return
|
|
}
|
|
}
|
|
cf.indexA = 0;
|
|
cf.typeA = b2ContactID.e_vertex;
|
|
manifold.pointCount = 1;
|
|
manifold.type = b2Manifold.e_circles;
|
|
manifold.localNormal.x = manifold.localNormal.y = 0;
|
|
manifold.localPoint.x = P.x;
|
|
manifold.localPoint.y = P.y;
|
|
manifold.points[0] = new b2ManifoldPoint();
|
|
manifold.points[0].id.Assign(cf);
|
|
manifold.points[0].localPoint.x = circleB.m_p.x;
|
|
manifold.points[0].localPoint.y = circleB.m_p.y;
|
|
return
|
|
}
|
|
if (u <= 0) {
|
|
var P = B;
|
|
var dx = Q.x - P.x;
|
|
var dy = Q.y - P.y;
|
|
var dd = dx * dx + dy * dy;
|
|
if (dd > radius * radius) {
|
|
return
|
|
}
|
|
if (edgeA.m_hasVertex3) {
|
|
var B2 = edgeA.m_vertex3;
|
|
var A2 = B;
|
|
var e2x = B2.x - A2.x;
|
|
var e2y = B2.y - A2.y;
|
|
var v2 = e2x * (Q.x - A2.x) + e2y * (Q.y - A2.y);
|
|
if (v2 > 0) {
|
|
return
|
|
}
|
|
}
|
|
cf.indexA = 1;
|
|
cf.typeA = b2ContactID.e_vertex;
|
|
manifold.pointCount = 1;
|
|
manifold.type = b2Manifold.e_circles;
|
|
manifold.localNormal.x = manifold.localNormal.y = 0;
|
|
manifold.localPoint.x = P.x;
|
|
manifold.localPoint.y = P.y;
|
|
manifold.points[0] = new b2ManifoldPoint();
|
|
manifold.points[0].id.Assign(cf);
|
|
manifold.points[0].localPoint.x = circleB.m_p.x;
|
|
manifold.points[0].localPoint.y = circleB.m_p.y;
|
|
return
|
|
}
|
|
var den = ex * ex + ey * ey;
|
|
var Px = (1 / den) * ((u * A.x) + (v * B.x));
|
|
var Py = (1 / den) * ((u * A.y) + (v * B.y));
|
|
var dx = Q.x - Px;
|
|
var dy = Q.y - Py;
|
|
var dd = dx * dx + dy * dy;
|
|
if (dd > radius * radius) {
|
|
return
|
|
}
|
|
var nx = -ey;
|
|
var ny = ex;
|
|
if (nx * (Q.x - A.x) + ny * (Q.y - A.y) < 0) {
|
|
nx = -nx;
|
|
ny = -ny
|
|
}
|
|
cf.indexA = 0;
|
|
cf.typeA = b2ContactID.e_face;
|
|
manifold.pointCount = 1;
|
|
manifold.type = b2Manifold.e_faceA;
|
|
manifold.localNormal.x = nx;
|
|
manifold.localNormal.y = ny;
|
|
manifold.localNormal.Normalize();
|
|
manifold.localPoint.x = A.x;
|
|
manifold.localPoint.y = A.y;
|
|
manifold.points[0] = new b2ManifoldPoint();
|
|
manifold.points[0].id.Assign(cf);
|
|
manifold.points[0].localPoint.x = circleB.m_p.x;
|
|
manifold.points[0].localPoint.y = circleB.m_p.y
|
|
}
|
|
|
|
function b2EPAxis() {
|
|
this.type = 0;
|
|
this.index = 0;
|
|
this.separation = 0
|
|
}
|
|
b2EPAxis.e_unknown = 0;
|
|
b2EPAxis.e_edgeA = 1;
|
|
b2EPAxis.e_edgeB = 2;
|
|
|
|
function b2TempPolygon() {
|
|
this.vertices = new Array(b2_maxPolygonVertices);
|
|
this.normals = new Array(b2_maxPolygonVertices);
|
|
this.count = 0
|
|
}
|
|
|
|
function b2ReferenceFace() {
|
|
this.i1 = 0, this.i2 = 0;
|
|
this.v1 = new b2Vec2(), this.v2 = new b2Vec2();
|
|
this.normal = new b2Vec2();
|
|
this.sideNormal1 = new b2Vec2();
|
|
this.sideOffset1 = 0;
|
|
this.sideNormal2 = new b2Vec2();
|
|
this.sideOffset2 = 0
|
|
}
|
|
|
|
function b2EPCollider() {
|
|
this.m_polygonB = new b2TempPolygon();
|
|
this.m_xf = new b2Transform();
|
|
this.m_centroidB = new b2Vec2();
|
|
this.m_v0 = new b2Vec2(), this.m_v1 = new b2Vec2(), this.m_v2 = new b2Vec2(), this.m_v3 = new b2Vec2();
|
|
this.m_normal0 = new b2Vec2(), this.m_normal1 = new b2Vec2(), this.m_normal2 = new b2Vec2();
|
|
this.m_normal = new b2Vec2();
|
|
this.m_type1 = 0, this.m_type2 = 0;
|
|
this.m_lowerLimit = new b2Vec2(), this.m_upperLimit = new b2Vec2();
|
|
this.m_radius = 0;
|
|
this.m_front = false
|
|
}
|
|
b2EPCollider._temp_edge = new b2Vec2();
|
|
b2EPCollider._temp_edge0 = new b2Vec2();
|
|
b2EPCollider._temp_edge2 = new b2Vec2();
|
|
b2EPCollider.prototype = {
|
|
Collide: function (manifold, edgeA, xfA, polygonB, xfB) {
|
|
this.m_xf.Assign(b2MulT_t_t(xfA, xfB));
|
|
this.m_centroidB.x = (this.m_xf.q.c * polygonB.m_centroid.x - this.m_xf.q.s * polygonB.m_centroid.y) + this.m_xf.p.x;
|
|
this.m_centroidB.y = (this.m_xf.q.s * polygonB.m_centroid.x + this.m_xf.q.c * polygonB.m_centroid.y) + this.m_xf.p.y;
|
|
this.m_v0.x = edgeA.m_vertex0.x;
|
|
this.m_v0.y = edgeA.m_vertex0.y;
|
|
this.m_v1.x = edgeA.m_vertex1.x;
|
|
this.m_v1.y = edgeA.m_vertex1.y;
|
|
this.m_v2.x = edgeA.m_vertex2.x;
|
|
this.m_v2.y = edgeA.m_vertex2.y;
|
|
this.m_v3.x = edgeA.m_vertex3.x;
|
|
this.m_v3.y = edgeA.m_vertex3.y;
|
|
var hasVertex0 = edgeA.m_hasVertex0;
|
|
var hasVertex3 = edgeA.m_hasVertex3;
|
|
b2EPCollider._temp_edge.x = this.m_v2.x - this.m_v1.x;
|
|
b2EPCollider._temp_edge.y = this.m_v2.y - this.m_v1.y;
|
|
b2EPCollider._temp_edge.Normalize();
|
|
this.m_normal1.x = b2EPCollider._temp_edge.y;
|
|
this.m_normal1.y = -b2EPCollider._temp_edge.x;
|
|
var offset1 = this.m_normal1.x * (this.m_centroidB.x - this.m_v1.x) + this.m_normal1.y * (this.m_centroidB.y - this.m_v1.y);
|
|
var offset0 = 0,
|
|
offset2 = 0;
|
|
var convex1 = false,
|
|
convex2 = false;
|
|
if (hasVertex0) {
|
|
b2EPCollider._temp_edge0.x = this.m_v1.x - this.m_v0.x;
|
|
b2EPCollider._temp_edge0.y = this.m_v1.y - this.m_v0.y;
|
|
b2EPCollider._temp_edge0.Normalize();
|
|
this.m_normal0.x = b2EPCollider._temp_edge0.y;
|
|
this.m_normal0.y = -b2EPCollider._temp_edge0.x;
|
|
convex1 = (b2EPCollider._temp_edge0.x * b2EPCollider._temp_edge.y - b2EPCollider._temp_edge0.y * b2EPCollider._temp_edge.x) >= 0;
|
|
offset0 = this.m_normal0.x * (this.m_centroidB.x - this.m_v0.x) + this.m_normal0.y * (this.m_centroidB.y - this.m_v0.y)
|
|
}
|
|
if (hasVertex3) {
|
|
b2EPCollider._temp_edge2.x = this.m_v3.x - this.m_v2.x;
|
|
b2EPCollider._temp_edge2.y = this.m_v3.y - this.m_v2.y;
|
|
b2EPCollider._temp_edge2.Normalize();
|
|
this.m_normal2.x = b2EPCollider._temp_edge2.y;
|
|
this.m_normal2.y = -b2EPCollider._temp_edge2.x;
|
|
convex2 = (b2EPCollider._temp_edge.x * b2EPCollider._temp_edge2.y - b2EPCollider._temp_edge.y * b2EPCollider._temp_edge2.x) > 0;
|
|
offset2 = this.m_normal2.x * (this.m_centroidB.x - this.m_v2.x) + this.m_normal2.y * (this.m_centroidB.y - this.m_v2.y)
|
|
}
|
|
if (hasVertex0 && hasVertex3) {
|
|
if (convex1 && convex2) {
|
|
this.m_front = offset0 >= 0 || offset1 >= 0 || offset2 >= 0;
|
|
if (this.m_front) {
|
|
this.m_normal.x = this.m_normal1.x;
|
|
this.m_normal.y = this.m_normal1.y;
|
|
this.m_lowerLimit.x = this.m_normal0.x;
|
|
this.m_lowerLimit.y = this.m_normal0.y;
|
|
this.m_upperLimit.x = this.m_normal2.x;
|
|
this.m_upperLimit.y = this.m_normal2.y
|
|
} else {
|
|
this.m_normal.x = -this.m_normal1.x;
|
|
this.m_normal.y = -this.m_normal1.y;
|
|
this.m_lowerLimit.x = -this.m_normal1.x;
|
|
this.m_lowerLimit.y = -this.m_normal1.y;
|
|
this.m_upperLimit.x = -this.m_normal1.x;
|
|
this.m_upperLimit.y = -this.m_normal1.y
|
|
}
|
|
} else {
|
|
if (convex1) {
|
|
this.m_front = offset0 >= 0 || (offset1 >= 0 && offset2 >= 0);
|
|
if (this.m_front) {
|
|
this.m_normal.x = this.m_normal1.x;
|
|
this.m_normal.y = this.m_normal1.y;
|
|
this.m_lowerLimit.x = this.m_normal0.x;
|
|
this.m_lowerLimit.y = this.m_normal0.y;
|
|
this.m_upperLimit.x = this.m_normal1.x;
|
|
this.m_upperLimit.y = this.m_normal1.y
|
|
} else {
|
|
this.m_normal.x = -this.m_normal1.x;
|
|
this.m_normal.y = -this.m_normal1.y;
|
|
this.m_lowerLimit.x = -this.m_normal2.x;
|
|
this.m_lowerLimit.y = -this.m_normal2.y;
|
|
this.m_upperLimit.x = -this.m_normal1.x;
|
|
this.m_upperLimit.y = -this.m_normal1.y
|
|
}
|
|
} else {
|
|
if (convex2) {
|
|
this.m_front = offset2 >= 0 || (offset0 >= 0 && offset1 >= 0);
|
|
if (this.m_front) {
|
|
this.m_normal.x = this.m_normal1.x;
|
|
this.m_normal.y = this.m_normal1.y;
|
|
this.m_lowerLimit.x = this.m_normal1.x;
|
|
this.m_lowerLimit.y = this.m_normal1.y;
|
|
this.m_upperLimit.x = this.m_normal2.x;
|
|
this.m_upperLimit.y = this.m_normal2.y
|
|
} else {
|
|
this.m_normal.x = -this.m_normal1.x;
|
|
this.m_normal.y = -this.m_normal1.y;
|
|
this.m_lowerLimit.x = -this.m_normal1.x;
|
|
this.m_lowerLimit.y = -this.m_normal1.y;
|
|
this.m_upperLimit.x = -this.m_normal0.x;
|
|
this.m_upperLimit.y = -this.m_normal0.y
|
|
}
|
|
} else {
|
|
this.m_front = offset0 >= 0 && offset1 >= 0 && offset2 >= 0;
|
|
if (this.m_front) {
|
|
this.m_normal.x = this.m_normal1.x;
|
|
this.m_normal.y = this.m_normal1.y;
|
|
this.m_lowerLimit.x = this.m_normal1.x;
|
|
this.m_lowerLimit.y = this.m_normal1.y;
|
|
this.m_upperLimit.x = this.m_normal1.x;
|
|
this.m_upperLimit.y = this.m_normal1.y
|
|
} else {
|
|
this.m_normal.x = -this.m_normal1.x;
|
|
this.m_normal.y = -this.m_normal1.y;
|
|
this.m_lowerLimit.x = -this.m_normal2.x;
|
|
this.m_lowerLimit.y = -this.m_normal2.y;
|
|
this.m_upperLimit.x = -this.m_normal0.x;
|
|
this.m_upperLimit.y = -this.m_normal0.y
|
|
}
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (hasVertex0) {
|
|
if (convex1) {
|
|
this.m_front = offset0 >= 0 || offset1 >= 0;
|
|
if (this.m_front) {
|
|
this.m_normal.x = this.m_normal1.x;
|
|
this.m_normal.y = this.m_normal1.y;
|
|
this.m_lowerLimit.x = this.m_normal0.x;
|
|
this.m_lowerLimit.y = this.m_normal0.y;
|
|
this.m_upperLimit.x = -this.m_normal1.x;
|
|
this.m_upperLimit.y = -this.m_normal1.y
|
|
} else {
|
|
this.m_normal.x = -this.m_normal1.x;
|
|
this.m_normal.y = -this.m_normal1.y;
|
|
this.m_lowerLimit.x = this.m_normal1.x;
|
|
this.m_lowerLimit.y = this.m_normal1.y;
|
|
this.m_upperLimit.x = -this.m_normal1.x;
|
|
this.m_upperLimit.y = -this.m_normal1.y
|
|
}
|
|
} else {
|
|
this.m_front = offset0 >= 0 && offset1 >= 0;
|
|
if (this.m_front) {
|
|
this.m_normal.x = this.m_normal1.x;
|
|
this.m_normal.y = this.m_normal1.y;
|
|
this.m_lowerLimit.x = this.m_normal1.x;
|
|
this.m_lowerLimit.y = this.m_normal1.y;
|
|
this.m_upperLimit.x = -this.m_normal1.x;
|
|
this.m_upperLimit.y = -this.m_normal1.y
|
|
} else {
|
|
this.m_normal.x = -this.m_normal1.x;
|
|
this.m_normal.y = -this.m_normal1.y;
|
|
this.m_lowerLimit.x = this.m_normal1.x;
|
|
this.m_lowerLimit.y = this.m_normal1.y;
|
|
this.m_upperLimit.x = -this.m_normal0.x;
|
|
this.m_upperLimit.y = -this.m_normal0.y
|
|
}
|
|
}
|
|
} else {
|
|
if (hasVertex3) {
|
|
if (convex2) {
|
|
this.m_front = offset1 >= 0 || offset2 >= 0;
|
|
if (this.m_front) {
|
|
this.m_normal.x = this.m_normal1.x;
|
|
this.m_normal.y = this.m_normal1.y;
|
|
this.m_lowerLimit.x = -this.m_normal1.x;
|
|
this.m_lowerLimit.y = -this.m_normal1.y;
|
|
this.m_upperLimit.x = this.m_normal2.x;
|
|
this.m_upperLimit.y = this.m_normal2.y
|
|
} else {
|
|
this.m_normal.x = -this.m_normal1.x;
|
|
this.m_normal.y = -this.m_normal1.y;
|
|
this.m_lowerLimit.x = -this.m_normal1.x;
|
|
this.m_lowerLimit.y = -this.m_normal1.y;
|
|
this.m_upperLimit.x = this.m_normal1.x;
|
|
this.m_upperLimit.y = this.m_normal1.y
|
|
}
|
|
} else {
|
|
this.m_front = offset1 >= 0 && offset2 >= 0;
|
|
if (this.m_front) {
|
|
this.m_normal.x = this.m_normal1.x;
|
|
this.m_normal.y = this.m_normal1.y;
|
|
this.m_lowerLimit.x = -this.m_normal1.x;
|
|
this.m_lowerLimit.y = -this.m_normal1.y;
|
|
this.m_upperLimit.x = this.m_normal1.x;
|
|
this.m_upperLimit.y = this.m_normal1.y
|
|
} else {
|
|
this.m_normal.x = -this.m_normal1.x;
|
|
this.m_normal.y = -this.m_normal1.y;
|
|
this.m_lowerLimit.x = -this.m_normal2.x;
|
|
this.m_lowerLimit.y = -this.m_normal2.y;
|
|
this.m_upperLimit.x = this.m_normal1.x;
|
|
this.m_upperLimit.y = this.m_normal1.y
|
|
}
|
|
}
|
|
} else {
|
|
this.m_front = offset1 >= 0;
|
|
if (this.m_front) {
|
|
this.m_normal.x = this.m_normal1.x;
|
|
this.m_normal.y = this.m_normal1.y;
|
|
this.m_lowerLimit.x = -this.m_normal1.x;
|
|
this.m_lowerLimit.y = -this.m_normal1.y;
|
|
this.m_upperLimit.x = -this.m_normal1.x;
|
|
this.m_upperLimit.y = -this.m_normal1.y
|
|
} else {
|
|
this.m_normal.x = -this.m_normal1.x;
|
|
this.m_normal.y = -this.m_normal1.y;
|
|
this.m_lowerLimit.x = this.m_normal1.x;
|
|
this.m_lowerLimit.y = this.m_normal1.y;
|
|
this.m_upperLimit.x = this.m_normal1.x;
|
|
this.m_upperLimit.y = this.m_normal1.y
|
|
}
|
|
}
|
|
}
|
|
}
|
|
this.m_polygonB.count = polygonB.m_count;
|
|
for (var i = 0; i < polygonB.m_count; ++i) {
|
|
this.m_polygonB.vertices[i] = b2Mul_t_v2(this.m_xf, polygonB.m_vertices[i]);
|
|
this.m_polygonB.normals[i] = b2Mul_r_v2(this.m_xf.q, polygonB.m_normals[i])
|
|
}
|
|
this.m_radius = 2 * b2_polygonRadius;
|
|
manifold.pointCount = 0;
|
|
var edgeAxis = this.ComputeEdgeSeparation();
|
|
if (edgeAxis.type == b2EPAxis.e_unknown) {
|
|
return
|
|
}
|
|
if (edgeAxis.separation > this.m_radius) {
|
|
return
|
|
}
|
|
var polygonAxis = this.ComputePolygonSeparation();
|
|
if (polygonAxis.type != b2EPAxis.e_unknown && polygonAxis.separation > this.m_radius) {
|
|
return
|
|
}
|
|
var k_relativeTol = 0.98;
|
|
var k_absoluteTol = 0.001;
|
|
var primaryAxis = new b2EPAxis();
|
|
if (polygonAxis.type == b2EPAxis.e_unknown) {
|
|
primaryAxis = edgeAxis
|
|
} else {
|
|
if (polygonAxis.separation > k_relativeTol * edgeAxis.separation + k_absoluteTol) {
|
|
primaryAxis = polygonAxis
|
|
} else {
|
|
primaryAxis = edgeAxis
|
|
}
|
|
}
|
|
var ie = new Array(2);
|
|
var rf = new b2ReferenceFace();
|
|
if (primaryAxis.type == b2EPAxis.e_edgeA) {
|
|
manifold.type = b2Manifold.e_faceA;
|
|
var bestIndex = 0;
|
|
var bestValue = this.m_normal.x * this.m_polygonB.normals[0].x + this.m_normal.y * this.m_polygonB.normals[0].y;
|
|
for (var i = 1; i < this.m_polygonB.count; ++i) {
|
|
var value = this.m_normal.x * this.m_polygonB.normals[i].x + this.m_normal.y * this.m_polygonB.normals[i].y;
|
|
if (value < bestValue) {
|
|
bestValue = value;
|
|
bestIndex = i
|
|
}
|
|
}
|
|
var i1 = bestIndex;
|
|
var i2 = i1 + 1 < this.m_polygonB.count ? i1 + 1 : 0;
|
|
ie[0] = new b2ClipVertex();
|
|
ie[0].v.x = this.m_polygonB.vertices[i1].x;
|
|
ie[0].v.y = this.m_polygonB.vertices[i1].y;
|
|
ie[0].id.indexA = 0;
|
|
ie[0].id.indexB = i1;
|
|
ie[0].id.typeA = b2ContactID.e_face;
|
|
ie[0].id.typeB = b2ContactID.e_vertex;
|
|
ie[1] = new b2ClipVertex();
|
|
ie[1].v.x = this.m_polygonB.vertices[i2].x;
|
|
ie[1].v.y = this.m_polygonB.vertices[i2].y;
|
|
ie[1].id.indexA = 0;
|
|
ie[1].id.indexB = i2;
|
|
ie[1].id.typeA = b2ContactID.e_face;
|
|
ie[1].id.typeB = b2ContactID.e_vertex;
|
|
if (this.m_front) {
|
|
rf.i1 = 0;
|
|
rf.i2 = 1;
|
|
rf.v1.x = this.m_v1.x;
|
|
rf.v1.y = this.m_v1.y;
|
|
rf.v2.x = this.m_v2.x;
|
|
rf.v2.y = this.m_v2.y;
|
|
rf.normal.x = this.m_normal1.x;
|
|
rf.normal.y = this.m_normal1.y
|
|
} else {
|
|
rf.i1 = 1;
|
|
rf.i2 = 0;
|
|
rf.v1.x = this.m_v2.x;
|
|
rf.v1.y = this.m_v2.y;
|
|
rf.v2.x = this.m_v1.x;
|
|
rf.v2.y = this.m_v1.y;
|
|
rf.normal.x = -this.m_normal1.x;
|
|
rf.normal.y = -this.m_normal1.y
|
|
}
|
|
} else {
|
|
manifold.type = b2Manifold.e_faceB;
|
|
ie[0] = new b2ClipVertex();
|
|
ie[0].v = this.m_v1;
|
|
ie[0].id.indexA = 0;
|
|
ie[0].id.indexB = primaryAxis.index;
|
|
ie[0].id.typeA = b2ContactID.e_vertex;
|
|
ie[0].id.typeB = b2ContactID.e_face;
|
|
ie[1] = new b2ClipVertex();
|
|
ie[1].v = this.m_v2;
|
|
ie[1].id.indexA = 0;
|
|
ie[1].id.indexB = primaryAxis.index;
|
|
ie[1].id.typeA = b2ContactID.e_vertex;
|
|
ie[1].id.typeB = b2ContactID.e_face;
|
|
rf.i1 = primaryAxis.index;
|
|
rf.i2 = rf.i1 + 1 < this.m_polygonB.count ? rf.i1 + 1 : 0;
|
|
rf.v1.x = this.m_polygonB.vertices[rf.i1].x;
|
|
rf.v1.y = this.m_polygonB.vertices[rf.i1].y;
|
|
rf.v2.x = this.m_polygonB.vertices[rf.i2].x;
|
|
rf.v2.y = this.m_polygonB.vertices[rf.i2].y;
|
|
rf.normal.x = this.m_polygonB.normals[rf.i1].x;
|
|
rf.normal.y = this.m_polygonB.normals[rf.i1].y
|
|
}
|
|
rf.sideNormal1.x = rf.normal.y;
|
|
rf.sideNormal1.y = -rf.normal.x;
|
|
rf.sideNormal2.x = -rf.sideNormal1.x;
|
|
rf.sideNormal2.y = -rf.sideNormal1.y;
|
|
rf.sideOffset1 = rf.sideNormal1.x * rf.v1.x + rf.sideNormal1.y * rf.v1.y;
|
|
rf.sideOffset2 = rf.sideNormal2.x * rf.v2.x + rf.sideNormal2.y * rf.v2.y;
|
|
var clipPoints1 = new Array(2);
|
|
var clipPoints2 = new Array(2);
|
|
var np;
|
|
np = b2ClipSegmentToLine(clipPoints1, ie, rf.sideNormal1.x, rf.sideNormal1.y, rf.sideOffset1, rf.i1);
|
|
if (np < b2_maxManifoldPoints) {
|
|
return
|
|
}
|
|
np = b2ClipSegmentToLine(clipPoints2, clipPoints1, rf.sideNormal2.x, rf.sideNormal2.y, rf.sideOffset2, rf.i2);
|
|
if (np < b2_maxManifoldPoints) {
|
|
return
|
|
}
|
|
if (primaryAxis.type == b2EPAxis.e_edgeA) {
|
|
manifold.localNormal.x = rf.normal.x;
|
|
manifold.localNormal.y = rf.normal.y;
|
|
manifold.localPoint.x = rf.v1.x;
|
|
manifold.localPoint.y = rf.v1.y
|
|
} else {
|
|
manifold.localNormal.x = polygonB.m_normals[rf.i1].x;
|
|
manifold.localNormal.y = polygonB.m_normals[rf.i1].y;
|
|
manifold.localPoint.x = polygonB.m_vertices[rf.i1].x;
|
|
manifold.localPoint.y = polygonB.m_vertices[rf.i1].y
|
|
}
|
|
var pointCount = 0;
|
|
for (var i = 0; i < b2_maxManifoldPoints; ++i) {
|
|
var separation = rf.normal.x * (clipPoints2[i].v.x - rf.v1.x) + rf.normal.y * (clipPoints2[i].v.y - rf.v1.y);
|
|
if (separation <= this.m_radius) {
|
|
var cp = manifold.points[pointCount] = new b2ManifoldPoint();
|
|
if (primaryAxis.type == b2EPAxis.e_edgeA) {
|
|
cp.localPoint.Assign(b2MulT_t_v2(this.m_xf, clipPoints2[i].v));
|
|
cp.id.Assign(clipPoints2[i].id)
|
|
} else {
|
|
cp.localPoint.x = clipPoints2[i].v.x;
|
|
cp.localPoint.y = clipPoints2[i].v.y;
|
|
cp.id.typeA = clipPoints2[i].id.typeB;
|
|
cp.id.typeB = clipPoints2[i].id.typeA;
|
|
cp.id.indexA = clipPoints2[i].id.indexB;
|
|
cp.id.indexB = clipPoints2[i].id.indexA
|
|
}++pointCount
|
|
}
|
|
}
|
|
manifold.pointCount = pointCount
|
|
},
|
|
ComputeEdgeSeparation: function () {
|
|
var axis = new b2EPAxis();
|
|
axis.type = b2EPAxis.e_edgeA;
|
|
axis.index = this.m_front ? 0 : 1;
|
|
axis.separation = Number.MAX_VALUE;
|
|
for (var i = 0; i < this.m_polygonB.count; ++i) {
|
|
var s = this.m_normal.x * (this.m_polygonB.vertices[i].x - this.m_v1.x) + this.m_normal.y * (this.m_polygonB.vertices[i].y - this.m_v1.y);
|
|
if (s < axis.separation) {
|
|
axis.separation = s
|
|
}
|
|
}
|
|
return axis
|
|
},
|
|
ComputePolygonSeparation: function () {
|
|
var axis = new b2EPAxis();
|
|
axis.type = b2EPAxis.e_unknown;
|
|
axis.index = -1;
|
|
axis.separation = -Number.MAX_VALUE;
|
|
var perpx = -this.m_normal.y;
|
|
var perpy = this.m_normal.x;
|
|
for (var i = 0; i < this.m_polygonB.count; ++i) {
|
|
var nx = -this.m_polygonB.normals[i].x;
|
|
var ny = -this.m_polygonB.normals[i].y;
|
|
var s1 = nx * (this.m_polygonB.vertices[i].x - this.m_v1.x) + ny * (this.m_polygonB.vertices[i].y - this.m_v1.y);
|
|
var s2 = nx * (this.m_polygonB.vertices[i].x - this.m_v2.x) + ny * (this.m_polygonB.vertices[i].y - this.m_v2.y);
|
|
var s = b2Min(s1, s2);
|
|
if (s > this.m_radius) {
|
|
axis.type = b2EPAxis.e_edgeB;
|
|
axis.index = i;
|
|
axis.separation = s;
|
|
return axis
|
|
}
|
|
if (nx * perpx + ny * perpy >= 0) {
|
|
if ((nx - this.m_upperLimit.x) * this.m_normal.x + (ny - this.m_upperLimit.y) * this.m_normal.y < -b2_angularSlop) {
|
|
continue
|
|
}
|
|
} else {
|
|
if ((nx - this.m_lowerLimit.x) * this.m_normal.x + (ny - this.m_lowerLimit.y) * this.m_normal.y < -b2_angularSlop) {
|
|
continue
|
|
}
|
|
}
|
|
if (s > axis.separation) {
|
|
axis.type = b2EPAxis.e_edgeB;
|
|
axis.index = i;
|
|
axis.separation = s
|
|
}
|
|
}
|
|
return axis
|
|
}
|
|
};
|
|
b2EPCollider.e_isolated = 0;
|
|
b2EPCollider.e_concave = 1;
|
|
b2EPCollider.e_convex = 2;
|
|
|
|
function b2CollideEdgeAndPolygon(manifold, edgeA, xfA, polygonB, xfB) {
|
|
b2CollideEdgeAndPolygon.collider.Collide(manifold, edgeA, xfA, polygonB, xfB)
|
|
}
|
|
b2CollideEdgeAndPolygon.collider = new b2EPCollider();
|
|
|
|
function b2ClipSegmentToLine(vOut, vIn, normalx, normaly, offset, vertexIndexA) {
|
|
var numOut = 0;
|
|
var distance0 = (normalx * vIn[0].v.x + normaly * vIn[0].v.y) - offset;
|
|
var distance1 = (normalx * vIn[1].v.x + normaly * vIn[1].v.y) - offset;
|
|
if (distance0 <= 0) {
|
|
vOut[numOut++] = vIn[0]
|
|
}
|
|
if (distance1 <= 0) {
|
|
vOut[numOut++] = vIn[1]
|
|
}
|
|
if (distance0 * distance1 < 0) {
|
|
var interp = distance0 / (distance0 - distance1);
|
|
vOut[numOut] = new b2ClipVertex();
|
|
vOut[numOut].v.x = vIn[0].v.x + (interp * (vIn[1].v.x - vIn[0].v.x));
|
|
vOut[numOut].v.y = vIn[0].v.y + (interp * (vIn[1].v.y - vIn[0].v.y));
|
|
vOut[numOut].id.indexA = vertexIndexA;
|
|
vOut[numOut].id.indexB = vIn[0].id.indexB;
|
|
vOut[numOut].id.typeA = b2ContactID.e_vertex;
|
|
vOut[numOut].id.typeB = b2ContactID.e_face;
|
|
++numOut
|
|
}
|
|
return numOut
|
|
}
|
|
|
|
function b2TestShapeOverlap(shapeA, indexA, shapeB, indexB, xfA, xfB) {
|
|
b2TestShapeOverlap.input.proxyA.Set(shapeA, indexA);
|
|
b2TestShapeOverlap.input.proxyB.Set(shapeB, indexB);
|
|
b2TestShapeOverlap.input.transformA = xfA;
|
|
b2TestShapeOverlap.input.transformB = xfB;
|
|
b2TestShapeOverlap.input.useRadii = true;
|
|
b2TestShapeOverlap.cache.count = 0;
|
|
b2DistanceFunc(b2TestShapeOverlap.output, b2TestShapeOverlap.cache, b2TestShapeOverlap.input);
|
|
return b2TestShapeOverlap.output.distance < 10 * b2_epsilon
|
|
}
|
|
b2TestShapeOverlap.input = new b2DistanceInput();
|
|
b2TestShapeOverlap.cache = new b2SimplexCache();
|
|
b2TestShapeOverlap.output = new b2DistanceOutput();
|
|
|
|
function b2TestOverlap(a, b) {
|
|
return !((b.lowerBound.x - a.upperBound.x) > 0 || (b.lowerBound.y - a.upperBound.y) > 0 || (a.lowerBound.x - b.upperBound.x) > 0 || (a.lowerBound.y - b.upperBound.y) > 0)
|
|
}
|
|
"use strict";
|
|
var b2_nullNode = -1;
|
|
|
|
function b2TreeNode() {
|
|
this.aabb = new b2AABB();
|
|
this.userData = null;
|
|
this.parent = 0;
|
|
this.child1 = this.child2 = this.height = 0
|
|
}
|
|
b2TreeNode.prototype = {
|
|
IsLeaf: function () {
|
|
return this.child1 == b2_nullNode
|
|
}
|
|
};
|
|
|
|
function b2DynamicTree() {
|
|
this.m_root = b2_nullNode;
|
|
this.m_nodeCapacity = 16;
|
|
this.m_nodeCount = 0;
|
|
this.m_nodes = new Array(this.m_nodeCapacity);
|
|
for (var i = 0; i < this.m_nodeCapacity - 1; ++i) {
|
|
this.m_nodes[i] = new b2TreeNode();
|
|
this.m_nodes[i].parent = i + 1;
|
|
this.m_nodes[i].height = -1
|
|
}
|
|
this.m_nodes[this.m_nodeCapacity - 1] = new b2TreeNode();
|
|
this.m_nodes[this.m_nodeCapacity - 1].parent = b2_nullNode;
|
|
this.m_nodes[this.m_nodeCapacity - 1].height = -1;
|
|
this.m_freeList = 0;
|
|
this.m_path = 0;
|
|
this.m_insertionCount = 0
|
|
}
|
|
b2DynamicTree.aabbExtensionFattener = new b2Vec2(b2_aabbExtension, b2_aabbExtension);
|
|
b2DynamicTree.prototype = {
|
|
CreateProxy: function (aabb, userData) {
|
|
var proxyId = this.AllocateNode();
|
|
this.m_nodes[proxyId].aabb.lowerBound.Assign(b2Vec2.Subtract(aabb.lowerBound, b2DynamicTree.aabbExtensionFattener));
|
|
this.m_nodes[proxyId].aabb.upperBound.Assign(b2Vec2.Add(aabb.upperBound, b2DynamicTree.aabbExtensionFattener));
|
|
this.m_nodes[proxyId].userData = userData;
|
|
this.m_nodes[proxyId].height = 0;
|
|
this.InsertLeaf(proxyId);
|
|
return proxyId
|
|
},
|
|
DestroyProxy: function (proxyId) {
|
|
this.RemoveLeaf(proxyId);
|
|
this.FreeNode(proxyId)
|
|
},
|
|
MoveProxy: function (proxyId, aabb, displacement) {
|
|
if (this.m_nodes[proxyId].aabb.Contains(aabb)) {
|
|
return false
|
|
}
|
|
this.RemoveLeaf(proxyId);
|
|
this.m_nodes[proxyId].aabb.Assign(aabb);
|
|
this.m_nodes[proxyId].aabb.lowerBound.Subtract(b2DynamicTree.aabbExtensionFattener);
|
|
this.m_nodes[proxyId].aabb.upperBound.Add(b2DynamicTree.aabbExtensionFattener);
|
|
var d = b2Vec2.Multiply(b2_aabbMultiplier, displacement);
|
|
if (d.x < 0) {
|
|
this.m_nodes[proxyId].aabb.lowerBound.x += d.x
|
|
} else {
|
|
this.m_nodes[proxyId].aabb.upperBound.x += d.x
|
|
}
|
|
if (d.y < 0) {
|
|
this.m_nodes[proxyId].aabb.lowerBound.y += d.y
|
|
} else {
|
|
this.m_nodes[proxyId].aabb.upperBound.y += d.y
|
|
}
|
|
this.InsertLeaf(proxyId);
|
|
return true
|
|
},
|
|
GetUserData: function (proxyId) {
|
|
return this.m_nodes[proxyId].userData
|
|
},
|
|
GetFatAABB: function (proxyId) {
|
|
return this.m_nodes[proxyId].aabb
|
|
},
|
|
Query: function (callback, aabb) {
|
|
var stack = [];
|
|
stack.push(this.m_root);
|
|
while (stack.length > 0) {
|
|
var nodeId = stack.pop();
|
|
if (nodeId == b2_nullNode) {
|
|
continue
|
|
}
|
|
var node = this.m_nodes[nodeId];
|
|
if (b2TestOverlap(node.aabb, aabb)) {
|
|
if (node.IsLeaf()) {
|
|
var proceed = callback.QueryCallback(nodeId);
|
|
if (proceed == false) {
|
|
return
|
|
}
|
|
} else {
|
|
stack.push(node.child1);
|
|
stack.push(node.child2)
|
|
}
|
|
}
|
|
}
|
|
},
|
|
RayCast: function (callback, input) {
|
|
var p1 = input.p1;
|
|
var p2 = input.p2;
|
|
var r = b2Vec2.Subtract(p2, p1);
|
|
r.Normalize();
|
|
var v = b2Cross_f_v2(1, r);
|
|
var abs_v = b2Abs_v2(v);
|
|
var maxFraction = input.maxFraction;
|
|
var segmentAABB = new b2AABB();
|
|
var t = b2Vec2.Add(p1, b2Vec2.Multiply(maxFraction, b2Vec2.Subtract(p2, p1)));
|
|
segmentAABB.lowerBound.Assign(b2Min_v2(p1, t));
|
|
segmentAABB.upperBound.Assign(b2Max_v2(p1, t));
|
|
var stack = [];
|
|
stack.push(this.m_root);
|
|
while (stack.length > 0) {
|
|
var nodeId = stack.pop();
|
|
if (nodeId == b2_nullNode) {
|
|
continue
|
|
}
|
|
var node = this.m_nodes[nodeId];
|
|
if (b2TestOverlap(node.aabb, segmentAABB) == false) {
|
|
continue
|
|
}
|
|
var c = node.aabb.GetCenter();
|
|
var h = node.aabb.GetExtents();
|
|
var separation = b2Abs(b2Dot_v2_v2(v, b2Vec2.Subtract(p1, c))) - b2Dot_v2_v2(abs_v, h);
|
|
if (separation > 0) {
|
|
continue
|
|
}
|
|
if (node.IsLeaf()) {
|
|
var subInput = new b2RayCastInput();
|
|
subInput.p1.Assign(input.p1);
|
|
subInput.p2.Assign(input.p2);
|
|
subInput.maxFraction = maxFraction;
|
|
var value = callback.RayCastCallback(subInput, nodeId);
|
|
if (value == 0) {
|
|
return
|
|
}
|
|
if (value > 0) {
|
|
maxFraction = value;
|
|
var t = b2Vec2.Add(p1, b2Vec2.Multiply(maxFraction, b2Vec2.Subtract(p2, p1)));
|
|
segmentAABB.lowerBound.Assign(b2Min_v2(p1, t));
|
|
segmentAABB.upperBound.Assign(b2Max_v2(p1, t))
|
|
}
|
|
} else {
|
|
stack.push(node.child1);
|
|
stack.push(node.child2)
|
|
}
|
|
}
|
|
},
|
|
Validate: function () {
|
|
this.ValidateStructure(this.m_root);
|
|
this.ValidateMetrics(this.m_root);
|
|
var freeCount = 0;
|
|
var freeIndex = this.m_freeList;
|
|
while (freeIndex != b2_nullNode) {
|
|
freeIndex = this.m_nodes[freeIndex].parent;
|
|
++freeCount
|
|
}
|
|
},
|
|
GetHeight: function () {
|
|
if (this.m_root == b2_nullNode) {
|
|
return 0
|
|
}
|
|
return this.m_nodes[this.m_root].height
|
|
},
|
|
GetMaxBalance: function () {
|
|
var maxBalance = 0;
|
|
for (var i = 0; i < this.m_nodeCapacity; ++i) {
|
|
var node = this.m_nodes[i];
|
|
if (node.height <= 1) {
|
|
continue
|
|
}
|
|
var child1 = node.child1;
|
|
var child2 = node.child2;
|
|
var balance = b2Abs(this.m_nodes[child2].height - this.m_nodes[child1].height);
|
|
maxBalance = b2Max(maxBalance, balance)
|
|
}
|
|
return maxBalance
|
|
},
|
|
GetAreaRatio: function () {
|
|
if (this.m_root == b2_nullNode) {
|
|
return 0
|
|
}
|
|
var root = this.m_nodes[this.m_root];
|
|
var rootArea = root.aabb.GetPerimeter();
|
|
var totalArea = 0;
|
|
for (var i = 0; i < this.m_nodeCapacity; ++i) {
|
|
var node = this.m_nodes[i];
|
|
if (node.height < 0) {
|
|
continue
|
|
}
|
|
totalArea += node.aabb.GetPerimeter()
|
|
}
|
|
return totalArea / rootArea
|
|
},
|
|
RebuildBottomUp: function () {
|
|
var nodes = new Array(this.m_nodeCount);
|
|
var count = 0;
|
|
for (var i = 0; i < this.m_nodeCapacity; ++i) {
|
|
if (this.m_nodes[i].height < 0) {
|
|
continue
|
|
}
|
|
if (this.m_nodes[i].IsLeaf()) {
|
|
this.m_nodes[i].parent = b2_nullNode;
|
|
nodes[count] = i;
|
|
++count
|
|
} else {
|
|
this.FreeNode(i)
|
|
}
|
|
}
|
|
while (count > 1) {
|
|
var minCost = b2_maxFloat;
|
|
var iMin = -1,
|
|
jMin = -1;
|
|
for (i = 0; i < count; ++i) {
|
|
var aabbi = this.m_nodes[nodes[i]].aabb;
|
|
for (var j = i + 1; j < count; ++j) {
|
|
var aabbj = this.m_nodes[nodes[j]].aabb;
|
|
var b = new b2AABB();
|
|
b.Combine(aabbi, aabbj);
|
|
var cost = b.GetPerimeter();
|
|
if (cost < minCost) {
|
|
iMin = i;
|
|
jMin = j;
|
|
minCost = cost
|
|
}
|
|
}
|
|
}
|
|
var index1 = nodes[iMin];
|
|
var index2 = nodes[jMin];
|
|
var child1 = this.m_nodes[index1];
|
|
var child2 = this.m_nodes[index2];
|
|
var parentIndex = this.AllocateNode();
|
|
var parent = this.m_nodes[parentIndex];
|
|
parent.child1 = index1;
|
|
parent.child2 = index2;
|
|
parent.height = 1 + b2Max(child1.height, child2.height);
|
|
parent.aabb.Combine(child1.aabb, child2.aabb);
|
|
parent.parent = b2_nullNode;
|
|
child1.parent = parentIndex;
|
|
child2.parent = parentIndex;
|
|
nodes[jMin] = nodes[count - 1];
|
|
nodes[iMin] = parentIndex;
|
|
--count
|
|
}
|
|
this.m_root = nodes[0];
|
|
this.Validate()
|
|
},
|
|
ShiftOrigin: function (newOrigin) {
|
|
for (var i = 0; i < this.m_nodeCapacity; ++i) {
|
|
this.m_nodes[i].aabb.lowerBound.Subtract(newOrigin);
|
|
this.m_nodes[i].aabb.upperBound.Subtract(newOrigin)
|
|
}
|
|
},
|
|
AllocateNode: function () {
|
|
if (this.m_freeList == b2_nullNode) {
|
|
var oldNodes = this.m_nodes;
|
|
this.m_nodeCapacity *= 2;
|
|
this.m_nodes = oldNodes.concat(new Array(this.m_nodeCapacity - this.m_nodeCount));
|
|
for (var i = this.m_nodeCount; i < this.m_nodeCapacity - 1; ++i) {
|
|
this.m_nodes[i] = new b2TreeNode();
|
|
this.m_nodes[i].parent = i + 1;
|
|
this.m_nodes[i].height = -1
|
|
}
|
|
this.m_nodes[this.m_nodeCapacity - 1] = new b2TreeNode();
|
|
this.m_nodes[this.m_nodeCapacity - 1].parent = b2_nullNode;
|
|
this.m_nodes[this.m_nodeCapacity - 1].height = -1;
|
|
this.m_freeList = this.m_nodeCount
|
|
}
|
|
var nodeId = this.m_freeList;
|
|
this.m_freeList = this.m_nodes[nodeId].parent;
|
|
this.m_nodes[nodeId].parent = b2_nullNode;
|
|
this.m_nodes[nodeId].child1 = b2_nullNode;
|
|
this.m_nodes[nodeId].child2 = b2_nullNode;
|
|
this.m_nodes[nodeId].height = 0;
|
|
this.m_nodes[nodeId].userData = null;
|
|
++this.m_nodeCount;
|
|
return nodeId
|
|
},
|
|
FreeNode: function (nodeId) {
|
|
this.m_nodes[nodeId].parent = this.m_freeList;
|
|
this.m_nodes[nodeId].height = -1;
|
|
this.m_freeList = nodeId;
|
|
--this.m_nodeCount
|
|
},
|
|
InsertLeaf: function (leaf) {
|
|
++this.m_insertionCount;
|
|
if (this.m_root == b2_nullNode) {
|
|
this.m_root = leaf;
|
|
this.m_nodes[this.m_root].parent = b2_nullNode;
|
|
return
|
|
}
|
|
var leafAABB = this.m_nodes[leaf].aabb;
|
|
var index = this.m_root;
|
|
while (this.m_nodes[index].IsLeaf() == false) {
|
|
var child1 = this.m_nodes[index].child1;
|
|
var child2 = this.m_nodes[index].child2;
|
|
var area = this.m_nodes[index].aabb.GetPerimeter();
|
|
var combinedAABB = new b2AABB();
|
|
combinedAABB.Combine(this.m_nodes[index].aabb, leafAABB);
|
|
var combinedArea = combinedAABB.GetPerimeter();
|
|
var cost = 2 * combinedArea;
|
|
var inheritanceCost = 2 * (combinedArea - area);
|
|
var cost1;
|
|
var aabb;
|
|
if (this.m_nodes[child1].IsLeaf()) {
|
|
aabb = new b2AABB();
|
|
aabb.Combine(leafAABB, this.m_nodes[child1].aabb);
|
|
cost1 = aabb.GetPerimeter() + inheritanceCost
|
|
} else {
|
|
aabb = new b2AABB();
|
|
aabb.Combine(leafAABB, this.m_nodes[child1].aabb);
|
|
var oldArea = this.m_nodes[child1].aabb.GetPerimeter();
|
|
var newArea = aabb.GetPerimeter();
|
|
cost1 = (newArea - oldArea) + inheritanceCost
|
|
}
|
|
var cost2;
|
|
if (this.m_nodes[child2].IsLeaf()) {
|
|
aabb = new b2AABB();
|
|
aabb.Combine(leafAABB, this.m_nodes[child2].aabb);
|
|
cost2 = aabb.GetPerimeter() + inheritanceCost
|
|
} else {
|
|
aabb = new b2AABB();
|
|
aabb.Combine(leafAABB, this.m_nodes[child2].aabb);
|
|
var oldArea = this.m_nodes[child2].aabb.GetPerimeter();
|
|
var newArea = aabb.GetPerimeter();
|
|
cost2 = newArea - oldArea + inheritanceCost
|
|
}
|
|
if (cost < cost1 && cost < cost2) {
|
|
break
|
|
}
|
|
if (cost1 < cost2) {
|
|
index = child1
|
|
} else {
|
|
index = child2
|
|
}
|
|
}
|
|
var sibling = index;
|
|
var oldParent = this.m_nodes[sibling].parent;
|
|
var newParent = this.AllocateNode();
|
|
this.m_nodes[newParent].parent = oldParent;
|
|
this.m_nodes[newParent].userData = null;
|
|
this.m_nodes[newParent].aabb.Combine(leafAABB, this.m_nodes[sibling].aabb);
|
|
this.m_nodes[newParent].height = this.m_nodes[sibling].height + 1;
|
|
if (oldParent != b2_nullNode) {
|
|
if (this.m_nodes[oldParent].child1 == sibling) {
|
|
this.m_nodes[oldParent].child1 = newParent
|
|
} else {
|
|
this.m_nodes[oldParent].child2 = newParent
|
|
}
|
|
this.m_nodes[newParent].child1 = sibling;
|
|
this.m_nodes[newParent].child2 = leaf;
|
|
this.m_nodes[sibling].parent = newParent;
|
|
this.m_nodes[leaf].parent = newParent
|
|
} else {
|
|
this.m_nodes[newParent].child1 = sibling;
|
|
this.m_nodes[newParent].child2 = leaf;
|
|
this.m_nodes[sibling].parent = newParent;
|
|
this.m_nodes[leaf].parent = newParent;
|
|
this.m_root = newParent
|
|
}
|
|
index = this.m_nodes[leaf].parent;
|
|
while (index != b2_nullNode) {
|
|
index = this.Balance(index);
|
|
var child1 = this.m_nodes[index].child1;
|
|
var child2 = this.m_nodes[index].child2;
|
|
this.m_nodes[index].height = 1 + b2Max(this.m_nodes[child1].height, this.m_nodes[child2].height);
|
|
this.m_nodes[index].aabb.Combine(this.m_nodes[child1].aabb, this.m_nodes[child2].aabb);
|
|
index = this.m_nodes[index].parent
|
|
}
|
|
},
|
|
RemoveLeaf: function (leaf) {
|
|
if (leaf == this.m_root) {
|
|
this.m_root = b2_nullNode;
|
|
return
|
|
}
|
|
var parent = this.m_nodes[leaf].parent;
|
|
var grandParent = this.m_nodes[parent].parent;
|
|
var sibling;
|
|
if (this.m_nodes[parent].child1 == leaf) {
|
|
sibling = this.m_nodes[parent].child2
|
|
} else {
|
|
sibling = this.m_nodes[parent].child1
|
|
}
|
|
if (grandParent != b2_nullNode) {
|
|
if (this.m_nodes[grandParent].child1 == parent) {
|
|
this.m_nodes[grandParent].child1 = sibling
|
|
} else {
|
|
this.m_nodes[grandParent].child2 = sibling
|
|
}
|
|
this.m_nodes[sibling].parent = grandParent;
|
|
this.FreeNode(parent);
|
|
var index = grandParent;
|
|
while (index != b2_nullNode) {
|
|
index = this.Balance(index);
|
|
var child1 = this.m_nodes[index].child1;
|
|
var child2 = this.m_nodes[index].child2;
|
|
this.m_nodes[index].aabb.Combine(this.m_nodes[child1].aabb, this.m_nodes[child2].aabb);
|
|
this.m_nodes[index].height = 1 + b2Max(this.m_nodes[child1].height, this.m_nodes[child2].height);
|
|
index = this.m_nodes[index].parent
|
|
}
|
|
} else {
|
|
this.m_root = sibling;
|
|
this.m_nodes[sibling].parent = b2_nullNode;
|
|
this.FreeNode(parent)
|
|
}
|
|
},
|
|
Balance: function (iA) {
|
|
var A = this.m_nodes[iA];
|
|
if (A.IsLeaf() || A.height < 2) {
|
|
return iA
|
|
}
|
|
var iB = A.child1;
|
|
var iC = A.child2;
|
|
var B = this.m_nodes[iB];
|
|
var C = this.m_nodes[iC];
|
|
var balance = C.height - B.height;
|
|
if (balance > 1) {
|
|
var iF = C.child1;
|
|
var iG = C.child2;
|
|
var F = this.m_nodes[iF];
|
|
var G = this.m_nodes[iG];
|
|
C.child1 = iA;
|
|
C.parent = A.parent;
|
|
A.parent = iC;
|
|
if (C.parent != b2_nullNode) {
|
|
if (this.m_nodes[C.parent].child1 == iA) {
|
|
this.m_nodes[C.parent].child1 = iC
|
|
} else {
|
|
this.m_nodes[C.parent].child2 = iC
|
|
}
|
|
} else {
|
|
this.m_root = iC
|
|
}
|
|
if (F.height > G.height) {
|
|
C.child2 = iF;
|
|
A.child2 = iG;
|
|
G.parent = iA;
|
|
A.aabb.Combine(B.aabb, G.aabb);
|
|
C.aabb.Combine(A.aabb, F.aabb);
|
|
A.height = 1 + b2Max(B.height, G.height);
|
|
C.height = 1 + b2Max(A.height, F.height)
|
|
} else {
|
|
C.child2 = iG;
|
|
A.child2 = iF;
|
|
F.parent = iA;
|
|
A.aabb.Combine(B.aabb, F.aabb);
|
|
C.aabb.Combine(A.aabb, G.aabb);
|
|
A.height = 1 + b2Max(B.height, F.height);
|
|
C.height = 1 + b2Max(A.height, G.height)
|
|
}
|
|
return iC
|
|
}
|
|
if (balance < -1) {
|
|
var iD = B.child1;
|
|
var iE = B.child2;
|
|
var D = this.m_nodes[iD];
|
|
var E = this.m_nodes[iE];
|
|
B.child1 = iA;
|
|
B.parent = A.parent;
|
|
A.parent = iB;
|
|
if (B.parent != b2_nullNode) {
|
|
if (this.m_nodes[B.parent].child1 == iA) {
|
|
this.m_nodes[B.parent].child1 = iB
|
|
} else {
|
|
this.m_nodes[B.parent].child2 = iB
|
|
}
|
|
} else {
|
|
this.m_root = iB
|
|
}
|
|
if (D.height > E.height) {
|
|
B.child2 = iD;
|
|
A.child1 = iE;
|
|
E.parent = iA;
|
|
A.aabb.Combine(C.aabb, E.aabb);
|
|
B.aabb.Combine(A.aabb, D.aabb);
|
|
A.height = 1 + b2Max(C.height, E.height);
|
|
B.height = 1 + b2Max(A.height, D.height)
|
|
} else {
|
|
B.child2 = iE;
|
|
A.child1 = iD;
|
|
D.parent = iA;
|
|
A.aabb.Combine(C.aabb, D.aabb);
|
|
B.aabb.Combine(A.aabb, E.aabb);
|
|
A.height = 1 + b2Max(C.height, D.height);
|
|
B.height = 1 + b2Max(A.height, E.height)
|
|
}
|
|
return iB
|
|
}
|
|
return iA
|
|
},
|
|
ComputeHeight: function (nodeId) {
|
|
if (typeof (nodeId) === "undefined") {
|
|
nodeId = this.m_root
|
|
}
|
|
var node = this.m_nodes[nodeId];
|
|
if (node.IsLeaf()) {
|
|
return 0
|
|
}
|
|
var height1 = this.ComputeHeight(node.child1);
|
|
var height2 = this.ComputeHeight(node.child2);
|
|
return 1 + b2Max(height1, height2)
|
|
},
|
|
ValidateStructure: function (index) {
|
|
if (index == b2_nullNode) {
|
|
return
|
|
}
|
|
var node = this.m_nodes[index];
|
|
var child1 = node.child1;
|
|
var child2 = node.child2;
|
|
if (node.IsLeaf()) {
|
|
return
|
|
}
|
|
this.ValidateStructure(child1);
|
|
this.ValidateStructure(child2)
|
|
},
|
|
ValidateMetrics: function (index) {
|
|
if (index == b2_nullNode) {
|
|
return
|
|
}
|
|
var node = this.m_nodes[index];
|
|
var child1 = node.child1;
|
|
var child2 = node.child2;
|
|
if (node.IsLeaf()) {
|
|
return
|
|
}
|
|
var height1 = this.m_nodes[child1].height;
|
|
var height2 = this.m_nodes[child2].height;
|
|
var height;
|
|
height = 1 + b2Max(height1, height2);
|
|
var aabb = new b2AABB();
|
|
aabb.Combine(this.m_nodes[child1].aabb, this.m_nodes[child2].aabb);
|
|
this.ValidateMetrics(child1);
|
|
this.ValidateMetrics(child2)
|
|
}
|
|
};
|
|
"use strict";
|
|
|
|
function b2TOIInput() {
|
|
this.proxyA = new b2DistanceProxy();
|
|
this.proxyB = new b2DistanceProxy();
|
|
this.sweepA = new b2Sweep();
|
|
this.sweepB = new b2Sweep();
|
|
this.tMax = 0
|
|
}
|
|
|
|
function b2TOIOutput() {
|
|
this.state = 0;
|
|
this.t = 0
|
|
}
|
|
b2TOIOutput.e_unknown = 0;
|
|
b2TOIOutput.e_failed = 1;
|
|
b2TOIOutput.e_overlapped = 2;
|
|
b2TOIOutput.e_touching = 3;
|
|
b2TOIOutput.e_separated = 4;
|
|
|
|
function b2SeparationFunction() {
|
|
this.m_proxyA = null;
|
|
this.m_proxyB = null;
|
|
this.m_sweepA = null;
|
|
this.m_sweepB = null;
|
|
this.m_type = 0;
|
|
this.m_localPoint = new b2Vec2();
|
|
this.m_axis = new b2Vec2()
|
|
}
|
|
var _local_xfA = new b2Transform();
|
|
var _local_xfB = new b2Transform();
|
|
b2SeparationFunction.prototype = {
|
|
Initialize: function (cache, proxyA, sweepA, proxyB, sweepB, t1) {
|
|
this.m_proxyA = proxyA;
|
|
this.m_proxyB = proxyB;
|
|
var count = cache.count;
|
|
this.m_sweepA = sweepA;
|
|
this.m_sweepB = sweepB;
|
|
this.m_sweepA.GetTransform(_local_xfA, t1);
|
|
this.m_sweepB.GetTransform(_local_xfB, t1);
|
|
if (count == 1) {
|
|
this.m_type = b2SeparationFunction.e_points;
|
|
var localPointA = this.m_proxyA.GetVertex(cache.indexA[0]);
|
|
var localPointB = this.m_proxyB.GetVertex(cache.indexB[0]);
|
|
var pointAx = (_local_xfA.q.c * localPointA.x - _local_xfA.q.s * localPointA.y) + _local_xfA.p.x;
|
|
var pointAy = (_local_xfA.q.s * localPointA.x + _local_xfA.q.c * localPointA.y) + _local_xfA.p.y;
|
|
var pointBx = (_local_xfB.q.c * localPointB.x - _local_xfB.q.s * localPointB.y) + _local_xfB.p.x;
|
|
var pointBy = (_local_xfB.q.s * localPointB.x + _local_xfB.q.c * localPointB.y) + _local_xfB.p.y;
|
|
this.m_axis.x = pointBx - pointAx;
|
|
this.m_axis.y = pointBy - pointAy;
|
|
var s = this.m_axis.Normalize();
|
|
return s
|
|
} else {
|
|
if (cache.indexA[0] == cache.indexA[1]) {
|
|
this.m_type = b2SeparationFunction.e_faceB;
|
|
var localPointB1 = proxyB.GetVertex(cache.indexB[0]);
|
|
var localPointB2 = proxyB.GetVertex(cache.indexB[1]);
|
|
this.m_axis.x = 1 * (localPointB2.y - localPointB1.y);
|
|
this.m_axis.y = -1 * (localPointB2.x - localPointB1.x);
|
|
this.m_axis.Normalize();
|
|
var normalx = _local_xfB.q.c * this.m_axis.x - _local_xfB.q.s * this.m_axis.y;
|
|
var normaly = _local_xfB.q.s * this.m_axis.x + _local_xfB.q.c * this.m_axis.y;
|
|
this.m_localPoint.x = 0.5 * (localPointB1.x + localPointB2.x);
|
|
this.m_localPoint.y = 0.5 * (localPointB1.y + localPointB2.y);
|
|
var pointBx = (_local_xfB.q.c * this.m_localPoint.x - _local_xfB.q.s * this.m_localPoint.y) + _local_xfB.p.x;
|
|
var pointBy = (_local_xfB.q.s * this.m_localPoint.x + _local_xfB.q.c * this.m_localPoint.y) + _local_xfB.p.y;
|
|
var localPointA = proxyA.GetVertex(cache.indexA[0]);
|
|
var pointAx = (_local_xfA.q.c * localPointA.x - _local_xfA.q.s * localPointA.y) + _local_xfA.p.x;
|
|
var pointAy = (_local_xfA.q.s * localPointA.x + _local_xfA.q.c * localPointA.y) + _local_xfA.p.y;
|
|
var s = (pointAx - pointBx) * normalx + (pointAy - pointBy) * normaly;
|
|
if (s < 0) {
|
|
this.m_axis.x = -this.m_axis.x;
|
|
this.m_axis.y = -this.m_axis.y;
|
|
s = -s
|
|
}
|
|
return s
|
|
} else {
|
|
this.m_type = b2SeparationFunction.e_faceA;
|
|
var localPointA1 = this.m_proxyA.GetVertex(cache.indexA[0]);
|
|
var localPointA2 = this.m_proxyA.GetVertex(cache.indexA[1]);
|
|
this.m_axis.x = 1 * (localPointA2.y - localPointA1.y);
|
|
this.m_axis.y = -1 * (localPointA2.x - localPointA1.x);
|
|
this.m_axis.Normalize();
|
|
var normalx = _local_xfA.q.c * this.m_axis.x - _local_xfA.q.s * this.m_axis.y;
|
|
var normaly = _local_xfA.q.s * this.m_axis.x + _local_xfA.q.c * this.m_axis.y;
|
|
this.m_localPoint.x = 0.5 * (localPointA1.x + localPointA2.x);
|
|
this.m_localPoint.y = 0.5 * (localPointA1.y + localPointA2.y);
|
|
var pointAx = (_local_xfA.q.c * this.m_localPoint.x - _local_xfA.q.s * this.m_localPoint.y) + _local_xfA.p.x;
|
|
var pointAy = (_local_xfA.q.s * this.m_localPoint.x + _local_xfA.q.c * this.m_localPoint.y) + _local_xfA.p.y;
|
|
var localPointB = this.m_proxyB.GetVertex(cache.indexB[0]);
|
|
var pointBx = (_local_xfB.q.c * localPointB.x - _local_xfB.q.s * localPointB.y) + _local_xfB.p.x;
|
|
var pointBy = (_local_xfB.q.s * localPointB.x + _local_xfB.q.c * localPointB.y) + _local_xfB.p.y;
|
|
var s = (pointBx - pointAx) * normalx + (pointBy - pointAy) * normaly;
|
|
if (s < 0) {
|
|
this.m_axis.x = -this.m_axis.x;
|
|
this.m_axis.y = -this.m_axis.y;
|
|
s = -s
|
|
}
|
|
return s
|
|
}
|
|
}
|
|
},
|
|
FindMinSeparation: function (indices, t) {
|
|
this.m_sweepA.GetTransform(_local_xfA, t);
|
|
this.m_sweepB.GetTransform(_local_xfB, t);
|
|
switch (this.m_type) {
|
|
case b2SeparationFunction.e_points:
|
|
var axisAx = _local_xfA.q.c * this.m_axis.x + _local_xfA.q.s * this.m_axis.y;
|
|
var axisAy = -_local_xfA.q.s * this.m_axis.x + _local_xfA.q.c * this.m_axis.y;
|
|
var axisBx = _local_xfB.q.c * -this.m_axis.x + _local_xfB.q.s * -this.m_axis.y;
|
|
var axisBy = -_local_xfB.q.s * -this.m_axis.x + _local_xfB.q.c * -this.m_axis.y;
|
|
indices[0] = this.m_proxyA.GetSupport(axisAx, axisAy);
|
|
indices[1] = this.m_proxyB.GetSupport(axisBx, axisBy);
|
|
var localPointA = this.m_proxyA.GetVertex(indices[0]);
|
|
var localPointB = this.m_proxyB.GetVertex(indices[1]);
|
|
var pointAx = (_local_xfA.q.c * localPointA.x - _local_xfA.q.s * localPointA.y) + _local_xfA.p.x;
|
|
var pointAy = (_local_xfA.q.s * localPointA.x + _local_xfA.q.c * localPointA.y) + _local_xfA.p.y;
|
|
var pointBx = (_local_xfB.q.c * localPointB.x - _local_xfB.q.s * localPointB.y) + _local_xfB.p.x;
|
|
var pointBy = (_local_xfB.q.s * localPointB.x + _local_xfB.q.c * localPointB.y) + _local_xfB.p.y;
|
|
return (pointBx - pointAx) * this.m_axis.x + (pointBy - pointAy) * this.m_axis.y;
|
|
case b2SeparationFunction.e_faceA:
|
|
var normalx = _local_xfA.q.c * this.m_axis.x - _local_xfA.q.s * this.m_axis.y;
|
|
var normaly = _local_xfA.q.s * this.m_axis.x + _local_xfA.q.c * this.m_axis.y;
|
|
var pointAx = (_local_xfA.q.c * this.m_localPoint.x - _local_xfA.q.s * this.m_localPoint.y) + _local_xfA.p.x;
|
|
var pointAy = (_local_xfA.q.s * this.m_localPoint.x + _local_xfA.q.c * this.m_localPoint.y) + _local_xfA.p.y;
|
|
var axisBx = _local_xfB.q.c * -normalx + _local_xfB.q.s * -normaly;
|
|
var axisBy = -_local_xfB.q.s * -normalx + _local_xfB.q.c * -normaly;
|
|
indices[0] = -1;
|
|
indices[1] = this.m_proxyB.GetSupport(axisBx, axisBy);
|
|
var localPointB = this.m_proxyB.GetVertex(indices[1]);
|
|
var pointBx = (_local_xfB.q.c * localPointB.x - _local_xfB.q.s * localPointB.y) + _local_xfB.p.x;
|
|
var pointBy = (_local_xfB.q.s * localPointB.x + _local_xfB.q.c * localPointB.y) + _local_xfB.p.y;
|
|
return (pointBx - pointAx) * normalx + (pointBy - pointAy) * normaly;
|
|
case b2SeparationFunction.e_faceB:
|
|
var normalx = _local_xfB.q.c * this.m_axis.x - _local_xfB.q.s * this.m_axis.y;
|
|
var normaly = _local_xfB.q.s * this.m_axis.x + _local_xfB.q.c * this.m_axis.y;
|
|
var pointBx = (_local_xfB.q.c * this.m_localPoint.x - _local_xfB.q.s * this.m_localPoint.y) + _local_xfB.p.x;
|
|
var pointBy = (_local_xfB.q.s * this.m_localPoint.x + _local_xfB.q.c * this.m_localPoint.y) + _local_xfB.p.y;
|
|
var axisAx = _local_xfA.q.c * -normalx + _local_xfA.q.s * -normaly;
|
|
var axisBy = -_local_xfA.q.s * -normalx + _local_xfA.q.c * -normaly;
|
|
indices[1] = -1;
|
|
indices[0] = this.m_proxyA.GetSupport(axisAx, axisBy);
|
|
var localPointA = this.m_proxyA.GetVertex(indices[0]);
|
|
var pointAx = (_local_xfA.q.c * localPointA.x - _local_xfA.q.s * localPointA.y) + _local_xfA.p.x;
|
|
var pointAy = (_local_xfA.q.s * localPointA.x + _local_xfA.q.c * localPointA.y) + _local_xfA.p.y;
|
|
return (pointAx - pointBx) * normalx + (pointAy - pointBy) * normaly
|
|
}
|
|
},
|
|
Evaluate: function (indexA, indexB, t) {
|
|
this.m_sweepA.GetTransform(_local_xfA, t);
|
|
this.m_sweepB.GetTransform(_local_xfB, t);
|
|
switch (this.m_type) {
|
|
case b2SeparationFunction.e_points:
|
|
var localPointA = this.m_proxyA.GetVertex(indexA);
|
|
var localPointB = this.m_proxyB.GetVertex(indexB);
|
|
var pointAx = (_local_xfA.q.c * localPointA.x - _local_xfA.q.s * localPointA.y) + _local_xfA.p.x;
|
|
var pointAy = (_local_xfA.q.s * localPointA.x + _local_xfA.q.c * localPointA.y) + _local_xfA.p.y;
|
|
var pointBx = (_local_xfB.q.c * localPointB.x - _local_xfB.q.s * localPointB.y) + _local_xfB.p.x;
|
|
var pointBy = (_local_xfB.q.s * localPointB.x + _local_xfB.q.c * localPointB.y) + _local_xfB.p.y;
|
|
var separation = (pointBx - pointAx) * this.m_axis.x + (pointBy - pointAy) * this.m_axis.y;
|
|
return separation;
|
|
case b2SeparationFunction.e_faceA:
|
|
var normalx = _local_xfA.q.c * this.m_axis.x - _local_xfA.q.s * this.m_axis.y;
|
|
var normaly = _local_xfA.q.s * this.m_axis.x + _local_xfA.q.c * this.m_axis.y;
|
|
var pointAx = (_local_xfA.q.c * this.m_localPoint.x - _local_xfA.q.s * this.m_localPoint.y) + _local_xfA.p.x;
|
|
var pointAy = (_local_xfA.q.s * this.m_localPoint.x + _local_xfA.q.c * this.m_localPoint.y) + _local_xfA.p.y;
|
|
var localPointB = this.m_proxyB.GetVertex(indexB);
|
|
var pointBx = (_local_xfB.q.c * localPointB.x - _local_xfB.q.s * localPointB.y) + _local_xfB.p.x;
|
|
var pointBy = (_local_xfB.q.s * localPointB.x + _local_xfB.q.c * localPointB.y) + _local_xfB.p.y;
|
|
var separation = (pointBx - pointAx) * normalx + (pointBy - pointAy) * normaly;
|
|
return separation;
|
|
case b2SeparationFunction.e_faceB:
|
|
var normalx = _local_xfB.q.c * this.m_axis.x - _local_xfB.q.s * this.m_axis.y;
|
|
var normaly = _local_xfB.q.s * this.m_axis.x + _local_xfB.q.c * this.m_axis.y;
|
|
var pointBx = (_local_xfB.q.c * this.m_localPoint.x - _local_xfB.q.s * this.m_localPoint.y) + _local_xfB.p.x;
|
|
var pointBy = (_local_xfB.q.s * this.m_localPoint.x + _local_xfB.q.c * this.m_localPoint.y) + _local_xfB.p.y;
|
|
var localPointA = this.m_proxyA.GetVertex(indexA);
|
|
var pointAx = (_local_xfA.q.c * localPointA.x - _local_xfA.q.s * localPointA.y) + _local_xfA.p.x;
|
|
var pointAy = (_local_xfA.q.s * localPointA.x + _local_xfA.q.c * localPointA.y) + _local_xfA.p.y;
|
|
var separation = (pointAx - pointBx) * normalx + (pointAy - pointBy) * normaly;
|
|
return separation
|
|
}
|
|
}
|
|
};
|
|
b2SeparationFunction.e_points = 0;
|
|
b2SeparationFunction.e_faceA = 1;
|
|
b2SeparationFunction.e_faceB = 2;
|
|
var profile_toi = b2Profiler.create("toi", "solveTOI");
|
|
|
|
function b2TimeOfImpact(output, input) {
|
|
profile_toi.start();
|
|
++b2TimeOfImpact.b2_toiCalls;
|
|
output.state = b2TOIOutput.e_unknown;
|
|
output.t = input.tMax;
|
|
var proxyA = input.proxyA;
|
|
var proxyB = input.proxyB;
|
|
b2TimeOfImpact._temp_sweepA.Assign(input.sweepA);
|
|
b2TimeOfImpact._temp_sweepB.Assign(input.sweepB);
|
|
b2TimeOfImpact._temp_sweepA.Normalize();
|
|
b2TimeOfImpact._temp_sweepB.Normalize();
|
|
var tMax = input.tMax;
|
|
var totalRadius = proxyA.m_radius + proxyB.m_radius;
|
|
var target = b2Max(b2_linearSlop, totalRadius - 3 * b2_linearSlop);
|
|
var tolerance = 0.25 * b2_linearSlop;
|
|
var t1 = 0;
|
|
var k_maxIterations = 20;
|
|
var iter = 0;
|
|
var cache = new b2SimplexCache();
|
|
cache.count = 0;
|
|
var distanceInput = new b2DistanceInput();
|
|
distanceInput.proxyA.Assign(input.proxyA);
|
|
distanceInput.proxyB.Assign(input.proxyB);
|
|
distanceInput.useRadii = false;
|
|
for (;;) {
|
|
b2TimeOfImpact._temp_sweepA.GetTransform(distanceInput.transformA, t1);
|
|
b2TimeOfImpact._temp_sweepB.GetTransform(distanceInput.transformB, t1);
|
|
var distanceOutput = new b2DistanceOutput();
|
|
b2DistanceFunc(distanceOutput, cache, distanceInput);
|
|
if (distanceOutput.distance <= 0) {
|
|
output.state = b2TOIOutput.e_overlapped;
|
|
output.t = 0;
|
|
break
|
|
}
|
|
if (distanceOutput.distance < target + tolerance) {
|
|
output.state = b2TOIOutput.e_touching;
|
|
output.t = t1;
|
|
break
|
|
}
|
|
var fcn = new b2SeparationFunction();
|
|
fcn.Initialize(cache, proxyA, b2TimeOfImpact._temp_sweepA, proxyB, b2TimeOfImpact._temp_sweepB, t1);
|
|
var done = false;
|
|
var t2 = tMax;
|
|
var pushBackIter = 0;
|
|
for (;;) {
|
|
var indices = [];
|
|
var s2 = fcn.FindMinSeparation(indices, t2);
|
|
if (s2 > target + tolerance) {
|
|
output.state = b2TOIOutput.e_separated;
|
|
output.t = tMax;
|
|
done = true;
|
|
break
|
|
}
|
|
if (s2 > target - tolerance) {
|
|
t1 = t2;
|
|
break
|
|
}
|
|
var s1 = fcn.Evaluate(indices[0], indices[1], t1);
|
|
if (s1 < target - tolerance) {
|
|
output.state = b2TOIOutput.e_failed;
|
|
output.t = t1;
|
|
done = true;
|
|
break
|
|
}
|
|
if (s1 <= target + tolerance) {
|
|
output.state = b2TOIOutput.e_touching;
|
|
output.t = t1;
|
|
done = true;
|
|
break
|
|
}
|
|
var rootIterCount = 0;
|
|
var a1 = t1,
|
|
a2 = t2;
|
|
for (;;) {
|
|
var t;
|
|
if (rootIterCount & 1) {
|
|
t = a1 + (target - s1) * (a2 - a1) / (s2 - s1)
|
|
} else {
|
|
t = 0.5 * (a1 + a2)
|
|
}++rootIterCount;
|
|
++b2TimeOfImpact.b2_toiRootIters;
|
|
var s = fcn.Evaluate(indices[0], indices[1], t);
|
|
if (b2Abs(s - target) < tolerance) {
|
|
t2 = t;
|
|
break
|
|
}
|
|
if (s > target) {
|
|
a1 = t;
|
|
s1 = s
|
|
} else {
|
|
a2 = t;
|
|
s2 = s
|
|
}
|
|
if (rootIterCount == 50) {
|
|
break
|
|
}
|
|
}
|
|
b2TimeOfImpact.b2_toiMaxRootIters = b2Max(b2TimeOfImpact.b2_toiMaxRootIters, rootIterCount);
|
|
++pushBackIter;
|
|
if (pushBackIter == b2_maxPolygonVertices) {
|
|
break
|
|
}
|
|
}++iter;
|
|
++b2TimeOfImpact.b2_toiIters;
|
|
if (done) {
|
|
break
|
|
}
|
|
if (iter == k_maxIterations) {
|
|
output.state = b2TOIOutput.e_failed;
|
|
output.t = t1;
|
|
break
|
|
}
|
|
}
|
|
b2TimeOfImpact.b2_toiMaxIters = b2Max(b2TimeOfImpact.b2_toiMaxIters, iter);
|
|
profile_toi.stop();
|
|
b2TimeOfImpact.b2_toiMaxTime = b2Max(b2TimeOfImpact.b2_toiMaxTime, profile_toi.elapsedTime);
|
|
b2TimeOfImpact.b2_toiTime += profile_toi.elapsedTime
|
|
}
|
|
b2TimeOfImpact._temp_sweepA = new b2Sweep();
|
|
b2TimeOfImpact._temp_sweepB = new b2Sweep();
|
|
b2TimeOfImpact.b2_toiTime = 0;
|
|
b2TimeOfImpact.b2_toiMaxTime = 0;
|
|
b2TimeOfImpact.b2_toiCalls = 0;
|
|
b2TimeOfImpact.b2_toiIters = 0;
|
|
b2TimeOfImpact.b2_toiMaxIters = 0;
|
|
b2TimeOfImpact.b2_toiRootIters = 0;
|
|
b2TimeOfImpact.b2_toiMaxRootIters = 0;
|
|
"use strict";
|
|
|
|
function b2BodyDef() {
|
|
this.type = b2Body.b2_staticBody;
|
|
this.position = new b2Vec2(0, 0);
|
|
this.angle = 0;
|
|
this.linearVelocity = new b2Vec2(0, 0);
|
|
this.angularVelocity = 0;
|
|
this.linearDamping = 0;
|
|
this.angularDamping = 0;
|
|
this.allowSleep = true;
|
|
this.awake = true;
|
|
this.fixedRotation = false;
|
|
this.bullet = false;
|
|
this.active = true;
|
|
this.userData = null;
|
|
this.gravityScale = 1;
|
|
Object.seal(this)
|
|
}
|
|
b2BodyDef.prototype = {
|
|
_deserialize: function (data) {
|
|
this.type = data.type;
|
|
this.position._deserialize(data.position);
|
|
this.angle = data.angle;
|
|
this.linearVelocity._deserialize(data.linearVelocity);
|
|
this.angularVelocity = data.angularVelocity;
|
|
this.linearDamping = data.linearDamping;
|
|
this.angularDamping = data.angularDamping;
|
|
this.allowSleep = data.allowSleep;
|
|
this.awake = data.awake;
|
|
this.fixedRotation = data.fixedRotation;
|
|
this.bullet = data.bullet;
|
|
this.active = data.active;
|
|
this.gravityScale = data.gravityScale
|
|
}
|
|
};
|
|
|
|
function b2Body(bd, world) {
|
|
this.m_islandIndex = 0;
|
|
this.m_flags = 0;
|
|
if (bd.bullet) {
|
|
this.m_flags |= b2Body.e_bulletFlag
|
|
}
|
|
if (bd.fixedRotation) {
|
|
this.m_flags |= b2Body.e_fixedRotationFlag
|
|
}
|
|
if (bd.allowSleep) {
|
|
this.m_flags |= b2Body.e_autoSleepFlag
|
|
}
|
|
if (bd.awake) {
|
|
this.m_flags |= b2Body.e_awakeFlag
|
|
}
|
|
if (bd.active) {
|
|
this.m_flags |= b2Body.e_activeFlag
|
|
}
|
|
this.m_world = world;
|
|
this.m_xf = new b2Transform();
|
|
this.m_xf.p.Assign(bd.position);
|
|
this.m_xf.q.Set(bd.angle);
|
|
this.m_sweep = new b2Sweep();
|
|
this.m_sweep.localCenter.SetZero();
|
|
this.m_sweep.c0.Assign(this.m_xf.p);
|
|
this.m_sweep.c.Assign(this.m_xf.p);
|
|
this.m_sweep.a0 = bd.angle;
|
|
this.m_sweep.a = bd.angle;
|
|
this.m_sweep.alpha0 = 0;
|
|
this.m_jointList = null;
|
|
this.m_contactList = null;
|
|
this.m_prev = null;
|
|
this.m_next = null;
|
|
this.m_linearVelocity = bd.linearVelocity.Clone();
|
|
this.m_angularVelocity = bd.angularVelocity;
|
|
this.m_linearDamping = bd.linearDamping;
|
|
this.m_angularDamping = bd.angularDamping;
|
|
this.m_gravityScale = bd.gravityScale;
|
|
this.m_force = new b2Vec2();
|
|
this.m_torque = 0;
|
|
this.m_sleepTime = 0;
|
|
this.m_type = bd.type;
|
|
if (this.m_type == b2Body.b2_dynamicBody) {
|
|
this.m_mass = 1;
|
|
this.m_invMass = 1
|
|
} else {
|
|
this.m_mass = 0;
|
|
this.m_invMass = 0
|
|
}
|
|
this.m_I = 0;
|
|
this.m_invI = 0;
|
|
this.m_userData = bd.userData;
|
|
this.m_fixtureList = null;
|
|
this.m_fixtureCount = 0
|
|
}
|
|
b2Body.b2_staticBody = 0;
|
|
b2Body.b2_kinematicBody = 1;
|
|
b2Body.b2_dynamicBody = 2;
|
|
b2Body.e_islandFlag = 1;
|
|
b2Body.e_awakeFlag = 2;
|
|
b2Body.e_autoSleepFlag = 4;
|
|
b2Body.e_bulletFlag = 8;
|
|
b2Body.e_fixedRotationFlag = 16;
|
|
b2Body.e_activeFlag = 32;
|
|
b2Body.e_toiFlag = 64;
|
|
b2Body.m_local_oldCenter = new b2Vec2();
|
|
b2Body.m_local_xf1 = new b2Transform();
|
|
b2Body.prototype = {
|
|
CreateFixture: function (def, density) {
|
|
if (typeof (density) !== "undefined") {
|
|
var ndef = new b2FixtureDef();
|
|
ndef.shape = def;
|
|
ndef.density = density;
|
|
return this.CreateFixture(ndef)
|
|
}
|
|
if (this.m_world.IsLocked() == true) {
|
|
return null
|
|
}
|
|
var fixture = new b2Fixture();
|
|
fixture.Create(this, def);
|
|
if (this.m_flags & b2Body.e_activeFlag) {
|
|
var broadPhase = this.m_world.m_contactManager.m_broadPhase;
|
|
fixture.CreateProxies(broadPhase, this.m_xf)
|
|
}
|
|
fixture.m_next = this.m_fixtureList;
|
|
this.m_fixtureList = fixture;
|
|
++this.m_fixtureCount;
|
|
fixture.m_body = this;
|
|
if (fixture.m_density > 0) {
|
|
this.ResetMassData()
|
|
}
|
|
this.m_world.m_flags |= b2World.e_newFixture;
|
|
return fixture
|
|
},
|
|
DestroyFixture: function (fixture) {
|
|
if (this.m_world.IsLocked() == true) {
|
|
return
|
|
}
|
|
var node = this.m_fixtureList;
|
|
var found = false;
|
|
while (node != null) {
|
|
if (node == fixture) {
|
|
this.m_fixtureList = node = fixture.m_next;
|
|
found = true;
|
|
break
|
|
}
|
|
node = node.m_next
|
|
}
|
|
var edge = this.m_contactList;
|
|
while (edge) {
|
|
var c = edge.contact;
|
|
edge = edge.next;
|
|
var fixtureA = c.GetFixtureA();
|
|
var fixtureB = c.GetFixtureB();
|
|
if (fixture == fixtureA || fixture == fixtureB) {
|
|
this.m_world.m_contactManager.Destroy(c)
|
|
}
|
|
}
|
|
if (this.m_flags & b2Body.e_activeFlag) {
|
|
var broadPhase = this.m_world.m_contactManager.m_broadPhase;
|
|
fixture.DestroyProxies(broadPhase)
|
|
}
|
|
fixture.Destroy();
|
|
fixture.m_body = null;
|
|
fixture.m_next = null;
|
|
--this.m_fixtureCount;
|
|
this.ResetMassData()
|
|
},
|
|
SetTransform: function (position, angle) {
|
|
if (this.m_world.IsLocked() == true) {
|
|
return
|
|
}
|
|
this.m_xf.q.Set(angle);
|
|
this.m_xf.p.Assign(position);
|
|
this.m_sweep.c.Assign(b2Mul_t_v2(this.m_xf, this.m_sweep.localCenter));
|
|
this.m_sweep.a = angle;
|
|
this.m_sweep.c0.Assign(this.m_sweep.c);
|
|
this.m_sweep.a0 = angle;
|
|
var broadPhase = this.m_world.m_contactManager.m_broadPhase;
|
|
for (var f = this.m_fixtureList; f; f = f.m_next) {
|
|
f.Synchronize(broadPhase, this.m_xf, this.m_xf)
|
|
}
|
|
},
|
|
GetTransform: function () {
|
|
return this.m_xf
|
|
},
|
|
GetPosition: function () {
|
|
return this.m_xf.p
|
|
},
|
|
GetAngle: function () {
|
|
return this.m_sweep.a
|
|
},
|
|
GetWorldCenter: function () {
|
|
return this.m_sweep.c
|
|
},
|
|
GetLocalCenter: function () {
|
|
return this.m_sweep.localCenter
|
|
},
|
|
SetLinearVelocity: function (v) {
|
|
if (this.m_type == b2Body.b2_staticBody) {
|
|
return
|
|
}
|
|
if (b2Dot_v2_v2(v, v) > 0) {
|
|
this.SetAwake(true)
|
|
}
|
|
this.m_linearVelocity = v
|
|
},
|
|
GetLinearVelocity: function () {
|
|
return this.m_linearVelocity
|
|
},
|
|
SetAngularVelocity: function (w) {
|
|
if (this.m_type == b2Body.b2_staticBody) {
|
|
return
|
|
}
|
|
if (w * w > 0) {
|
|
this.SetAwake(true)
|
|
}
|
|
this.m_angularVelocity = w
|
|
},
|
|
GetAngularVelocity: function () {
|
|
return this.m_angularVelocity
|
|
},
|
|
ApplyForce: function (force, point, wake) {
|
|
if (this.m_type != b2Body.b2_dynamicBody) {
|
|
return
|
|
}
|
|
if (wake && (this.m_flags & b2Body.e_awakeFlag) == 0) {
|
|
this.SetAwake(true)
|
|
}
|
|
if (this.m_flags & b2Body.e_awakeFlag) {
|
|
this.m_force.Add(force);
|
|
this.m_torque += b2Cross_v2_v2(b2Vec2.Subtract(point, this.m_sweep.c), force)
|
|
}
|
|
},
|
|
ApplyForceToCenter: function (force, wake) {
|
|
if (this.m_type != b2Body.b2_dynamicBody) {
|
|
return
|
|
}
|
|
if (wake && (this.m_flags & b2Body.e_awakeFlag) == 0) {
|
|
this.SetAwake(true)
|
|
}
|
|
if (this.m_flags & b2Body.e_awakeFlag) {
|
|
this.m_force.Add(force)
|
|
}
|
|
},
|
|
ApplyTorque: function (torque, wake) {
|
|
if (this.m_type != b2Body.b2_dynamicBody) {
|
|
return
|
|
}
|
|
if (wake && (this.m_flags & b2Body.e_awakeFlag) == 0) {
|
|
this.SetAwake(true)
|
|
}
|
|
if (this.m_flags & b2Body.e_awakeFlag) {
|
|
this.m_torque += torque
|
|
}
|
|
},
|
|
ApplyLinearImpulse: function (impulse, point, wake) {
|
|
if (this.m_type != b2Body.b2_dynamicBody) {
|
|
return
|
|
}
|
|
if (wake && (this.m_flags & b2Body.e_awakeFlag) == 0) {
|
|
this.SetAwake(true)
|
|
}
|
|
if (this.m_flags & b2Body.e_awakeFlag) {
|
|
this.m_linearVelocity.Add(b2Vec2.Multiply(this.m_invMass, impulse));
|
|
this.m_angularVelocity += this.m_invI * b2Cross_v2_v2(b2Vec2.Subtract(point, this.m_sweep.c), impulse)
|
|
}
|
|
},
|
|
ApplyAngularImpulse: function (impulse, wake) {
|
|
if (this.m_type != b2Body.b2_dynamicBody) {
|
|
return
|
|
}
|
|
if (wake && (this.m_flags & b2Body.e_awakeFlag) == 0) {
|
|
this.SetAwake(true)
|
|
}
|
|
if (this.m_flags & b2Body.e_awakeFlag) {
|
|
this.m_angularVelocity += this.m_invI * impulse
|
|
}
|
|
},
|
|
GetMass: function () {
|
|
return this.m_mass
|
|
},
|
|
GetInertia: function () {
|
|
return this.m_I + this.m_mass * b2Dot_v2_v2(this.m_sweep.localCenter, this.m_sweep.localCenter)
|
|
},
|
|
GetMassData: function (data) {
|
|
data.mass = this.m_mass;
|
|
data.I = this.m_I + this.m_mass * b2Dot_v2_v2(this.m_sweep.localCenter, this.m_sweep.localCenter);
|
|
data.center = this.m_sweep.localCenter
|
|
},
|
|
SetMassData: function (massData) {
|
|
if (this.m_world.IsLocked() == true) {
|
|
return
|
|
}
|
|
if (this.m_type != b2Body.b2_dynamicBody) {
|
|
return
|
|
}
|
|
this.m_invMass = 0;
|
|
this.m_I = 0;
|
|
this.m_invI = 0;
|
|
this.m_mass = massData.mass;
|
|
if (this.m_mass <= 0) {
|
|
this.m_mass = 1
|
|
}
|
|
this.m_invMass = 1 / this.m_mass;
|
|
if (massData.I > 0 && (this.m_flags & b2Body.e_fixedRotationFlag) == 0) {
|
|
this.m_I = massData.I - this.m_mass * b2Dot_v2_v2(massData.center, massData.center);
|
|
this.m_invI = 1 / this.m_I
|
|
}
|
|
b2Body.m_local_oldCenter.Assign(this.m_sweep.c);
|
|
this.m_sweep.localCenter.Assign(massData.center);
|
|
this.m_sweep.c0.Assign(b2Mul_t_v2(this.m_xf, this.m_sweep.localCenter));
|
|
this.m_sweep.c.Assign(this.m_sweep.c0);
|
|
this.m_linearVelocity.Add(b2Cross_f_v2(this.m_angularVelocity, b2Vec2.Subtract(this.m_sweep.c, b2Body.m_local_oldCenter)))
|
|
},
|
|
ResetMassData: function () {
|
|
this.m_mass = 0;
|
|
this.m_invMass = 0;
|
|
this.m_I = 0;
|
|
this.m_invI = 0;
|
|
this.m_sweep.localCenter.SetZero();
|
|
if (this.m_type == b2Body.b2_staticBody || this.m_type == b2Body.b2_kinematicBody) {
|
|
this.m_sweep.c0.Assign(this.m_xf.p);
|
|
this.m_sweep.c.Assign(this.m_xf.p);
|
|
this.m_sweep.a0 = this.m_sweep.a;
|
|
return
|
|
}
|
|
var localCenter = new b2Vec2(0, 0);
|
|
for (var f = this.m_fixtureList; f; f = f.m_next) {
|
|
if (f.m_density == 0) {
|
|
continue
|
|
}
|
|
var massData = new b2MassData();
|
|
f.GetMassData(massData);
|
|
this.m_mass += massData.mass;
|
|
localCenter.Add(b2Vec2.Multiply(massData.mass, massData.center));
|
|
this.m_I += massData.I
|
|
}
|
|
if (this.m_mass > 0) {
|
|
this.m_invMass = 1 / this.m_mass;
|
|
localCenter.Multiply(this.m_invMass)
|
|
} else {
|
|
this.m_mass = 1;
|
|
this.m_invMass = 1
|
|
}
|
|
if (this.m_I > 0 && (this.m_flags & b2Body.e_fixedRotationFlag) == 0) {
|
|
this.m_I -= this.m_mass * b2Dot_v2_v2(localCenter, localCenter);
|
|
this.m_invI = 1 / this.m_I
|
|
} else {
|
|
this.m_I = 0;
|
|
this.m_invI = 0
|
|
}
|
|
b2Body.m_local_oldCenter.Assign(this.m_sweep.c);
|
|
this.m_sweep.localCenter.Assign(localCenter);
|
|
this.m_sweep.c0.Assign(b2Mul_t_v2(this.m_xf, this.m_sweep.localCenter));
|
|
this.m_sweep.c.Assign(this.m_sweep.c0);
|
|
this.m_linearVelocity.Add(b2Cross_f_v2(this.m_angularVelocity, b2Vec2.Subtract(this.m_sweep.c, b2Body.m_local_oldCenter)))
|
|
},
|
|
GetWorldPoint: function (localPoint) {
|
|
return b2Mul_t_v2(this.m_xf, localPoint)
|
|
},
|
|
GetWorldVector: function (localVector) {
|
|
return b2Mul_r_v2(this.m_xf.q, localVector)
|
|
},
|
|
GetLocalPoint: function (worldPoint) {
|
|
return b2MulT_t_v2(this.m_xf, worldPoint)
|
|
},
|
|
GetLocalVector: function (worldVector) {
|
|
return b2MulT_r_v2(this.m_xf.q, worldVector)
|
|
},
|
|
GetLinearVelocityFromWorldPoint: function (worldPoint) {
|
|
return b2Vec2.Add(this.m_linearVelocity, b2Cross_f_v2(this.m_angularVelocity, b2Vec2.Subtract(worldPoint, this.m_sweep.c)))
|
|
},
|
|
GetLinearVelocityFromLocalPoint: function (localPoint) {
|
|
return this.GetLinearVelocityFromWorldPoint(this.GetWorldPoint(localPoint))
|
|
},
|
|
GetLinearDamping: function () {
|
|
return this.m_linearDamping
|
|
},
|
|
SetLinearDamping: function (linearDamping) {
|
|
this.m_linearDamping = linearDamping
|
|
},
|
|
GetAngularDamping: function () {
|
|
return this.m_angularDamping
|
|
},
|
|
SetAngularDamping: function (angularDamping) {
|
|
this.m_angularDamping = angularDamping
|
|
},
|
|
GetGravityScale: function () {
|
|
return this.m_gravityScale
|
|
},
|
|
SetGravityScale: function (scale) {
|
|
this.m_gravityScale = scale
|
|
},
|
|
SetType: function (type) {
|
|
if (this.m_world.IsLocked() == true) {
|
|
return
|
|
}
|
|
if (this.m_type == type) {
|
|
return
|
|
}
|
|
this.m_type = type;
|
|
this.ResetMassData();
|
|
if (this.m_type == b2Body.b2_staticBody) {
|
|
this.m_linearVelocity.SetZero();
|
|
this.m_angularVelocity = 0;
|
|
this.m_sweep.a0 = this.m_sweep.a;
|
|
this.m_sweep.c0.Assign(this.m_sweep.c);
|
|
this.SynchronizeFixtures()
|
|
}
|
|
this.SetAwake(true);
|
|
this.m_force.SetZero();
|
|
this.m_torque = 0;
|
|
var ce = this.m_contactList;
|
|
while (ce) {
|
|
var ce0 = ce;
|
|
ce = ce.next;
|
|
this.m_world.m_contactManager.Destroy(ce0.contact)
|
|
}
|
|
this.m_contactList = null;
|
|
var broadPhase = this.m_world.m_contactManager.m_broadPhase;
|
|
for (var f = this.m_fixtureList; f; f = f.m_next) {
|
|
var proxyCount = f.m_proxyCount;
|
|
for (var i = 0; i < proxyCount; ++i) {
|
|
broadPhase.TouchProxy(f.m_proxies[i].proxyId)
|
|
}
|
|
}
|
|
},
|
|
GetType: function () {
|
|
return this.m_type
|
|
},
|
|
SetBullet: function (flag) {
|
|
if (flag) {
|
|
this.m_flags |= b2Body.e_bulletFlag
|
|
} else {
|
|
this.m_flags &= ~b2Body.e_bulletFlag
|
|
}
|
|
},
|
|
IsBullet: function () {
|
|
return (this.m_flags & b2Body.e_bulletFlag) == b2Body.e_bulletFlag
|
|
},
|
|
SetSleepingAllowed: function (flag) {
|
|
if (flag) {
|
|
this.m_flags |= b2Body.e_autoSleepFlag
|
|
} else {
|
|
this.m_flags &= ~b2Body.e_autoSleepFlag;
|
|
this.SetAwake(true)
|
|
}
|
|
},
|
|
IsSleepingAllowed: function () {
|
|
return (this.m_flags & b2Body.e_autoSleepFlag) == b2Body.e_autoSleepFlag
|
|
},
|
|
SetAwake: function (flag) {
|
|
if (flag) {
|
|
if ((this.m_flags & b2Body.e_awakeFlag) == 0) {
|
|
this.m_flags |= b2Body.e_awakeFlag;
|
|
this.m_sleepTime = 0
|
|
}
|
|
} else {
|
|
this.m_flags &= ~b2Body.e_awakeFlag;
|
|
this.m_sleepTime = 0;
|
|
this.m_linearVelocity.SetZero();
|
|
this.m_angularVelocity = 0;
|
|
this.m_force.SetZero();
|
|
this.m_torque = 0
|
|
}
|
|
},
|
|
IsAwake: function () {
|
|
return (this.m_flags & b2Body.e_awakeFlag) == b2Body.e_awakeFlag
|
|
},
|
|
SetActive: function (flag) {
|
|
if (flag == this.IsActive()) {
|
|
return
|
|
}
|
|
if (flag) {
|
|
this.m_flags |= b2Body.e_activeFlag;
|
|
var broadPhase = this.m_world.m_contactManager.m_broadPhase;
|
|
for (var f = this.m_fixtureList; f; f = f.m_next) {
|
|
f.CreateProxies(broadPhase, this.m_xf)
|
|
}
|
|
} else {
|
|
this.m_flags &= ~b2Body.e_activeFlag;
|
|
var broadPhase = this.m_world.m_contactManager.m_broadPhase;
|
|
for (var f = this.m_fixtureList; f; f = f.m_next) {
|
|
f.DestroyProxies(broadPhase)
|
|
}
|
|
var ce = this.m_contactList;
|
|
while (ce) {
|
|
var ce0 = ce;
|
|
ce = ce.next;
|
|
this.m_world.m_contactManager.Destroy(ce0.contact)
|
|
}
|
|
this.m_contactList = null
|
|
}
|
|
},
|
|
IsActive: function () {
|
|
return (this.m_flags & b2Body.e_activeFlag) == b2Body.e_activeFlag
|
|
},
|
|
SetFixedRotation: function (flag) {
|
|
var status = (this.m_flags & b2Body.e_fixedRotationFlag) == b2Body.e_fixedRotationFlag;
|
|
if (status == flag) {
|
|
return
|
|
}
|
|
if (flag) {
|
|
this.m_flags |= b2Body.e_fixedRotationFlag
|
|
} else {
|
|
this.m_flags &= ~b2Body.e_fixedRotationFlag
|
|
}
|
|
this.m_angularVelocity = 0;
|
|
this.ResetMassData()
|
|
},
|
|
IsFixedRotation: function () {
|
|
return (this.m_flags & b2Body.e_fixedRotationFlag) == b2Body.e_fixedRotationFlag
|
|
},
|
|
GetFixtureList: function () {
|
|
return this.m_fixtureList
|
|
},
|
|
GetJointList: function () {
|
|
return this.m_jointList
|
|
},
|
|
GetContactList: function () {
|
|
return this.m_contactList
|
|
},
|
|
GetNext: function () {
|
|
return this.m_next
|
|
},
|
|
GetUserData: function () {
|
|
return this.m_userData
|
|
},
|
|
SetUserData: function (data) {
|
|
this.m_userData = data
|
|
},
|
|
GetWorld: function () {
|
|
return this.m_world
|
|
},
|
|
SynchronizeFixtures: function () {
|
|
b2Body.m_local_xf1.q.Set(this.m_sweep.a0);
|
|
b2Body.m_local_xf1.p.Assign(b2Vec2.Subtract(this.m_sweep.c0, b2Mul_r_v2(b2Body.m_local_xf1.q, this.m_sweep.localCenter)));
|
|
var broadPhase = this.m_world.m_contactManager.m_broadPhase;
|
|
for (var f = this.m_fixtureList; f; f = f.m_next) {
|
|
f.Synchronize(broadPhase, b2Body.m_local_xf1, this.m_xf)
|
|
}
|
|
},
|
|
SynchronizeTransform: function () {
|
|
this.m_xf.q.Set(this.m_sweep.a);
|
|
this.m_xf.p.Assign(b2Vec2.Subtract(this.m_sweep.c, b2Mul_r_v2(this.m_xf.q, this.m_sweep.localCenter)))
|
|
},
|
|
ShouldCollide: function (other) {
|
|
if (this.m_type != b2Body.b2_dynamicBody && other.m_type != b2Body.b2_dynamicBody) {
|
|
return false
|
|
}
|
|
for (var jn = this.m_jointList; jn; jn = jn.next) {
|
|
if (jn.other == other) {
|
|
if (jn.joint.m_collideConnected == false) {
|
|
return false
|
|
}
|
|
}
|
|
}
|
|
return true
|
|
},
|
|
Advance: function (alpha) {
|
|
this.m_sweep.Advance(alpha);
|
|
this.m_sweep.c.Assign(this.m_sweep.c0);
|
|
this.m_sweep.a = this.m_sweep.a0;
|
|
this.m_xf.q.Set(this.m_sweep.a);
|
|
this.m_xf.p.Assign(b2Vec2.Subtract(this.m_sweep.c, b2Mul_r_v2(this.m_xf.q, this.m_sweep.localCenter)))
|
|
},
|
|
_serialize: function (out) {
|
|
var obj = out || {};
|
|
obj.fixtures = null;
|
|
obj.type = this.m_type;
|
|
obj.position = this.GetPosition()._serialize();
|
|
obj.angle = this.GetAngle();
|
|
obj.linearVelocity = this.GetLinearVelocity()._serialize();
|
|
obj.angularVelocity = this.GetAngularVelocity();
|
|
obj.linearDamping = this.GetLinearDamping();
|
|
obj.angularDamping = this.GetAngularDamping();
|
|
obj.allowSleep = this.IsSleepingAllowed();
|
|
obj.awake = this.IsAwake();
|
|
obj.fixedRotation = this.IsFixedRotation();
|
|
obj.bullet = this.IsBullet();
|
|
obj.active = this.IsActive();
|
|
obj.gravityScale = this.GetGravityScale();
|
|
return obj
|
|
}
|
|
};
|
|
"use strict";
|
|
|
|
function b2Filter() {
|
|
this.categoryBits = 1;
|
|
this.maskBits = 65535;
|
|
this.groupIndex = 0
|
|
}
|
|
b2Filter.prototype = {
|
|
Clone: function () {
|
|
var filter = new b2Filter();
|
|
filter.categoryBits = this.categoryBits;
|
|
filter.maskBits = this.maskBits;
|
|
filter.groupIndex = this.groupIndex;
|
|
return filter
|
|
},
|
|
Assign: function (filter) {
|
|
this.categoryBits = filter.categoryBits;
|
|
this.maskBits = filter.maskBits;
|
|
this.groupIndex = filter.groupIndex
|
|
},
|
|
_serialize: function (out) {
|
|
var obj = out || {};
|
|
obj.categoryBits = this.categoryBits;
|
|
obj.maskBits = this.maskBits;
|
|
obj.groupIndex = this.groupIndex;
|
|
return obj
|
|
},
|
|
_deserialize: function (data) {
|
|
this.categoryBits = data.categoryBits;
|
|
this.maskBits = data.maskBits;
|
|
this.groupIndex = data.groupIndex
|
|
}
|
|
};
|
|
|
|
function b2FixtureDef() {
|
|
this.shape = null;
|
|
this.userData = null;
|
|
this.friction = 0.2;
|
|
this.restitution = 0;
|
|
this.density = 0;
|
|
this.isSensor = false;
|
|
this.filter = new b2Filter();
|
|
Object.seal(this)
|
|
}
|
|
b2FixtureDef.prototype = {
|
|
_deserialize: function (data) {
|
|
this.friction = data.friction;
|
|
this.restitution = data.restitution;
|
|
this.density = data.density;
|
|
this.isSensor = data.isSensor;
|
|
this.filter._deserialize(data.filter)
|
|
}
|
|
};
|
|
|
|
function b2FixtureProxy() {
|
|
this.aabb = new b2AABB();
|
|
this.fixture = null;
|
|
this.childIndex = 0;
|
|
this.proxyId = 0
|
|
}
|
|
|
|
function b2Fixture() {
|
|
this.m_userData = null;
|
|
this.m_body = null;
|
|
this.m_next = null;
|
|
this.m_proxies = null;
|
|
this.m_proxyCount = 0;
|
|
this.m_shape = null;
|
|
this.m_density = 0;
|
|
this.m_filter = new b2Filter();
|
|
this.m_isSensor = false;
|
|
this.m_friction = 0;
|
|
this.m_restitution = 0
|
|
}
|
|
b2Fixture.prototype = {
|
|
GetType: function () {
|
|
return this.m_shape.GetType()
|
|
},
|
|
GetShape: function () {
|
|
return this.m_shape
|
|
},
|
|
SetSensor: function (sensor) {
|
|
if (sensor != this.m_isSensor) {
|
|
this.m_body.SetAwake(true);
|
|
this.m_isSensor = sensor
|
|
}
|
|
},
|
|
IsSensor: function () {
|
|
return this.m_isSensor
|
|
},
|
|
SetFilterData: function (filter) {
|
|
this.m_filter = filter;
|
|
this.Refilter()
|
|
},
|
|
GetFilterData: function () {
|
|
return this.m_filter
|
|
},
|
|
Refilter: function () {
|
|
if (this.m_body == null) {
|
|
return
|
|
}
|
|
var edge = this.m_body.GetContactList();
|
|
while (edge) {
|
|
var contact = edge.contact;
|
|
var fixtureA = contact.GetFixtureA();
|
|
var fixtureB = contact.GetFixtureB();
|
|
if (fixtureA == this || fixtureB == this) {
|
|
contact.FlagForFiltering()
|
|
}
|
|
edge = edge.next
|
|
}
|
|
var world = this.m_body.GetWorld();
|
|
if (world == null) {
|
|
return
|
|
}
|
|
var broadPhase = world.m_contactManager.m_broadPhase;
|
|
for (var i = 0; i < this.m_proxyCount; ++i) {
|
|
broadPhase.TouchProxy(this.m_proxies[i].proxyId)
|
|
}
|
|
},
|
|
GetBody: function () {
|
|
return this.m_body
|
|
},
|
|
GetNext: function () {
|
|
return this.m_next
|
|
},
|
|
GetUserData: function () {
|
|
return this.m_userData
|
|
},
|
|
SetUserData: function (data) {
|
|
this.m_userData = data
|
|
},
|
|
TestPoint: function (p) {
|
|
return this.m_shape.TestPoint(this.m_body.GetTransform(), p)
|
|
},
|
|
RayCast: function (output, input, childIndex) {
|
|
return this.m_shape.RayCast(output, input, this.m_body.GetTransform(), childIndex)
|
|
},
|
|
GetMassData: function (massData) {
|
|
this.m_shape.ComputeMass(massData, this.m_density)
|
|
},
|
|
SetDensity: function (density) {
|
|
this.m_density = density
|
|
},
|
|
GetDensity: function () {
|
|
return this.m_density
|
|
},
|
|
GetFriction: function () {
|
|
return this.m_friction
|
|
},
|
|
SetFriction: function (friction) {
|
|
this.m_friction = friction
|
|
},
|
|
GetRestitution: function () {
|
|
return this.m_restitution
|
|
},
|
|
SetRestitution: function (restitution) {
|
|
this.m_restitution = restitution
|
|
},
|
|
GetAABB: function (childIndex) {
|
|
return this.m_proxies[childIndex].aabb
|
|
},
|
|
Create: function (body, def) {
|
|
this.m_userData = def.userData;
|
|
this.m_friction = def.friction;
|
|
this.m_restitution = def.restitution;
|
|
this.m_body = body;
|
|
this.m_next = null;
|
|
this.m_filter.Assign(def.filter);
|
|
this.m_isSensor = def.isSensor;
|
|
this.m_shape = def.shape.Clone();
|
|
var childCount = this.m_shape.GetChildCount();
|
|
this.m_proxies = new Array(childCount);
|
|
for (var i = 0; i < childCount; ++i) {
|
|
this.m_proxies[i] = new b2FixtureProxy();
|
|
this.m_proxies[i].fixture = null;
|
|
this.m_proxies[i].proxyId = b2BroadPhase.e_nullProxy
|
|
}
|
|
this.m_proxyCount = 0;
|
|
this.m_density = def.density
|
|
},
|
|
Destroy: function () {
|
|
this.m_proxies = null;
|
|
this.m_shape = null
|
|
},
|
|
CreateProxies: function (broadPhase, xf) {
|
|
this.m_proxyCount = this.m_shape.GetChildCount();
|
|
for (var i = 0; i < this.m_proxyCount; ++i) {
|
|
var proxy = this.m_proxies[i];
|
|
this.m_shape.ComputeAABB(proxy.aabb, xf, i);
|
|
proxy.proxyId = broadPhase.CreateProxy(proxy.aabb, proxy);
|
|
proxy.fixture = this;
|
|
proxy.childIndex = i
|
|
}
|
|
},
|
|
DestroyProxies: function (broadPhase) {
|
|
for (var i = 0; i < this.m_proxyCount; ++i) {
|
|
var proxy = this.m_proxies[i];
|
|
broadPhase.DestroyProxy(proxy.proxyId);
|
|
proxy.proxyId = b2BroadPhase.e_nullProxy
|
|
}
|
|
this.m_proxyCount = 0
|
|
},
|
|
Synchronize: function (broadPhase, transform1, transform2) {
|
|
if (this.m_proxyCount == 0) {
|
|
return
|
|
}
|
|
for (var i = 0; i < this.m_proxyCount; ++i) {
|
|
var proxy = this.m_proxies[i];
|
|
var aabb1 = new b2AABB(),
|
|
aabb2 = new b2AABB();
|
|
this.m_shape.ComputeAABB(aabb1, transform1, proxy.childIndex);
|
|
this.m_shape.ComputeAABB(aabb2, transform2, proxy.childIndex);
|
|
proxy.aabb.Combine(aabb1, aabb2);
|
|
var displacement = b2Vec2.Subtract(transform2.p, transform1.p);
|
|
broadPhase.MoveProxy(proxy.proxyId, proxy.aabb, displacement)
|
|
}
|
|
},
|
|
_serialize: function (out) {
|
|
var obj = out || {};
|
|
obj.shape = null;
|
|
obj.friction = this.m_friction;
|
|
obj.restitution = this.m_restitution;
|
|
obj.density = this.m_density;
|
|
obj.isSensor = this.m_isSensor;
|
|
obj.filter = this.m_filter._serialize();
|
|
return obj
|
|
}
|
|
};
|
|
"use strict";
|
|
|
|
function b2DestructionListener() {}
|
|
b2DestructionListener.prototype = {
|
|
SayGoodbyeJoint: function (joint) {},
|
|
SayGoodbyeFixture: function (fixture) {}
|
|
};
|
|
|
|
function b2ContactFilter() {}
|
|
b2ContactFilter.prototype = {
|
|
ShouldCollide: function (fixtureA, fixtureB) {
|
|
var filterA = fixtureA.GetFilterData();
|
|
var filterB = fixtureB.GetFilterData();
|
|
if (filterA.groupIndex == filterB.groupIndex && filterA.groupIndex != 0) {
|
|
return filterA.groupIndex > 0
|
|
}
|
|
var collide = (filterA.maskBits & filterB.categoryBits) != 0 && (filterA.categoryBits & filterB.maskBits) != 0;
|
|
return collide
|
|
}
|
|
};
|
|
|
|
function b2ContactImpulse() {
|
|
this.normalImpulses = new Array(b2_maxManifoldPoints);
|
|
this.tangentImpulses = new Array(b2_maxManifoldPoints);
|
|
this.count = 0
|
|
}
|
|
|
|
function b2ContactListener() {}
|
|
b2ContactListener.prototype = {
|
|
BeginContact: function (contact) {},
|
|
EndContact: function (contact) {},
|
|
PreSolve: function (contact, oldManifold) {},
|
|
PostSolve: function (contact, impulse) {}
|
|
};
|
|
|
|
function b2QueryCallback() {}
|
|
b2QueryCallback.prototype = {
|
|
ReportFixture: function (fixture) {}
|
|
};
|
|
|
|
function b2RayCastCallback() {}
|
|
b2RayCastCallback.prototype = {
|
|
ReportFixture: function (fixture, point, normal, fraction) {}
|
|
};
|
|
"use strict";
|
|
|
|
function b2TimeStep() {
|
|
this.dt = 0;
|
|
this.inv_dt = 0;
|
|
this.dtRatio = 0;
|
|
this.velocityIterations = 0;
|
|
this.positionIterations = 0;
|
|
this.warmStarting = false
|
|
}
|
|
|
|
function b2Position() {
|
|
this.c = new b2Vec2();
|
|
this.a = 0
|
|
}
|
|
|
|
function b2Velocity() {
|
|
this.v = new b2Vec2();
|
|
this.w = 0
|
|
}
|
|
|
|
function b2SolverData() {
|
|
this.step = new b2TimeStep();
|
|
this.positions = null;
|
|
this.velocities = null
|
|
}
|
|
"use strict";
|
|
var profile_world_step = b2Profiler.create("step");
|
|
var profile_world_collide = b2Profiler.create("collide", "step");
|
|
var profile_world_solve = b2Profiler.create("solve", "step");
|
|
var profile_world_solveTOI = b2Profiler.create("solveTOI", "step");
|
|
var profile_world_broadphase = b2Profiler.create("broadphase", "step");
|
|
|
|
function b2World(gravity) {
|
|
this.m_contactManager = new b2ContactManager();
|
|
this.m_destructionListener = null;
|
|
this.g_debugDraw = null;
|
|
this.m_bodyList = null;
|
|
this.m_jointList = null;
|
|
this.m_bodyCount = 0;
|
|
this.m_jointCount = 0;
|
|
this.m_warmStarting = true;
|
|
this.m_continuousPhysics = true;
|
|
this.m_subStepping = false;
|
|
this.m_stepComplete = true;
|
|
this.m_allowSleep = true;
|
|
this.m_gravity = gravity;
|
|
this.m_flags = b2World.e_clearForces;
|
|
this.m_inv_dt0 = 0;
|
|
this.p_step = new b2TimeStep();
|
|
this.p_island = new b2Island()
|
|
}
|
|
|
|
function b2WorldQueryWrapper() {
|
|
this.broadPhase = null;
|
|
this.callback = null
|
|
}
|
|
b2WorldQueryWrapper.prototype = {
|
|
QueryCallback: function (proxyId) {
|
|
var proxy = this.broadPhase.GetUserData(proxyId);
|
|
return this.callback.ReportFixture(proxy.fixture)
|
|
}
|
|
};
|
|
|
|
function b2WorldRayCastWrapper() {
|
|
this.broadPhase = null;
|
|
this.callback = null
|
|
}
|
|
b2WorldRayCastWrapper.prototype = {
|
|
RayCastCallback: function (input, proxyId) {
|
|
var userData = this.broadPhase.GetUserData(proxyId);
|
|
var proxy = userData;
|
|
var fixture = proxy.fixture;
|
|
var index = proxy.childIndex;
|
|
var output = new b2RayCastOutput();
|
|
var hit = fixture.RayCast(output, input, index);
|
|
if (hit) {
|
|
var fraction = output.fraction;
|
|
var point = b2Vec2.Add(b2Vec2.Multiply((1 - fraction), input.p1), b2Vec2.Multiply(fraction, input.p2));
|
|
return this.callback.ReportFixture(fixture, point, output.normal, fraction)
|
|
}
|
|
return input.maxFraction
|
|
}
|
|
};
|
|
b2World.m_local_sweep_backupA = new b2Sweep();
|
|
b2World.m_local_sweep_backupB = new b2Sweep();
|
|
b2World.m_local_sweep_backupC = new b2Sweep();
|
|
b2World.prototype = {
|
|
Destroy: function () {
|
|
var b = this.m_bodyList;
|
|
while (b) {
|
|
var bNext = b.m_next;
|
|
var f = b.m_fixtureList;
|
|
while (f) {
|
|
var fNext = f.m_next;
|
|
f.m_proxyCount = 0;
|
|
f.Destroy();
|
|
f = fNext
|
|
}
|
|
b = bNext
|
|
}
|
|
},
|
|
SetDestructionListener: function (listener) {
|
|
this.m_destructionListener = listener
|
|
},
|
|
SetContactFilter: function (filter) {
|
|
this.m_contactManager.m_contactFilter = filter
|
|
},
|
|
SetContactListener: function (listener) {
|
|
this.m_contactManager.m_contactListener = listener
|
|
},
|
|
SetDebugDraw: function (debugDraw) {
|
|
this.g_debugDraw = debugDraw
|
|
},
|
|
CreateBody: function (def) {
|
|
if (this.IsLocked()) {
|
|
return null
|
|
}
|
|
var b = new b2Body(def, this);
|
|
b.m_prev = null;
|
|
b.m_next = this.m_bodyList;
|
|
if (this.m_bodyList) {
|
|
this.m_bodyList.m_prev = b
|
|
}
|
|
this.m_bodyList = b;
|
|
++this.m_bodyCount;
|
|
return b
|
|
},
|
|
DestroyBody: function (b) {
|
|
if (this.IsLocked()) {
|
|
return
|
|
}
|
|
var je = b.m_jointList;
|
|
while (je) {
|
|
var je0 = je;
|
|
je = je.next;
|
|
if (this.m_destructionListener) {
|
|
this.m_destructionListener.SayGoodbyeJoint(je0.joint)
|
|
}
|
|
this.DestroyJoint(je0.joint);
|
|
b.m_jointList = je
|
|
}
|
|
b.m_jointList = null;
|
|
var ce = b.m_contactList;
|
|
while (ce) {
|
|
var ce0 = ce;
|
|
ce = ce.next;
|
|
this.m_contactManager.Destroy(ce0.contact)
|
|
}
|
|
b.m_contactList = null;
|
|
var f = b.m_fixtureList;
|
|
while (f) {
|
|
var f0 = f;
|
|
f = f.m_next;
|
|
if (this.m_destructionListener) {
|
|
this.m_destructionListener.SayGoodbyeFixture(f0)
|
|
}
|
|
f0.DestroyProxies(this.m_contactManager.m_broadPhase);
|
|
f0.Destroy();
|
|
b.m_fixtureList = f;
|
|
b.m_fixtureCount -= 1
|
|
}
|
|
b.m_fixtureList = null;
|
|
b.m_fixtureCount = 0;
|
|
if (b.m_prev) {
|
|
b.m_prev.m_next = b.m_next
|
|
}
|
|
if (b.m_next) {
|
|
b.m_next.m_prev = b.m_prev
|
|
}
|
|
if (b == this.m_bodyList) {
|
|
this.m_bodyList = b.m_next
|
|
}
|
|
b.m_destroyed = true;
|
|
--this.m_bodyCount
|
|
},
|
|
CreateJoint: function (def) {
|
|
if (this.IsLocked()) {
|
|
return null
|
|
}
|
|
var j = b2Joint.Create(def);
|
|
j.m_prev = null;
|
|
j.m_next = this.m_jointList;
|
|
if (this.m_jointList) {
|
|
this.m_jointList.m_prev = j
|
|
}
|
|
this.m_jointList = j;
|
|
++this.m_jointCount;
|
|
j.m_edgeA.joint = j;
|
|
j.m_edgeA.other = j.m_bodyB;
|
|
j.m_edgeA.prev = null;
|
|
j.m_edgeA.next = j.m_bodyA.m_jointList;
|
|
if (j.m_bodyA.m_jointList) {
|
|
j.m_bodyA.m_jointList.prev = j.m_edgeA
|
|
}
|
|
j.m_bodyA.m_jointList = j.m_edgeA;
|
|
j.m_edgeB.joint = j;
|
|
j.m_edgeB.other = j.m_bodyA;
|
|
j.m_edgeB.prev = null;
|
|
j.m_edgeB.next = j.m_bodyB.m_jointList;
|
|
if (j.m_bodyB.m_jointList) {
|
|
j.m_bodyB.m_jointList.prev = j.m_edgeB
|
|
}
|
|
j.m_bodyB.m_jointList = j.m_edgeB;
|
|
var bodyA = def.bodyA;
|
|
var bodyB = def.bodyB;
|
|
if (def.collideConnected == false) {
|
|
var edge = bodyB.GetContactList();
|
|
while (edge) {
|
|
if (edge.other == bodyA) {
|
|
edge.contact.FlagForFiltering()
|
|
}
|
|
edge = edge.next
|
|
}
|
|
}
|
|
return j
|
|
},
|
|
DestroyJoint: function (j) {
|
|
if (this.IsLocked()) {
|
|
return
|
|
}
|
|
var collideConnected = j.m_collideConnected;
|
|
if (j.m_prev) {
|
|
j.m_prev.m_next = j.m_next
|
|
}
|
|
if (j.m_next) {
|
|
j.m_next.m_prev = j.m_prev
|
|
}
|
|
if (j == this.m_jointList) {
|
|
this.m_jointList = j.m_next
|
|
}
|
|
var bodyA = j.m_bodyA;
|
|
var bodyB = j.m_bodyB;
|
|
bodyA.SetAwake(true);
|
|
bodyB.SetAwake(true);
|
|
if (j.m_edgeA.prev) {
|
|
j.m_edgeA.prev.next = j.m_edgeA.next
|
|
}
|
|
if (j.m_edgeA.next) {
|
|
j.m_edgeA.next.prev = j.m_edgeA.prev
|
|
}
|
|
if (j.m_edgeA == bodyA.m_jointList) {
|
|
bodyA.m_jointList = j.m_edgeA.next
|
|
}
|
|
j.m_edgeA.prev = null;
|
|
j.m_edgeA.next = null;
|
|
if (j.m_edgeB.prev) {
|
|
j.m_edgeB.prev.next = j.m_edgeB.next
|
|
}
|
|
if (j.m_edgeB.next) {
|
|
j.m_edgeB.next.prev = j.m_edgeB.prev
|
|
}
|
|
if (j.m_edgeB == bodyB.m_jointList) {
|
|
bodyB.m_jointList = j.m_edgeB.next
|
|
}
|
|
j.m_edgeB.prev = null;
|
|
j.m_edgeB.next = null;
|
|
b2Joint.Destroy(j);
|
|
--this.m_jointCount;
|
|
if (collideConnected == false) {
|
|
var edge = bodyB.GetContactList();
|
|
while (edge) {
|
|
if (edge.other == bodyA) {
|
|
edge.contact.FlagForFiltering()
|
|
}
|
|
edge = edge.next
|
|
}
|
|
}
|
|
},
|
|
Step: function (dt, velocityIterations, positionIterations) {
|
|
profile_world_step.start();
|
|
if (this.m_flags & b2World.e_newFixture) {
|
|
this.m_contactManager.FindNewContacts();
|
|
this.m_flags &= ~b2World.e_newFixture
|
|
}
|
|
this.m_flags |= b2World.e_locked;
|
|
this.p_step.dt = dt;
|
|
this.p_step.velocityIterations = velocityIterations;
|
|
this.p_step.positionIterations = positionIterations;
|
|
if (dt > 0) {
|
|
this.p_step.inv_dt = 1 / dt
|
|
} else {
|
|
this.p_step.inv_dt = 0
|
|
}
|
|
this.p_step.dtRatio = this.m_inv_dt0 * dt;
|
|
this.p_step.warmStarting = this.m_warmStarting;
|
|
profile_world_collide.start();
|
|
this.m_contactManager.Collide();
|
|
profile_world_collide.stop();
|
|
if (this.m_stepComplete && this.p_step.dt > 0) {
|
|
profile_world_solve.start();
|
|
this.Solve(this.p_step);
|
|
profile_world_solve.stop()
|
|
}
|
|
if (this.m_continuousPhysics && this.p_step.dt > 0) {
|
|
profile_world_solveTOI.start();
|
|
this.SolveTOI(this.p_step);
|
|
profile_world_solveTOI.stop()
|
|
}
|
|
if (this.p_step.dt > 0) {
|
|
this.m_inv_dt0 = this.p_step.inv_dt
|
|
}
|
|
if (this.m_flags & b2World.e_clearForces) {
|
|
this.ClearForces()
|
|
}
|
|
this.m_flags &= ~b2World.e_locked;
|
|
profile_world_step.stop()
|
|
},
|
|
ClearForces: function () {
|
|
for (var body = this.m_bodyList; body; body = body.GetNext()) {
|
|
body.m_force.x = body.m_force.y = 0;
|
|
body.m_torque = 0
|
|
}
|
|
},
|
|
DrawDebugData: function () {
|
|
if (this.g_debugDraw == null) {
|
|
return
|
|
}
|
|
var flags = this.g_debugDraw.GetFlags();
|
|
if (flags & b2Draw.e_shapeBit) {
|
|
for (var b = this.m_bodyList; b; b = b.GetNext()) {
|
|
var xf = b.GetTransform();
|
|
for (var f = b.GetFixtureList(); f; f = f.GetNext()) {
|
|
if (b.IsActive() == false) {
|
|
this.DrawShape(f, xf, new b2Color(0.5, 0.5, 0.3))
|
|
} else {
|
|
if (b.GetType() == b2Body.b2_staticBody) {
|
|
this.DrawShape(f, xf, new b2Color(0.5, 0.9, 0.5))
|
|
} else {
|
|
if (b.GetType() == b2Body.b2_kinematicBody) {
|
|
this.DrawShape(f, xf, new b2Color(0.5, 0.5, 0.9))
|
|
} else {
|
|
if (b.IsAwake() == false) {
|
|
this.DrawShape(f, xf, new b2Color(0.6, 0.6, 0.6))
|
|
} else {
|
|
this.DrawShape(f, xf, new b2Color(0.9, 0.7, 0.7))
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (flags & b2Draw.e_jointBit) {
|
|
for (var j = this.m_jointList; j; j = j.GetNext()) {
|
|
this.DrawJoint(j)
|
|
}
|
|
}
|
|
if (flags & b2Draw.e_pairBit) {
|
|
var color = new b2Color(0.3, 0.9, 0.9);
|
|
for (var c = this.m_contactManager.m_contactList; c; c = c.GetNext()) {
|
|
var fixtureA = c.GetFixtureA();
|
|
var fixtureB = c.GetFixtureB();
|
|
var cA = fixtureA.GetAABB(c.GetChildIndexA()).GetCenter();
|
|
var cB = fixtureB.GetAABB(c.GetChildIndexB()).GetCenter();
|
|
this.g_debugDraw.DrawSegment(cA, cB, color)
|
|
}
|
|
}
|
|
if (flags & b2Draw.e_aabbBit) {
|
|
var color = new b2Color(0.9, 0.3, 0.9);
|
|
var bp = this.m_contactManager.m_broadPhase;
|
|
for (var b = this.m_bodyList; b; b = b.GetNext()) {
|
|
if (b.IsActive() == false) {
|
|
continue
|
|
}
|
|
for (var f = b.GetFixtureList(); f; f = f.GetNext()) {
|
|
for (var i = 0; i < f.m_proxyCount; ++i) {
|
|
var proxy = f.m_proxies[i];
|
|
var aabb = bp.GetFatAABB(proxy.proxyId);
|
|
var vs = [];
|
|
vs[0] = new b2Vec2(aabb.lowerBound.x, aabb.lowerBound.y);
|
|
vs[1] = new b2Vec2(aabb.upperBound.x, aabb.lowerBound.y);
|
|
vs[2] = new b2Vec2(aabb.upperBound.x, aabb.upperBound.y);
|
|
vs[3] = new b2Vec2(aabb.lowerBound.x, aabb.upperBound.y);
|
|
this.g_debugDraw.DrawPolygon(vs, 4, color)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (flags & b2Draw.e_centerOfMassBit) {
|
|
for (var b = this.m_bodyList; b; b = b.GetNext()) {
|
|
var xf = b.GetTransform().Clone();
|
|
xf.p = b.GetWorldCenter();
|
|
this.g_debugDraw.DrawTransform(xf)
|
|
}
|
|
}
|
|
},
|
|
QueryAABB: function (callback, aabb) {
|
|
var wrapper = new b2WorldQueryWrapper();
|
|
wrapper.broadPhase = this.m_contactManager.m_broadPhase;
|
|
wrapper.callback = callback;
|
|
this.m_contactManager.m_broadPhase.Query(wrapper, aabb)
|
|
},
|
|
RayCast: function (callback, point1, point2) {
|
|
var wrapper = new b2WorldRayCastWrapper();
|
|
wrapper.broadPhase = this.m_contactManager.m_broadPhase;
|
|
wrapper.callback = callback;
|
|
var input = new b2RayCastInput();
|
|
input.maxFraction = 1;
|
|
input.p1 = point1;
|
|
input.p2 = point2;
|
|
this.m_contactManager.m_broadPhase.RayCast(wrapper, input)
|
|
},
|
|
GetBodyList: function () {
|
|
return this.m_bodyList
|
|
},
|
|
GetJointList: function () {
|
|
return this.m_jointList
|
|
},
|
|
GetContactList: function () {
|
|
return this.m_contactManager.m_contactList
|
|
},
|
|
SetAllowSleeping: function (flag) {
|
|
if (flag == this.m_allowSleep) {
|
|
return
|
|
}
|
|
this.m_allowSleep = flag;
|
|
if (this.m_allowSleep == false) {
|
|
for (var b = this.m_bodyList; b; b = b.m_next) {
|
|
b.SetAwake(true)
|
|
}
|
|
}
|
|
},
|
|
GetAllowSleeping: function () {
|
|
return this.m_allowSleep
|
|
},
|
|
SetWarmStarting: function (flag) {
|
|
this.m_warmStarting = flag
|
|
},
|
|
GetWarmStarting: function () {
|
|
return this.m_warmStarting
|
|
},
|
|
SetContinuousPhysics: function (flag) {
|
|
this.m_continuousPhysics = flag
|
|
},
|
|
GetContinuousPhysics: function () {
|
|
return this.m_continuousPhysics
|
|
},
|
|
SetSubStepping: function (flag) {
|
|
this.m_subStepping = flag
|
|
},
|
|
GetSubStepping: function () {
|
|
return this.m_subStepping
|
|
},
|
|
GetProxyCount: function () {
|
|
return this.m_contactManager.m_broadPhase.GetProxyCount()
|
|
},
|
|
GetBodyCount: function () {
|
|
return this.m_bodyCount
|
|
},
|
|
GetJointCount: function () {
|
|
return this.m_jointCount
|
|
},
|
|
GetContactCount: function () {
|
|
return this.m_contactManager.m_contactCount
|
|
},
|
|
GetTreeHeight: function () {
|
|
return this.m_contactManager.m_broadPhase.GetTreeHeight()
|
|
},
|
|
GetTreeBalance: function () {
|
|
return this.m_contactManager.m_broadPhase.GetTreeBalance()
|
|
},
|
|
GetTreeQuality: function () {
|
|
return this.m_contactManager.m_broadPhase.GetTreeQuality()
|
|
},
|
|
SetGravity: function (gravity) {
|
|
this.m_gravity = gravity
|
|
},
|
|
GetGravity: function () {
|
|
return this.m_gravity
|
|
},
|
|
IsLocked: function () {
|
|
return (this.m_flags & b2World.e_locked) == b2World.e_locked
|
|
},
|
|
SetAutoClearForces: function (flag) {
|
|
if (flag) {
|
|
this.m_flags |= b2World.e_clearForces
|
|
} else {
|
|
this.m_flags &= ~b2World.e_clearForces
|
|
}
|
|
},
|
|
GetAutoClearForces: function () {
|
|
return (this.m_flags & b2World.e_clearForces) == b2World.e_clearForces
|
|
},
|
|
ShiftOrigin: function (newOrigin) {
|
|
if ((this.m_flags & b2World.e_locked) == b2World.e_locked) {
|
|
return
|
|
}
|
|
for (var b = this.m_bodyList; b; b = b.m_next) {
|
|
b.m_xf.p.Subtract(newOrigin);
|
|
b.m_sweep.c0.Subtract(newOrigin);
|
|
b.m_sweep.c.Subtract(newOrigin)
|
|
}
|
|
for (var j = this.m_jointList; j; j = j.m_next) {
|
|
j.ShiftOrigin(newOrigin)
|
|
}
|
|
this.m_contactManager.m_broadPhase.ShiftOrigin(newOrigin)
|
|
},
|
|
GetContactManager: function () {
|
|
return this.m_contactManager
|
|
},
|
|
Solve: function (step) {
|
|
this.p_island.Initialize(this.m_bodyCount, this.m_contactManager.m_contactCount, this.m_jointCount, this.m_contactManager.m_contactListener);
|
|
for (var b = this.m_bodyList; b; b = b.m_next) {
|
|
b.m_flags &= ~b2Body.e_islandFlag
|
|
}
|
|
for (var c = this.m_contactManager.m_contactList; c; c = c.m_next) {
|
|
c.m_flags &= ~b2Contact.e_islandFlag
|
|
}
|
|
for (var j = this.m_jointList; j; j = j.m_next) {
|
|
j.m_islandFlag = false
|
|
}
|
|
var stackSize = this.m_bodyCount;
|
|
var stack = new Array(stackSize);
|
|
for (var seed = this.m_bodyList; seed; seed = seed.m_next) {
|
|
if (seed.m_flags & b2Body.e_islandFlag) {
|
|
continue
|
|
}
|
|
if (seed.IsAwake() == false || seed.IsActive() == false) {
|
|
continue
|
|
}
|
|
if (seed.GetType() == b2Body.b2_staticBody) {
|
|
continue
|
|
}
|
|
this.p_island.Clear();
|
|
var stackCount = 0;
|
|
stack[stackCount++] = seed;
|
|
seed.m_flags |= b2Body.e_islandFlag;
|
|
while (stackCount > 0) {
|
|
var b = stack[--stackCount];
|
|
this.p_island.AddBody(b);
|
|
b.SetAwake(true);
|
|
if (b.GetType() == b2Body.b2_staticBody) {
|
|
continue
|
|
}
|
|
for (var ce = b.m_contactList; ce; ce = ce.next) {
|
|
var contact = ce.contact;
|
|
if (contact.m_flags & b2Contact.e_islandFlag) {
|
|
continue
|
|
}
|
|
if (contact.IsEnabled() == false || contact.IsTouching() == false) {
|
|
continue
|
|
}
|
|
var sensorA = contact.m_fixtureA.m_isSensor;
|
|
var sensorB = contact.m_fixtureB.m_isSensor;
|
|
if (sensorA || sensorB) {
|
|
continue
|
|
}
|
|
this.p_island.AddContact(contact);
|
|
contact.m_flags |= b2Contact.e_islandFlag;
|
|
var other = ce.other;
|
|
if (other.m_flags & b2Body.e_islandFlag) {
|
|
continue
|
|
}
|
|
stack[stackCount++] = other;
|
|
other.m_flags |= b2Body.e_islandFlag
|
|
}
|
|
for (var je = b.m_jointList; je; je = je.next) {
|
|
if (je.joint.m_islandFlag == true) {
|
|
continue
|
|
}
|
|
var other = je.other;
|
|
if (other.IsActive() == false) {
|
|
continue
|
|
}
|
|
this.p_island.AddJoint(je.joint);
|
|
je.joint.m_islandFlag = true;
|
|
if (other.m_flags & b2Body.e_islandFlag) {
|
|
continue
|
|
}
|
|
stack[stackCount++] = other;
|
|
other.m_flags |= b2Body.e_islandFlag
|
|
}
|
|
}
|
|
this.p_island.Solve(step, this.m_gravity, this.m_allowSleep);
|
|
for (var i = 0; i < this.p_island.m_bodyCount; ++i) {
|
|
var b = this.p_island.m_bodies[i];
|
|
if (b.GetType() == b2Body.b2_staticBody) {
|
|
b.m_flags &= ~b2Body.e_islandFlag
|
|
}
|
|
}
|
|
}
|
|
profile_world_broadphase.start();
|
|
for (var b = this.m_bodyList; b; b = b.GetNext()) {
|
|
if ((b.m_flags & b2Body.e_islandFlag) == 0) {
|
|
continue
|
|
}
|
|
if (b.GetType() == b2Body.b2_staticBody) {
|
|
continue
|
|
}
|
|
b.SynchronizeFixtures()
|
|
}
|
|
this.m_contactManager.FindNewContacts();
|
|
profile_world_broadphase.stop()
|
|
},
|
|
SolveTOI: function (step) {
|
|
this.p_island.Initialize(2 * b2_maxTOIContacts, b2_maxTOIContacts, 0, this.m_contactManager.m_contactListener);
|
|
if (this.m_stepComplete) {
|
|
for (var b = this.m_bodyList; b; b = b.m_next) {
|
|
b.m_flags &= ~b2Body.e_islandFlag;
|
|
b.m_sweep.alpha0 = 0
|
|
}
|
|
for (var c = this.m_contactManager.m_contactList; c; c = c.m_next) {
|
|
c.m_flags &= ~(b2Contact.e_toiFlag | b2Contact.e_islandFlag);
|
|
c.m_toiCount = 0;
|
|
c.m_toi = 1
|
|
}
|
|
}
|
|
for (;;) {
|
|
var minContact = null;
|
|
var minAlpha = 1;
|
|
for (var c = this.m_contactManager.m_contactList; c; c = c.m_next) {
|
|
if (c.IsEnabled() == false) {
|
|
continue
|
|
}
|
|
if (c.m_toiCount > b2_maxSubSteps) {
|
|
continue
|
|
}
|
|
var alpha = 1;
|
|
if (c.m_flags & b2Contact.e_toiFlag) {
|
|
alpha = c.m_toi
|
|
} else {
|
|
var fA = c.GetFixtureA();
|
|
var fB = c.GetFixtureB();
|
|
if (fA.IsSensor() || fB.IsSensor()) {
|
|
continue
|
|
}
|
|
var bA = fA.GetBody();
|
|
var bB = fB.GetBody();
|
|
var typeA = bA.m_type;
|
|
var typeB = bB.m_type;
|
|
var activeA = bA.IsAwake() && typeA != b2Body.b2_staticBody;
|
|
var activeB = bB.IsAwake() && typeB != b2Body.b2_staticBody;
|
|
if (activeA == false && activeB == false) {
|
|
continue
|
|
}
|
|
var collideA = bA.IsBullet() || typeA != b2Body.b2_dynamicBody;
|
|
var collideB = bB.IsBullet() || typeB != b2Body.b2_dynamicBody;
|
|
if (collideA == false && collideB == false) {
|
|
continue
|
|
}
|
|
var alpha0 = bA.m_sweep.alpha0;
|
|
if (bA.m_sweep.alpha0 < bB.m_sweep.alpha0) {
|
|
alpha0 = bB.m_sweep.alpha0;
|
|
bA.m_sweep.Advance(alpha0)
|
|
} else {
|
|
if (bB.m_sweep.alpha0 < bA.m_sweep.alpha0) {
|
|
alpha0 = bA.m_sweep.alpha0;
|
|
bB.m_sweep.Advance(alpha0)
|
|
}
|
|
}
|
|
var indexA = c.GetChildIndexA();
|
|
var indexB = c.GetChildIndexB();
|
|
var input = new b2TOIInput();
|
|
input.proxyA.Set(fA.GetShape(), indexA);
|
|
input.proxyB.Set(fB.GetShape(), indexB);
|
|
input.sweepA.Assign(bA.m_sweep);
|
|
input.sweepB.Assign(bB.m_sweep);
|
|
input.tMax = 1;
|
|
var output = new b2TOIOutput();
|
|
b2TimeOfImpact(output, input);
|
|
var beta = output.t;
|
|
if (output.state == b2TOIOutput.e_touching) {
|
|
alpha = b2Min(alpha0 + (1 - alpha0) * beta, 1)
|
|
} else {
|
|
alpha = 1
|
|
}
|
|
c.m_toi = alpha;
|
|
c.m_flags |= b2Contact.e_toiFlag
|
|
}
|
|
if (alpha < minAlpha) {
|
|
minContact = c;
|
|
minAlpha = alpha
|
|
}
|
|
}
|
|
if (minContact == null || 1 - 10 * b2_epsilon < minAlpha) {
|
|
this.m_stepComplete = true;
|
|
break
|
|
}
|
|
var fA = minContact.GetFixtureA();
|
|
var fB = minContact.GetFixtureB();
|
|
var bA = fA.GetBody();
|
|
var bB = fB.GetBody();
|
|
b2World.m_local_sweep_backupA.Assign(bA.m_sweep);
|
|
b2World.m_local_sweep_backupB.Assign(bB.m_sweep);
|
|
bA.Advance(minAlpha);
|
|
bB.Advance(minAlpha);
|
|
minContact.Update(this.m_contactManager.m_contactListener);
|
|
minContact.m_flags &= ~b2Contact.e_toiFlag;
|
|
++minContact.m_toiCount;
|
|
if (minContact.IsEnabled() == false || minContact.IsTouching() == false) {
|
|
minContact.SetEnabled(false);
|
|
bA.m_sweep.Assign(b2World.m_local_sweep_backupA);
|
|
bB.m_sweep.Assign(b2World.m_local_sweep_backupB);
|
|
bA.SynchronizeTransform();
|
|
bB.SynchronizeTransform();
|
|
continue
|
|
}
|
|
bA.SetAwake(true);
|
|
bB.SetAwake(true);
|
|
this.p_island.Clear();
|
|
this.p_island.AddBody(bA);
|
|
this.p_island.AddBody(bB);
|
|
this.p_island.AddContact(minContact);
|
|
bA.m_flags |= b2Body.e_islandFlag;
|
|
bB.m_flags |= b2Body.e_islandFlag;
|
|
minContact.m_flags |= b2Contact.e_islandFlag;
|
|
var bodies = [bA, bB];
|
|
for (var i = 0; i < 2; ++i) {
|
|
var body = bodies[i];
|
|
if (body.m_type == b2Body.b2_dynamicBody) {
|
|
for (var ce = body.m_contactList; ce; ce = ce.next) {
|
|
if (this.p_island.m_bodyCount == this.p_island.m_bodyCapacity) {
|
|
break
|
|
}
|
|
if (this.p_island.m_contactCount == this.p_island.m_contactCapacity) {
|
|
break
|
|
}
|
|
var contact = ce.contact;
|
|
if (contact.m_flags & b2Contact.e_islandFlag) {
|
|
continue
|
|
}
|
|
var other = ce.other;
|
|
if (other.m_type == b2Body.b2_dynamicBody && body.IsBullet() == false && other.IsBullet() == false) {
|
|
continue
|
|
}
|
|
var sensorA = contact.m_fixtureA.m_isSensor;
|
|
var sensorB = contact.m_fixtureB.m_isSensor;
|
|
if (sensorA || sensorB) {
|
|
continue
|
|
}
|
|
b2World.m_local_sweep_backupC.Assign(other.m_sweep);
|
|
if ((other.m_flags & b2Body.e_islandFlag) == 0) {
|
|
other.Advance(minAlpha)
|
|
}
|
|
contact.Update(this.m_contactManager.m_contactListener);
|
|
if (contact.IsEnabled() == false) {
|
|
other.m_sweep.Assign(b2World.m_local_sweep_backupC);
|
|
other.SynchronizeTransform();
|
|
continue
|
|
}
|
|
if (contact.IsTouching() == false) {
|
|
other.m_sweep.Assign(b2World.m_local_sweep_backupC);
|
|
other.SynchronizeTransform();
|
|
continue
|
|
}
|
|
contact.m_flags |= b2Contact.e_islandFlag;
|
|
this.p_island.AddContact(contact);
|
|
if (other.m_flags & b2Body.e_islandFlag) {
|
|
continue
|
|
}
|
|
other.m_flags |= b2Body.e_islandFlag;
|
|
if (other.m_type != b2Body.b2_staticBody) {
|
|
other.SetAwake(true)
|
|
}
|
|
this.p_island.AddBody(other)
|
|
}
|
|
}
|
|
}
|
|
var subStep = new b2TimeStep();
|
|
subStep.dt = (1 - minAlpha) * step.dt;
|
|
subStep.inv_dt = 1 / subStep.dt;
|
|
subStep.dtRatio = 1;
|
|
subStep.positionIterations = 20;
|
|
subStep.velocityIterations = step.velocityIterations;
|
|
subStep.warmStarting = false;
|
|
this.p_island.SolveTOI(subStep, bA.m_islandIndex, bB.m_islandIndex);
|
|
for (var i = 0; i < this.p_island.m_bodyCount; ++i) {
|
|
var body = this.p_island.m_bodies[i];
|
|
body.m_flags &= ~b2Body.e_islandFlag;
|
|
if (body.m_type != b2Body.b2_dynamicBody) {
|
|
continue
|
|
}
|
|
body.SynchronizeFixtures();
|
|
for (var ce = body.m_contactList; ce; ce = ce.next) {
|
|
ce.contact.m_flags &= ~(b2Contact.e_toiFlag | b2Contact.e_islandFlag)
|
|
}
|
|
}
|
|
this.m_contactManager.FindNewContacts();
|
|
if (this.m_subStepping) {
|
|
this.m_stepComplete = false;
|
|
break
|
|
}
|
|
}
|
|
},
|
|
DrawJoint: function (joint) {
|
|
var bodyA = joint.GetBodyA();
|
|
var bodyB = joint.GetBodyB();
|
|
var xf1 = bodyA.GetTransform();
|
|
var xf2 = bodyB.GetTransform();
|
|
var x1 = xf1.p;
|
|
var x2 = xf2.p;
|
|
var p1 = joint.GetAnchorA();
|
|
var p2 = joint.GetAnchorB();
|
|
var color = new b2Color(0.5, 0.8, 0.8);
|
|
switch (joint.GetType()) {
|
|
case b2Joint.e_distanceJoint:
|
|
this.g_debugDraw.DrawSegment(p1, p2, color);
|
|
break;
|
|
case b2Joint.e_pulleyJoint:
|
|
var pulley = joint;
|
|
var s1 = pulley.GetGroundAnchorA();
|
|
var s2 = pulley.GetGroundAnchorB();
|
|
this.g_debugDraw.DrawSegment(s1, p1, color);
|
|
this.g_debugDraw.DrawSegment(s2, p2, color);
|
|
this.g_debugDraw.DrawSegment(s1, s2, color);
|
|
break;
|
|
case b2Joint.e_mouseJoint:
|
|
break;
|
|
case b2Joint.e_motorJoint:
|
|
this.g_debugDraw.DrawPoint(joint.GetLinearOffset(), 5, color);
|
|
default:
|
|
this.g_debugDraw.DrawSegment(x1, p1, color);
|
|
this.g_debugDraw.DrawSegment(p1, p2, color);
|
|
this.g_debugDraw.DrawSegment(x2, p2, color)
|
|
}
|
|
},
|
|
DrawShape: function (fixture, xf, color) {
|
|
switch (fixture.GetType()) {
|
|
case b2Shape.e_circle:
|
|
var circle = fixture.GetShape();
|
|
var center = b2Mul_t_v2(xf, circle.m_p);
|
|
var radius = circle.m_radius;
|
|
var axis = b2Mul_r_v2(xf.q, new b2Vec2(1, 0));
|
|
this.g_debugDraw.DrawSolidCircle(center, radius, axis, color);
|
|
break;
|
|
case b2Shape.e_edge:
|
|
var edge = fixture.GetShape();
|
|
var v1 = b2Mul_t_v2(xf, edge.m_vertex1);
|
|
var v2 = b2Mul_t_v2(xf, edge.m_vertex2);
|
|
this.g_debugDraw.DrawSegment(v1, v2, color);
|
|
break;
|
|
case b2Shape.e_chain:
|
|
var chain = fixture.GetShape();
|
|
var count = chain.m_count;
|
|
var vertices = chain.m_vertices;
|
|
var v1 = b2Mul_t_v2(xf, vertices[0]);
|
|
for (var i = 1; i < count; ++i) {
|
|
var v2 = b2Mul_t_v2(xf, vertices[i]);
|
|
this.g_debugDraw.DrawSegment(v1, v2, color);
|
|
v1 = v2
|
|
}
|
|
break;
|
|
case b2Shape.e_polygon:
|
|
var poly = fixture.GetShape();
|
|
var vertexCount = poly.m_count;
|
|
var vertices = new Array(b2_maxPolygonVertices);
|
|
for (var i = 0; i < vertexCount; ++i) {
|
|
vertices[i] = b2Mul_t_v2(xf, poly.m_vertices[i])
|
|
}
|
|
this.g_debugDraw.DrawSolidPolygon(vertices, vertexCount, color);
|
|
break;
|
|
default:
|
|
break
|
|
}
|
|
}
|
|
};
|
|
b2World.e_newFixture = 1;
|
|
b2World.e_locked = 2;
|
|
b2World.e_clearForces = 4;
|
|
"use strict";
|
|
|
|
function b2MixFriction(friction1, friction2) {
|
|
return b2Sqrt(friction1 * friction2)
|
|
}
|
|
|
|
function b2MixRestitution(restitution1, restitution2) {
|
|
return restitution1 > restitution2 ? restitution1 : restitution2
|
|
}
|
|
|
|
function b2ContactRegister() {
|
|
this.fcn = null;
|
|
this.primary = false
|
|
}
|
|
|
|
function b2ContactEdge() {
|
|
this.other = null;
|
|
this.contact = null;
|
|
this.prev = null;
|
|
this.next = null
|
|
}
|
|
|
|
function b2Contact() {
|
|
this.m_nodeA = new b2ContactEdge();
|
|
this.m_nodeB = new b2ContactEdge();
|
|
this.m_manifold = new b2Manifold()
|
|
}
|
|
b2Contact.m_local_tempManifold = new b2Manifold();
|
|
b2Contact.prototype = {
|
|
Create: function (fA, indexA, fB, indexB) {
|
|
this.m_toi = 0;
|
|
this.m_flags = b2Contact.e_enabledFlag;
|
|
this.m_fixtureA = fA || null;
|
|
this.m_fixtureB = fB || null;
|
|
this.m_indexA = indexA || 0;
|
|
this.m_indexB = indexB || 0;
|
|
this.m_manifold.pointCount = 0;
|
|
this.m_prev = null;
|
|
this.m_next = null;
|
|
this.m_nodeA.contact = null;
|
|
this.m_nodeA.prev = null;
|
|
this.m_nodeA.next = null;
|
|
this.m_nodeA.other = null;
|
|
this.m_nodeB.contact = null;
|
|
this.m_nodeB.prev = null;
|
|
this.m_nodeB.next = null;
|
|
this.m_nodeB.other = null;
|
|
this.m_toiCount = 0;
|
|
if (fA) {
|
|
this.m_friction = b2MixFriction(this.m_fixtureA.m_friction, this.m_fixtureB.m_friction);
|
|
this.m_restitution = b2MixRestitution(this.m_fixtureA.m_restitution, this.m_fixtureB.m_restitution)
|
|
} else {
|
|
this.m_friction = 0;
|
|
this.m_restitution = 0
|
|
}
|
|
this.m_tangentSpeed = 0
|
|
},
|
|
GetManifold: function () {
|
|
return this.m_manifold
|
|
},
|
|
GetWorldManifold: function (worldManifold) {
|
|
var bodyA = this.m_fixtureA.GetBody();
|
|
var bodyB = this.m_fixtureB.GetBody();
|
|
var shapeA = this.m_fixtureA.GetShape();
|
|
var shapeB = this.m_fixtureB.GetShape();
|
|
worldManifold.Initialize(this.m_manifold, bodyA.GetTransform(), shapeA.m_radius, bodyB.GetTransform(), shapeB.m_radius)
|
|
},
|
|
IsTouching: function () {
|
|
return (this.m_flags & b2Contact.e_touchingFlag) == b2Contact.e_touchingFlag
|
|
},
|
|
SetEnabled: function (flag) {
|
|
if (flag) {
|
|
this.m_flags |= b2Contact.e_enabledFlag
|
|
} else {
|
|
this.m_flags &= ~b2Contact.e_enabledFlag
|
|
}
|
|
},
|
|
IsEnabled: function () {
|
|
return (this.m_flags & b2Contact.e_enabledFlag) == b2Contact.e_enabledFlag
|
|
},
|
|
GetNext: function () {
|
|
return this.m_next
|
|
},
|
|
GetFixtureA: function () {
|
|
return this.m_fixtureA
|
|
},
|
|
GetChildIndexA: function () {
|
|
return this.m_indexA
|
|
},
|
|
GetFixtureB: function () {
|
|
return this.m_fixtureB
|
|
},
|
|
GetChildIndexB: function () {
|
|
return this.m_indexB
|
|
},
|
|
SetFriction: function (friction) {
|
|
this.m_friction = friction
|
|
},
|
|
GetFriction: function () {
|
|
return this.m_friction
|
|
},
|
|
ResetFriction: function () {
|
|
this.m_friction = b2MixFriction(this.m_fixtureA.m_friction, this.m_fixtureB.m_friction)
|
|
},
|
|
SetRestitution: function (restitution) {
|
|
this.m_restitution = restitution
|
|
},
|
|
GetRestitution: function () {
|
|
return this.m_restitution
|
|
},
|
|
ResetRestitution: function () {
|
|
this.m_restitution = b2MixRestitution(this.m_fixtureA.m_restitution, this.m_fixtureB.m_restitution)
|
|
},
|
|
SetTangentSpeed: function (speed) {
|
|
this.m_tangentSpeed = speed
|
|
},
|
|
GetTangentSpeed: function () {
|
|
return this.m_tangentSpeed
|
|
},
|
|
Evaluate: function (manifold, xfA, xfB) {},
|
|
FlagForFiltering: function () {
|
|
this.m_flags |= b2Contact.e_filterFlag
|
|
},
|
|
m_oldManifold: null,
|
|
Update: function (listener) {
|
|
b2Contact.m_local_tempManifold.Assign(this.m_manifold);
|
|
this.m_flags |= b2Contact.e_enabledFlag;
|
|
var touching = false;
|
|
var wasTouching = (this.m_flags & b2Contact.e_touchingFlag) == b2Contact.e_touchingFlag;
|
|
var sensorA = this.m_fixtureA.IsSensor();
|
|
var sensorB = this.m_fixtureB.IsSensor();
|
|
var sensor = sensorA || sensorB;
|
|
var bodyA = this.m_fixtureA.GetBody();
|
|
var bodyB = this.m_fixtureB.GetBody();
|
|
var xfA = bodyA.GetTransform();
|
|
var xfB = bodyB.GetTransform();
|
|
if (sensor) {
|
|
var shapeA = this.m_fixtureA.GetShape();
|
|
var shapeB = this.m_fixtureB.GetShape();
|
|
touching = b2TestShapeOverlap(shapeA, this.m_indexA, shapeB, this.m_indexB, xfA, xfB);
|
|
this.m_manifold.pointCount = 0
|
|
} else {
|
|
this.Evaluate(this.m_manifold, xfA, xfB);
|
|
touching = this.m_manifold.pointCount > 0;
|
|
for (var i = 0; i < this.m_manifold.pointCount; ++i) {
|
|
var mp2 = this.m_manifold.points[i];
|
|
mp2.normalImpulse = 0;
|
|
mp2.tangentImpulse = 0;
|
|
var id2 = mp2.id;
|
|
for (var j = 0; j < b2Contact.m_local_tempManifold.pointCount; ++j) {
|
|
var mp1 = b2Contact.m_local_tempManifold.points[j];
|
|
if (mp1.id.Get() == id2.Get()) {
|
|
mp2.normalImpulse = mp1.normalImpulse;
|
|
mp2.tangentImpulse = mp1.tangentImpulse;
|
|
break
|
|
}
|
|
}
|
|
}
|
|
if (touching != wasTouching) {
|
|
bodyA.SetAwake(true);
|
|
bodyB.SetAwake(true)
|
|
}
|
|
}
|
|
if (touching) {
|
|
this.m_flags |= b2Contact.e_touchingFlag
|
|
} else {
|
|
this.m_flags &= ~b2Contact.e_touchingFlag
|
|
}
|
|
if (wasTouching == false && touching == true && listener) {
|
|
listener.BeginContact(this)
|
|
}
|
|
if (wasTouching == true && touching == false && listener) {
|
|
listener.EndContact(this)
|
|
}
|
|
if (sensor == false && touching && listener) {
|
|
listener.PreSolve(this, b2Contact.m_local_tempManifold)
|
|
}
|
|
}
|
|
};
|
|
b2Contact.e_islandFlag = 1;
|
|
b2Contact.e_touchingFlag = 2;
|
|
b2Contact.e_enabledFlag = 4;
|
|
b2Contact.e_filterFlag = 8;
|
|
b2Contact.e_bulletHitFlag = 16;
|
|
b2Contact.e_toiFlag = 32;
|
|
|
|
function b2CircleContact() {
|
|
this.parent.call(this)
|
|
}
|
|
b2CircleContact.prototype = {
|
|
Evaluate: function (manifold, xfA, xfB) {
|
|
b2CollideCircles(manifold, this.m_fixtureA.GetShape(), xfA, this.m_fixtureB.GetShape(), xfB)
|
|
},
|
|
Create: function (fixtureA, unused1, fixtureB, unused2) {
|
|
this.parent.prototype.Create.call(this, fixtureA, 0, fixtureB, 0)
|
|
}
|
|
};
|
|
b2CircleContact._extend(b2Contact);
|
|
var _local_temp_edgeShape = new b2EdgeShape();
|
|
|
|
function b2ChainAndCircleContact() {
|
|
this.parent.call(this)
|
|
}
|
|
b2ChainAndCircleContact.prototype = {
|
|
Evaluate: function (manifold, xfA, xfB) {
|
|
var chain = this.m_fixtureA.GetShape();
|
|
chain.GetChildEdge(_local_temp_edgeShape, this.m_indexA);
|
|
b2CollideEdgeAndCircle(manifold, _local_temp_edgeShape, xfA, this.m_fixtureB.GetShape(), xfB)
|
|
},
|
|
Create: function (fixtureA, indexA, fixtureB, indexB) {
|
|
this.parent.prototype.Create.call(this, fixtureA, indexA, fixtureB, indexB)
|
|
}
|
|
};
|
|
b2ChainAndCircleContact._extend(b2Contact);
|
|
|
|
function b2ChainAndPolygonContact() {
|
|
this.parent.call(this)
|
|
}
|
|
b2ChainAndPolygonContact.prototype = {
|
|
Evaluate: function (manifold, xfA, xfB) {
|
|
var chain = this.m_fixtureA.GetShape();
|
|
chain.GetChildEdge(_local_temp_edgeShape, this.m_indexA);
|
|
b2CollideEdgeAndPolygon(manifold, _local_temp_edgeShape, xfA, this.m_fixtureB.GetShape(), xfB)
|
|
},
|
|
Create: function (fixtureA, indexA, fixtureB, indexB) {
|
|
this.parent.prototype.Create.call(this, fixtureA, indexA, fixtureB, indexB)
|
|
}
|
|
};
|
|
b2ChainAndPolygonContact.Create = function (fixtureA, indexA, fixtureB, indexB) {
|
|
return new b2ChainAndPolygonContact(fixtureA, indexA, fixtureB, indexB)
|
|
};
|
|
b2ChainAndPolygonContact._extend(b2Contact);
|
|
|
|
function b2EdgeAndCircleContact() {
|
|
this.parent.call(this)
|
|
}
|
|
b2EdgeAndCircleContact.prototype = {
|
|
Evaluate: function (manifold, xfA, xfB) {
|
|
b2CollideEdgeAndCircle(manifold, this.m_fixtureA.GetShape(), xfA, this.m_fixtureB.GetShape(), xfB)
|
|
},
|
|
Create: function (fixtureA, indexA, fixtureB, indexB) {
|
|
this.parent.prototype.Create.call(this, fixtureA, 0, fixtureB, 0)
|
|
}
|
|
};
|
|
b2EdgeAndCircleContact.Create = function (fixtureA, indexA, fixtureB, indexB) {
|
|
return new b2EdgeAndCircleContact(fixtureA, fixtureB)
|
|
};
|
|
b2EdgeAndCircleContact._extend(b2Contact);
|
|
|
|
function b2EdgeAndPolygonContact() {
|
|
this.parent.call(this)
|
|
}
|
|
b2EdgeAndPolygonContact.prototype = {
|
|
Evaluate: function (manifold, xfA, xfB) {
|
|
b2CollideEdgeAndPolygon(manifold, this.m_fixtureA.GetShape(), xfA, this.m_fixtureB.GetShape(), xfB)
|
|
},
|
|
Create: function (fixtureA, indexA, fixtureB, indexB) {
|
|
this.parent.prototype.Create.call(this, fixtureA, 0, fixtureB, 0)
|
|
}
|
|
};
|
|
b2EdgeAndPolygonContact.Create = function (fixtureA, indexA, fixtureB, indexB) {
|
|
return new b2EdgeAndPolygonContact(fixtureA, fixtureB)
|
|
};
|
|
b2EdgeAndPolygonContact._extend(b2Contact);
|
|
|
|
function b2PolygonAndCircleContact() {
|
|
this.parent.call(this)
|
|
}
|
|
b2PolygonAndCircleContact.prototype = {
|
|
Evaluate: function (manifold, xfA, xfB) {
|
|
b2CollidePolygonAndCircle(manifold, this.m_fixtureA.GetShape(), xfA, this.m_fixtureB.GetShape(), xfB)
|
|
},
|
|
Create: function (fixtureA, indexA, fixtureB, indexB) {
|
|
this.parent.prototype.Create.call(this, fixtureA, 0, fixtureB, 0)
|
|
}
|
|
};
|
|
b2PolygonAndCircleContact.Create = function (fixtureA, indexA, fixtureB, indexB) {
|
|
return new b2PolygonAndCircleContact(fixtureA, fixtureB)
|
|
};
|
|
b2PolygonAndCircleContact._extend(b2Contact);
|
|
|
|
function b2PolygonContact() {
|
|
this.parent.call(this)
|
|
}
|
|
b2PolygonContact.prototype = {
|
|
Evaluate: function (manifold, xfA, xfB) {
|
|
b2CollidePolygons(manifold, this.m_fixtureA.GetShape(), xfA, this.m_fixtureB.GetShape(), xfB)
|
|
},
|
|
Create: function (fixtureA, indexA, fixtureB, indexB) {
|
|
this.parent.prototype.Create.call(this, fixtureA, 0, fixtureB, 0)
|
|
}
|
|
};
|
|
b2PolygonContact.Create = function (fixtureA, indexA, fixtureB, indexB) {
|
|
return new b2PolygonContact(fixtureA, fixtureB)
|
|
};
|
|
b2PolygonContact._extend(b2Contact);
|
|
b2Contact.AddType = function (fcn, type1, type2) {
|
|
if (!b2Contact.s_registers[type1]) {
|
|
b2Contact.s_registers[type1] = []
|
|
}
|
|
b2Contact.s_registers[type1][type2] = new b2ContactRegister();
|
|
b2Contact.s_registers[type1][type2].fcn = fcn;
|
|
b2Contact.s_registers[type1][type2].primary = true;
|
|
if (type1 != type2) {
|
|
if (!b2Contact.s_registers[type2]) {
|
|
b2Contact.s_registers[type2] = []
|
|
}
|
|
b2Contact.s_registers[type2][type1] = new b2ContactRegister();
|
|
b2Contact.s_registers[type2][type1].fcn = fcn;
|
|
b2Contact.s_registers[type2][type1].primary = false
|
|
}
|
|
fcn.garbage = [];
|
|
fcn.alloc = 2
|
|
};
|
|
b2Contact.InitializeRegisters = function () {
|
|
b2Contact.AddType(b2CircleContact, b2Shape.e_circle, b2Shape.e_circle);
|
|
b2Contact.AddType(b2PolygonAndCircleContact, b2Shape.e_polygon, b2Shape.e_circle);
|
|
b2Contact.AddType(b2PolygonContact, b2Shape.e_polygon, b2Shape.e_polygon);
|
|
b2Contact.AddType(b2EdgeAndCircleContact, b2Shape.e_edge, b2Shape.e_circle);
|
|
b2Contact.AddType(b2EdgeAndPolygonContact, b2Shape.e_edge, b2Shape.e_polygon);
|
|
b2Contact.AddType(b2ChainAndCircleContact, b2Shape.e_chain, b2Shape.e_circle);
|
|
b2Contact.AddType(b2ChainAndPolygonContact, b2Shape.e_chain, b2Shape.e_polygon)
|
|
};
|
|
b2Contact.RetrieveGarbage = function (fcn) {
|
|
var contact;
|
|
if (contact = fcn.garbage.pop()) {
|
|
return contact
|
|
}
|
|
for (var i = 0; i < fcn.alloc - 1; ++i) {
|
|
fcn.garbage.push(new fcn())
|
|
}
|
|
fcn.alloc += 32;
|
|
return new fcn()
|
|
};
|
|
b2Contact.Create = function (fixtureA, indexA, fixtureB, indexB) {
|
|
if (b2Contact.s_initialized == false) {
|
|
b2Contact.InitializeRegisters();
|
|
b2Contact.s_initialized = true
|
|
}
|
|
var type1 = fixtureA.GetType();
|
|
var type2 = fixtureB.GetType();
|
|
var fcn = b2Contact.s_registers[type1][type2].fcn;
|
|
if (fcn) {
|
|
var contact = b2Contact.RetrieveGarbage(fcn);
|
|
if (b2Contact.s_registers[type1][type2].primary) {
|
|
contact.Create(fixtureA, indexA, fixtureB, indexB)
|
|
} else {
|
|
contact.Create(fixtureB, indexB, fixtureA, indexA)
|
|
}
|
|
return contact
|
|
}
|
|
return null
|
|
};
|
|
b2Contact.Destroy = function (contact) {
|
|
var fixtureA = contact.m_fixtureA;
|
|
var fixtureB = contact.m_fixtureB;
|
|
if (contact.m_manifold.pointCount > 0 && fixtureA.IsSensor() == false && fixtureB.IsSensor() == false) {
|
|
fixtureA.GetBody().SetAwake(true);
|
|
fixtureB.GetBody().SetAwake(true)
|
|
}
|
|
var typeA = fixtureA.GetType();
|
|
var typeB = fixtureB.GetType();
|
|
b2Contact.s_registers[typeA][typeB].fcn.garbage.push(contact)
|
|
};
|
|
b2Contact.s_registers = [];
|
|
b2Contact.s_initialized = false;
|
|
"use strict";
|
|
var b2_defaultFilter = new b2ContactFilter();
|
|
var b2_defaultListener = new b2ContactListener();
|
|
|
|
function b2ContactManager() {
|
|
this.m_broadPhase = new b2BroadPhase();
|
|
this.m_contactList = null;
|
|
this.m_contactCount = 0;
|
|
this.m_contactFilter = b2_defaultFilter;
|
|
this.m_contactListener = b2_defaultListener
|
|
}
|
|
b2ContactManager.prototype = {
|
|
AddPair: function (proxyUserDataA, proxyUserDataB) {
|
|
var proxyA = proxyUserDataA;
|
|
var proxyB = proxyUserDataB;
|
|
var fixtureA = proxyA.fixture;
|
|
var fixtureB = proxyB.fixture;
|
|
var indexA = proxyA.childIndex;
|
|
var indexB = proxyB.childIndex;
|
|
var bodyA = fixtureA.GetBody();
|
|
var bodyB = fixtureB.GetBody();
|
|
if (bodyA == bodyB) {
|
|
return
|
|
}
|
|
var edge = bodyB.GetContactList();
|
|
while (edge) {
|
|
if (edge.other == bodyA) {
|
|
var fA = edge.contact.GetFixtureA();
|
|
var fB = edge.contact.GetFixtureB();
|
|
var iA = edge.contact.GetChildIndexA();
|
|
var iB = edge.contact.GetChildIndexB();
|
|
if (fA == fixtureA && fB == fixtureB && iA == indexA && iB == indexB) {
|
|
return
|
|
}
|
|
if (fA == fixtureB && fB == fixtureA && iA == indexB && iB == indexA) {
|
|
return
|
|
}
|
|
}
|
|
edge = edge.next
|
|
}
|
|
if (bodyB.ShouldCollide(bodyA) == false) {
|
|
return
|
|
}
|
|
if (this.m_contactFilter && this.m_contactFilter.ShouldCollide(fixtureA, fixtureB) == false) {
|
|
return
|
|
}
|
|
var c = b2Contact.Create(fixtureA, indexA, fixtureB, indexB);
|
|
if (c == null) {
|
|
return
|
|
}
|
|
fixtureA = c.GetFixtureA();
|
|
fixtureB = c.GetFixtureB();
|
|
indexA = c.GetChildIndexA();
|
|
indexB = c.GetChildIndexB();
|
|
bodyA = fixtureA.GetBody();
|
|
bodyB = fixtureB.GetBody();
|
|
c.m_prev = null;
|
|
c.m_next = this.m_contactList;
|
|
if (this.m_contactList != null) {
|
|
this.m_contactList.m_prev = c
|
|
}
|
|
this.m_contactList = c;
|
|
c.m_nodeA.contact = c;
|
|
c.m_nodeA.other = bodyB;
|
|
c.m_nodeA.prev = null;
|
|
c.m_nodeA.next = bodyA.m_contactList;
|
|
if (bodyA.m_contactList != null) {
|
|
bodyA.m_contactList.prev = c.m_nodeA
|
|
}
|
|
bodyA.m_contactList = c.m_nodeA;
|
|
c.m_nodeB.contact = c;
|
|
c.m_nodeB.other = bodyA;
|
|
c.m_nodeB.prev = null;
|
|
c.m_nodeB.next = bodyB.m_contactList;
|
|
if (bodyB.m_contactList != null) {
|
|
bodyB.m_contactList.prev = c.m_nodeB
|
|
}
|
|
bodyB.m_contactList = c.m_nodeB;
|
|
if (fixtureA.IsSensor() == false && fixtureB.IsSensor() == false) {
|
|
bodyA.SetAwake(true);
|
|
bodyB.SetAwake(true)
|
|
}++this.m_contactCount
|
|
},
|
|
FindNewContacts: function () {
|
|
this.m_broadPhase.UpdatePairs(this)
|
|
},
|
|
Destroy: function (c) {
|
|
var fixtureA = c.GetFixtureA();
|
|
var fixtureB = c.GetFixtureB();
|
|
var bodyA = fixtureA.GetBody();
|
|
var bodyB = fixtureB.GetBody();
|
|
if (this.m_contactListener && c.IsTouching()) {
|
|
this.m_contactListener.EndContact(c)
|
|
}
|
|
if (c.m_prev) {
|
|
c.m_prev.m_next = c.m_next
|
|
}
|
|
if (c.m_next) {
|
|
c.m_next.m_prev = c.m_prev
|
|
}
|
|
if (c == this.m_contactList) {
|
|
this.m_contactList = c.m_next
|
|
}
|
|
if (c.m_nodeA.prev) {
|
|
c.m_nodeA.prev.next = c.m_nodeA.next
|
|
}
|
|
if (c.m_nodeA.next) {
|
|
c.m_nodeA.next.prev = c.m_nodeA.prev
|
|
}
|
|
if (c.m_nodeA == bodyA.m_contactList) {
|
|
bodyA.m_contactList = c.m_nodeA.next
|
|
}
|
|
if (c.m_nodeB.prev) {
|
|
c.m_nodeB.prev.next = c.m_nodeB.next
|
|
}
|
|
if (c.m_nodeB.next) {
|
|
c.m_nodeB.next.prev = c.m_nodeB.prev
|
|
}
|
|
if (c.m_nodeB == bodyB.m_contactList) {
|
|
bodyB.m_contactList = c.m_nodeB.next
|
|
}
|
|
b2Contact.Destroy(c);
|
|
--this.m_contactCount
|
|
},
|
|
Collide: function () {
|
|
var c = this.m_contactList;
|
|
while (c) {
|
|
var fixtureA = c.GetFixtureA();
|
|
var fixtureB = c.GetFixtureB();
|
|
var indexA = c.GetChildIndexA();
|
|
var indexB = c.GetChildIndexB();
|
|
var bodyA = fixtureA.GetBody();
|
|
var bodyB = fixtureB.GetBody();
|
|
if (c.m_flags & b2Contact.e_filterFlag) {
|
|
if (bodyB.ShouldCollide(bodyA) == false) {
|
|
var cNuke = c;
|
|
c = cNuke.GetNext();
|
|
this.Destroy(cNuke);
|
|
continue
|
|
}
|
|
if (this.m_contactFilter && this.m_contactFilter.ShouldCollide(fixtureA, fixtureB) == false) {
|
|
var cNuke = c;
|
|
c = cNuke.GetNext();
|
|
this.Destroy(cNuke);
|
|
continue
|
|
}
|
|
c.m_flags &= ~b2Contact.e_filterFlag
|
|
}
|
|
var activeA = bodyA.IsAwake() && bodyA.m_type != b2Body.b2_staticBody;
|
|
var activeB = bodyB.IsAwake() && bodyB.m_type != b2Body.b2_staticBody;
|
|
if (activeA == false && activeB == false) {
|
|
c = c.GetNext();
|
|
continue
|
|
}
|
|
var proxyIdA = fixtureA.m_proxies[indexA].proxyId;
|
|
var proxyIdB = fixtureB.m_proxies[indexB].proxyId;
|
|
var overlap = this.m_broadPhase.TestOverlap(proxyIdA, proxyIdB);
|
|
if (overlap == false) {
|
|
var cNuke = c;
|
|
c = cNuke.GetNext();
|
|
this.Destroy(cNuke);
|
|
continue
|
|
}
|
|
c.Update(this.m_contactListener);
|
|
c = c.GetNext()
|
|
}
|
|
}
|
|
};
|
|
|
|
function b2VelocityConstraintPoint() {
|
|
this.rA = new b2Vec2();
|
|
this.rB = new b2Vec2();
|
|
this.normalImpulse = 0;
|
|
this.tangentImpulse = 0;
|
|
this.normalMass = 0;
|
|
this.tangentMass = 0;
|
|
this.velocityBias = 0
|
|
}
|
|
|
|
function b2ContactPositionConstraint() {
|
|
this.localPoints = new Array(b2_maxManifoldPoints);
|
|
this.localNormal = new b2Vec2();
|
|
this.localPoint = new b2Vec2();
|
|
this.indexA = 0;
|
|
this.indexB = 0;
|
|
this.invMassA = 0, this.invMassB = 0;
|
|
this.localCenterA = new b2Vec2(), this.localCenterB = new b2Vec2();
|
|
this.invIA = 0, this.invIB = 0;
|
|
this.type = 0;
|
|
this.radiusA = 0, this.radiusB = 0;
|
|
this.pointCount = 0
|
|
}
|
|
|
|
function b2ContactVelocityConstraint() {
|
|
this.points = new Array(b2_maxManifoldPoints);
|
|
for (var i = 0; i < this.points.length; ++i) {
|
|
this.points[i] = new b2VelocityConstraintPoint()
|
|
}
|
|
this.normal = new b2Vec2();
|
|
this.normalMass = new b2Mat22();
|
|
this.K = new b2Mat22();
|
|
this.indexA = 0;
|
|
this.indexB = 0;
|
|
this.invMassA = 0, this.invMassB = 0;
|
|
this.invIA = 0, this.invIB = 0;
|
|
this.friction = 0;
|
|
this.restitution = 0;
|
|
this.tangentSpeed = 0;
|
|
this.pointCount = 0;
|
|
this.contactIndex = 0
|
|
}
|
|
|
|
function b2PositionSolverManifold() {
|
|
this.normal = new b2Vec2();
|
|
this.point = new b2Vec2();
|
|
this.separation = 0
|
|
}
|
|
b2PositionSolverManifold.prototype = {
|
|
Initialize: function (pc, xfA, xfB, index) {
|
|
switch (pc.type) {
|
|
case b2Manifold.e_circles:
|
|
var pointAx = (xfA.q.c * pc.localPoint.x - xfA.q.s * pc.localPoint.y) + xfA.p.x;
|
|
var pointAy = (xfA.q.s * pc.localPoint.x + xfA.q.c * pc.localPoint.y) + xfA.p.y;
|
|
var pointBx = (xfB.q.c * pc.localPoints[0].x - xfB.q.s * pc.localPoints[0].y) + xfB.p.x;
|
|
var pointBy = (xfB.q.s * pc.localPoints[0].x + xfB.q.c * pc.localPoints[0].y) + xfB.p.y;
|
|
this.point.x = 0.5 * (pointAx + pointBx);
|
|
this.point.y = 0.5 * (pointAy + pointBy);
|
|
this.normal.x = pointBx - pointAx;
|
|
this.normal.y = pointBy - pointAy;
|
|
var tempnx = this.normal.x;
|
|
var tempny = this.normal.y;
|
|
this.normal.Normalize();
|
|
this.separation = (tempnx * this.normal.x + tempny * this.normal.y) - pc.radiusA - pc.radiusB;
|
|
break;
|
|
case b2Manifold.e_faceA:
|
|
this.normal.x = xfA.q.c * pc.localNormal.x - xfA.q.s * pc.localNormal.y;
|
|
this.normal.y = xfA.q.s * pc.localNormal.x + xfA.q.c * pc.localNormal.y;
|
|
var planePointx = (xfA.q.c * pc.localPoint.x - xfA.q.s * pc.localPoint.y) + xfA.p.x;
|
|
var planePointy = (xfA.q.s * pc.localPoint.x + xfA.q.c * pc.localPoint.y) + xfA.p.y;
|
|
var clipPointx = (xfB.q.c * pc.localPoints[index].x - xfB.q.s * pc.localPoints[index].y) + xfB.p.x;
|
|
var clipPointy = (xfB.q.s * pc.localPoints[index].x + xfB.q.c * pc.localPoints[index].y) + xfB.p.y;
|
|
this.separation = ((clipPointx - planePointx) * this.normal.x + (clipPointy - planePointy) * this.normal.y) - pc.radiusA - pc.radiusB;
|
|
this.point.x = clipPointx;
|
|
this.point.y = clipPointy;
|
|
break;
|
|
case b2Manifold.e_faceB:
|
|
this.normal.x = xfB.q.c * pc.localNormal.x - xfB.q.s * pc.localNormal.y;
|
|
this.normal.y = xfB.q.s * pc.localNormal.x + xfB.q.c * pc.localNormal.y;
|
|
var planePointx = (xfB.q.c * pc.localPoint.x - xfB.q.s * pc.localPoint.y) + xfB.p.x;
|
|
var planePointy = (xfB.q.s * pc.localPoint.x + xfB.q.c * pc.localPoint.y) + xfB.p.y;
|
|
var clipPointx = (xfA.q.c * pc.localPoints[index].x - xfA.q.s * pc.localPoints[index].y) + xfA.p.x;
|
|
var clipPointy = (xfA.q.s * pc.localPoints[index].x + xfA.q.c * pc.localPoints[index].y) + xfA.p.y;
|
|
this.separation = ((clipPointx - planePointx) * this.normal.x + (clipPointy - planePointy) * this.normal.y) - pc.radiusA - pc.radiusB;
|
|
this.point.x = clipPointx;
|
|
this.point.y = clipPointy;
|
|
this.normal.x = -this.normal.x;
|
|
this.normal.y = -this.normal.y;
|
|
break
|
|
}
|
|
}
|
|
};
|
|
|
|
function b2ContactSolverDef() {
|
|
this.step = new b2TimeStep();
|
|
this.contacts = null;
|
|
this.count = 0;
|
|
this.positions = null;
|
|
this.velocities = null
|
|
}
|
|
|
|
function b2ContactSolver() {
|
|
this.m_positionConstraints = [];
|
|
this.m_velocityConstraints = []
|
|
}
|
|
b2ContactSolver.cs_xfA = new b2Transform();
|
|
b2ContactSolver.cs_xfB = new b2Transform();
|
|
b2ContactSolver.temp_solver_manifold = new b2PositionSolverManifold();
|
|
b2ContactSolver.prototype = {
|
|
Init: function (def) {
|
|
this.m_step = def.step;
|
|
this.m_count = def.count;
|
|
this.m_positionConstraints.length = this.m_count;
|
|
this.m_velocityConstraints.length = this.m_count;
|
|
this.m_positions = def.positions;
|
|
this.m_velocities = def.velocities;
|
|
this.m_contacts = def.contacts;
|
|
for (var i = 0; i < this.m_count; ++i) {
|
|
var contact = this.m_contacts[i];
|
|
var fixtureA = contact.m_fixtureA;
|
|
var fixtureB = contact.m_fixtureB;
|
|
var shapeA = fixtureA.GetShape();
|
|
var shapeB = fixtureB.GetShape();
|
|
var radiusA = shapeA.m_radius;
|
|
var radiusB = shapeB.m_radius;
|
|
var bodyA = fixtureA.GetBody();
|
|
var bodyB = fixtureB.GetBody();
|
|
var manifold = contact.GetManifold();
|
|
var pointCount = manifold.pointCount;
|
|
var vc = this.m_velocityConstraints[i] || new b2ContactVelocityConstraint();
|
|
vc.friction = contact.m_friction;
|
|
vc.restitution = contact.m_restitution;
|
|
vc.tangentSpeed = contact.m_tangentSpeed;
|
|
vc.indexA = bodyA.m_islandIndex;
|
|
vc.indexB = bodyB.m_islandIndex;
|
|
vc.invMassA = bodyA.m_invMass;
|
|
vc.invMassB = bodyB.m_invMass;
|
|
vc.invIA = bodyA.m_invI;
|
|
vc.invIB = bodyB.m_invI;
|
|
vc.contactIndex = i;
|
|
vc.pointCount = pointCount;
|
|
vc.K.SetZero();
|
|
vc.normalMass.SetZero();
|
|
this.m_velocityConstraints[i] = vc;
|
|
var pc = this.m_positionConstraints[i] || new b2ContactPositionConstraint();
|
|
pc.indexA = bodyA.m_islandIndex;
|
|
pc.indexB = bodyB.m_islandIndex;
|
|
pc.invMassA = bodyA.m_invMass;
|
|
pc.invMassB = bodyB.m_invMass;
|
|
pc.localCenterA.x = bodyA.m_sweep.localCenter.x;
|
|
pc.localCenterA.y = bodyA.m_sweep.localCenter.y;
|
|
pc.localCenterB.x = bodyB.m_sweep.localCenter.x;
|
|
pc.localCenterB.y = bodyB.m_sweep.localCenter.y;
|
|
pc.invIA = bodyA.m_invI;
|
|
pc.invIB = bodyB.m_invI;
|
|
pc.localNormal.x = manifold.localNormal.x;
|
|
pc.localNormal.y = manifold.localNormal.y;
|
|
pc.localPoint.x = manifold.localPoint.x;
|
|
pc.localPoint.y = manifold.localPoint.y;
|
|
pc.pointCount = pointCount;
|
|
pc.radiusA = radiusA;
|
|
pc.radiusB = radiusB;
|
|
pc.type = manifold.type;
|
|
this.m_positionConstraints[i] = pc;
|
|
for (var j = 0; j < pointCount; ++j) {
|
|
var cp = manifold.points[j];
|
|
var vcp = vc.points[j];
|
|
if (this.m_step.warmStarting) {
|
|
vcp.normalImpulse = this.m_step.dtRatio * cp.normalImpulse;
|
|
vcp.tangentImpulse = this.m_step.dtRatio * cp.tangentImpulse
|
|
} else {
|
|
vcp.normalImpulse = 0;
|
|
vcp.tangentImpulse = 0
|
|
}
|
|
vcp.rA.SetZero();
|
|
vcp.rB.SetZero();
|
|
vcp.normalMass = 0;
|
|
vcp.tangentMass = 0;
|
|
vcp.velocityBias = 0;
|
|
pc.localPoints[j] = cp.localPoint
|
|
}
|
|
}
|
|
},
|
|
InitializeVelocityConstraints: function () {
|
|
for (var i = 0; i < this.m_count; ++i) {
|
|
var vc = this.m_velocityConstraints[i];
|
|
var pc = this.m_positionConstraints[i];
|
|
var radiusA = pc.radiusA;
|
|
var radiusB = pc.radiusB;
|
|
var manifold = this.m_contacts[vc.contactIndex].GetManifold();
|
|
var indexA = vc.indexA;
|
|
var indexB = vc.indexB;
|
|
var mA = vc.invMassA;
|
|
var mB = vc.invMassB;
|
|
var iA = vc.invIA;
|
|
var iB = vc.invIB;
|
|
var localCenterA = pc.localCenterA;
|
|
var localCenterB = pc.localCenterB;
|
|
var cA = this.m_positions[indexA].c;
|
|
var aA = this.m_positions[indexA].a;
|
|
var vA = this.m_velocities[indexA].v;
|
|
var wA = this.m_velocities[indexA].w;
|
|
var cB = this.m_positions[indexB].c;
|
|
var aB = this.m_positions[indexB].a;
|
|
var vB = this.m_velocities[indexB].v;
|
|
var wB = this.m_velocities[indexB].w;
|
|
b2ContactSolver.cs_xfA.q.Set(aA);
|
|
b2ContactSolver.cs_xfB.q.Set(aB);
|
|
b2ContactSolver.cs_xfA.p.x = cA.x - (b2ContactSolver.cs_xfA.q.c * localCenterA.x - b2ContactSolver.cs_xfA.q.s * localCenterA.y);
|
|
b2ContactSolver.cs_xfA.p.y = cA.y - (b2ContactSolver.cs_xfA.q.s * localCenterA.x + b2ContactSolver.cs_xfA.q.c * localCenterA.y);
|
|
b2ContactSolver.cs_xfB.p.x = cB.x - (b2ContactSolver.cs_xfB.q.c * localCenterB.x - b2ContactSolver.cs_xfB.q.s * localCenterB.y);
|
|
b2ContactSolver.cs_xfB.p.y = cB.y - (b2ContactSolver.cs_xfB.q.s * localCenterB.x + b2ContactSolver.cs_xfB.q.c * localCenterB.y);
|
|
var worldManifold = new b2WorldManifold();
|
|
worldManifold.Initialize(manifold, b2ContactSolver.cs_xfA, radiusA, b2ContactSolver.cs_xfB, radiusB);
|
|
vc.normal.x = worldManifold.normal.x;
|
|
vc.normal.y = worldManifold.normal.y;
|
|
var pointCount = vc.pointCount;
|
|
for (var j = 0; j < pointCount; ++j) {
|
|
var vcp = vc.points[j];
|
|
vcp.rA.x = worldManifold.points[j].x - cA.x;
|
|
vcp.rA.y = worldManifold.points[j].y - cA.y;
|
|
vcp.rB.x = worldManifold.points[j].x - cB.x;
|
|
vcp.rB.y = worldManifold.points[j].y - cB.y;
|
|
var rnA = vcp.rA.x * vc.normal.y - vcp.rA.y * vc.normal.x;
|
|
var rnB = vcp.rB.x * vc.normal.y - vcp.rB.y * vc.normal.x;
|
|
var kNormal = mA + mB + iA * rnA * rnA + iB * rnB * rnB;
|
|
vcp.normalMass = kNormal > 0 ? 1 / kNormal : 0;
|
|
var tangentx = 1 * vc.normal.y;
|
|
var tangenty = -1 * vc.normal.x;
|
|
var rtA = vcp.rA.x * tangenty - vcp.rA.y * tangentx;
|
|
var rtB = vcp.rB.x * tangenty - vcp.rB.y * tangentx;
|
|
var kTangent = mA + mB + iA * rtA * rtA + iB * rtB * rtB;
|
|
vcp.tangentMass = kTangent > 0 ? 1 / kTangent : 0;
|
|
vcp.velocityBias = 0;
|
|
var vRel = vc.normal.x * (((vB.x + (-wB * vcp.rB.y)) - vA.x) - (-wA * vcp.rA.y)) + vc.normal.y * (((vB.y + (wB * vcp.rB.x)) - vA.y) - (wA * vcp.rA.x));
|
|
if (vRel < -b2_velocityThreshold) {
|
|
vcp.velocityBias = -vc.restitution * vRel
|
|
}
|
|
}
|
|
if (vc.pointCount == 2) {
|
|
var vcp1 = vc.points[0];
|
|
var vcp2 = vc.points[1];
|
|
var rn1A = vcp1.rA.x * vc.normal.y - vcp1.rA.y * vc.normal.x;
|
|
var rn1B = vcp1.rB.x * vc.normal.y - vcp1.rB.y * vc.normal.x;
|
|
var rn2A = vcp2.rA.x * vc.normal.y - vcp2.rA.y * vc.normal.x;
|
|
var rn2B = vcp2.rB.x * vc.normal.y - vcp2.rB.y * vc.normal.x;
|
|
var k11 = mA + mB + iA * rn1A * rn1A + iB * rn1B * rn1B;
|
|
var k22 = mA + mB + iA * rn2A * rn2A + iB * rn2B * rn2B;
|
|
var k12 = mA + mB + iA * rn1A * rn2A + iB * rn1B * rn2B;
|
|
var k_maxConditionNumber = 1000;
|
|
if (k11 * k11 < k_maxConditionNumber * (k11 * k22 - k12 * k12)) {
|
|
vc.K.ex.x = k11;
|
|
vc.K.ex.y = k12;
|
|
vc.K.ey.x = k12;
|
|
vc.K.ey.y = k22;
|
|
vc.normalMass.Assign(vc.K.GetInverse())
|
|
} else {
|
|
vc.pointCount = 1
|
|
}
|
|
}
|
|
}
|
|
},
|
|
WarmStart: function () {
|
|
for (var i = 0; i < this.m_count; ++i) {
|
|
var vc = this.m_velocityConstraints[i];
|
|
var indexA = vc.indexA;
|
|
var indexB = vc.indexB;
|
|
var mA = vc.invMassA;
|
|
var iA = vc.invIA;
|
|
var mB = vc.invMassB;
|
|
var iB = vc.invIB;
|
|
var pointCount = vc.pointCount;
|
|
var vA = this.m_velocities[indexA].v;
|
|
var wA = this.m_velocities[indexA].w;
|
|
var vB = this.m_velocities[indexB].v;
|
|
var wB = this.m_velocities[indexB].w;
|
|
var normal = vc.normal;
|
|
var tangentx = 1 * normal.y;
|
|
var tangenty = -1 * normal.x;
|
|
for (var j = 0; j < pointCount; ++j) {
|
|
var vcp = vc.points[j];
|
|
var Px = (vcp.normalImpulse * normal.x) + (vcp.tangentImpulse * tangentx);
|
|
var Py = (vcp.normalImpulse * normal.y) + (vcp.tangentImpulse * tangenty);
|
|
wA -= iA * (vcp.rA.x * Py - vcp.rA.y * Px);
|
|
vA.x -= mA * Px;
|
|
vA.y -= mA * Py;
|
|
wB += iB * (vcp.rB.x * Py - vcp.rB.y * Px);
|
|
vB.x += mB * Px;
|
|
vB.y += mB * Py
|
|
}
|
|
this.m_velocities[indexA].w = wA;
|
|
this.m_velocities[indexB].w = wB
|
|
}
|
|
},
|
|
SolveVelocityConstraints: function () {
|
|
for (var i = 0; i < this.m_count; ++i) {
|
|
var vc = this.m_velocityConstraints[i];
|
|
var indexA = vc.indexA;
|
|
var indexB = vc.indexB;
|
|
var mA = vc.invMassA;
|
|
var iA = vc.invIA;
|
|
var mB = vc.invMassB;
|
|
var iB = vc.invIB;
|
|
var pointCount = vc.pointCount;
|
|
var vA = this.m_velocities[indexA].v;
|
|
var wA = this.m_velocities[indexA].w;
|
|
var vB = this.m_velocities[indexB].v;
|
|
var wB = this.m_velocities[indexB].w;
|
|
var normal = vc.normal;
|
|
var tangentx = 1 * normal.y;
|
|
var tangenty = -1 * normal.x;
|
|
var friction = vc.friction;
|
|
for (var j = 0; j < pointCount; ++j) {
|
|
var vcp = vc.points[j];
|
|
var dvx = vB.x + (-wB * vcp.rB.y) - vA.x - (-wA * vcp.rA.y);
|
|
var dvy = vB.y + (wB * vcp.rB.x) - vA.y - (wA * vcp.rA.x);
|
|
var vt = (dvx * tangentx + dvy * tangenty) - vc.tangentSpeed;
|
|
var lambda = vcp.tangentMass * (-vt);
|
|
var maxFriction = friction * vcp.normalImpulse;
|
|
var newImpulse = b2Clamp(vcp.tangentImpulse + lambda, -maxFriction, maxFriction);
|
|
lambda = newImpulse - vcp.tangentImpulse;
|
|
vcp.tangentImpulse = newImpulse;
|
|
var Px = lambda * tangentx;
|
|
var Py = lambda * tangenty;
|
|
vA.x -= mA * Px;
|
|
vA.y -= mA * Py;
|
|
wA -= iA * (vcp.rA.x * Py - vcp.rA.y * Px);
|
|
vB.x += mB * Px;
|
|
vB.y += mB * Py;
|
|
wB += iB * (vcp.rB.x * Py - vcp.rB.y * Px)
|
|
}
|
|
if (vc.pointCount == 1) {
|
|
vcp = vc.points[0];
|
|
dvx = vB.x + (-wB * vcp.rB.y) - vA.x - (-wA * vcp.rA.y);
|
|
dvy = vB.y + (wB * vcp.rB.x) - vA.y - (wA * vcp.rA.x);
|
|
var vn = dvx * normal.x + dvy * normal.y;
|
|
var lambda = -vcp.normalMass * (vn - vcp.velocityBias);
|
|
var newImpulse = b2Max(vcp.normalImpulse + lambda, 0);
|
|
lambda = newImpulse - vcp.normalImpulse;
|
|
vcp.normalImpulse = newImpulse;
|
|
Px = lambda * normal.x;
|
|
Py = lambda * normal.y;
|
|
vA.x -= mA * Px;
|
|
vA.y -= mA * Py;
|
|
wA -= iA * (vcp.rA.x * Py - vcp.rA.y * Px);
|
|
vB.x += mB * Px;
|
|
vB.y += mB * Py;
|
|
wB += iB * (vcp.rB.x * Py - vcp.rB.y * Px)
|
|
} else {
|
|
var cp1 = vc.points[0];
|
|
var cp2 = vc.points[1];
|
|
var ax = cp1.normalImpulse;
|
|
var ay = cp2.normalImpulse;
|
|
var dv1x = vB.x + (-wB * cp1.rB.y) - vA.x - (-wA * cp1.rA.y);
|
|
var dv1y = vB.y + (wB * cp1.rB.x) - vA.y - (wA * cp1.rA.x);
|
|
var dv2x = vB.x + (-wB * cp2.rB.y) - vA.x - (-wA * cp2.rA.y);
|
|
var dv2y = vB.y + (wB * cp2.rB.x) - vA.y - (wA * cp2.rA.x);
|
|
var vn1 = dv1x * normal.x + dv1y * normal.y;
|
|
var vn2 = dv2x * normal.x + dv2y * normal.y;
|
|
var bx = vn1 - cp1.velocityBias;
|
|
var by = vn2 - cp2.velocityBias;
|
|
bx -= vc.K.ex.x * ax + vc.K.ey.x * ay;
|
|
by -= vc.K.ex.y * ax + vc.K.ey.y * ay;
|
|
for (;;) {
|
|
var xx = -(vc.normalMass.ex.x * bx + vc.normalMass.ey.x * by);
|
|
var xy = -(vc.normalMass.ex.y * bx + vc.normalMass.ey.y * by);
|
|
if (xx >= 0 && xy >= 0) {
|
|
var dx = xx - ax;
|
|
var dy = xy - ay;
|
|
var P1x = dx * normal.x;
|
|
var P1y = dx * normal.y;
|
|
var P2x = dy * normal.x;
|
|
var P2y = dy * normal.y;
|
|
vA.x -= mA * (P1x + P2x);
|
|
vA.y -= mA * (P1y + P2y);
|
|
wA -= iA * ((cp1.rA.x * P1y - cp1.rA.y * P1x) + (cp2.rA.x * P2y - cp2.rA.y * P2x));
|
|
vB.x += mB * (P1x + P2x);
|
|
vB.y += mB * (P1y + P2y);
|
|
wB += iB * ((cp1.rB.x * P1y - cp1.rB.y * P1x) + (cp2.rB.x * P2y - cp2.rB.y * P2x));
|
|
cp1.normalImpulse = xx;
|
|
cp2.normalImpulse = xy;
|
|
break
|
|
}
|
|
xx = -cp1.normalMass * bx;
|
|
xy = 0;
|
|
vn1 = 0;
|
|
vn2 = vc.K.ex.y * xx + by;
|
|
if (xx >= 0 && vn2 >= 0) {
|
|
dx = xx - ax;
|
|
dy = xy - ay;
|
|
P1x = dx * normal.x;
|
|
P1y = dx * normal.y;
|
|
P2x = dy * normal.x;
|
|
P2y = dy * normal.y;
|
|
vA.x -= mA * (P1x + P2x);
|
|
vA.y -= mA * (P1y + P2y);
|
|
wA -= iA * ((cp1.rA.x * P1y - cp1.rA.y * P1x) + (cp2.rA.x * P2y - cp2.rA.y * P2x));
|
|
vB.x += mB * (P1x + P2x);
|
|
vB.y += mB * (P1y + P2y);
|
|
wB += iB * ((cp1.rB.x * P1y - cp1.rB.y * P1x) + (cp2.rB.x * P2y - cp2.rB.y * P2x));
|
|
cp1.normalImpulse = xx;
|
|
cp2.normalImpulse = xy;
|
|
break
|
|
}
|
|
xx = 0;
|
|
xy = -cp2.normalMass * by;
|
|
vn1 = vc.K.ey.x * xy + bx;
|
|
vn2 = 0;
|
|
if (xy >= 0 && vn1 >= 0) {
|
|
dx = xx - ax;
|
|
dy = xy - ay;
|
|
P1x = dx * normal.x;
|
|
P1y = dx * normal.y;
|
|
P2x = dy * normal.x;
|
|
P2y = dy * normal.y;
|
|
vA.x -= mA * (P1x + P2x);
|
|
vA.y -= mA * (P1y + P2y);
|
|
wA -= iA * ((cp1.rA.x * P1y - cp1.rA.y * P1x) + (cp2.rA.x * P2y - cp2.rA.y * P2x));
|
|
vB.x += mB * (P1x + P2x);
|
|
vB.y += mB * (P1y + P2y);
|
|
wB += iB * ((cp1.rB.x * P1y - cp1.rB.y * P1x) + (cp2.rB.x * P2y - cp2.rB.y * P2x));
|
|
cp1.normalImpulse = xx;
|
|
cp2.normalImpulse = xy;
|
|
break
|
|
}
|
|
xx = 0;
|
|
xy = 0;
|
|
vn1 = bx;
|
|
vn2 = by;
|
|
if (vn1 >= 0 && vn2 >= 0) {
|
|
dx = xx - ax;
|
|
dy = xy - ay;
|
|
P1x = dx * normal.x;
|
|
P1y = dx * normal.y;
|
|
P2x = dy * normal.x;
|
|
P2y = dy * normal.y;
|
|
vA.x -= mA * (P1x + P2x);
|
|
vA.y -= mA * (P1y + P2y);
|
|
wA -= iA * ((cp1.rA.x * P1y - cp1.rA.y * P1x) + (cp2.rA.x * P2y - cp2.rA.y * P2x));
|
|
vB.x += mB * (P1x + P2x);
|
|
vB.y += mB * (P1y + P2y);
|
|
wB += iB * ((cp1.rB.x * P1y - cp1.rB.y * P1x) + (cp2.rB.x * P2y - cp2.rB.y * P2x));
|
|
cp1.normalImpulse = xx;
|
|
cp2.normalImpulse = xy;
|
|
break
|
|
}
|
|
break
|
|
}
|
|
}
|
|
this.m_velocities[indexA].w = wA;
|
|
this.m_velocities[indexB].w = wB
|
|
}
|
|
},
|
|
StoreImpulses: function () {
|
|
for (var i = 0; i < this.m_count; ++i) {
|
|
var vc = this.m_velocityConstraints[i];
|
|
var manifold = this.m_contacts[vc.contactIndex].GetManifold();
|
|
for (var j = 0; j < vc.pointCount; ++j) {
|
|
manifold.points[j].normalImpulse = vc.points[j].normalImpulse;
|
|
manifold.points[j].tangentImpulse = vc.points[j].tangentImpulse
|
|
}
|
|
}
|
|
},
|
|
SolvePositionConstraints: function () {
|
|
var minSeparation = 0;
|
|
for (var i = 0; i < this.m_count; ++i) {
|
|
var pc = this.m_positionConstraints[i];
|
|
var indexA = pc.indexA;
|
|
var indexB = pc.indexB;
|
|
var localCenterA = pc.localCenterA;
|
|
var mA = pc.invMassA;
|
|
var iA = pc.invIA;
|
|
var localCenterB = pc.localCenterB;
|
|
var mB = pc.invMassB;
|
|
var iB = pc.invIB;
|
|
var pointCount = pc.pointCount;
|
|
var cA = this.m_positions[indexA].c;
|
|
var aA = this.m_positions[indexA].a;
|
|
var cB = this.m_positions[indexB].c;
|
|
var aB = this.m_positions[indexB].a;
|
|
for (var j = 0; j < pointCount; ++j) {
|
|
b2ContactSolver.cs_xfA.q.Set(aA);
|
|
b2ContactSolver.cs_xfB.q.Set(aB);
|
|
b2ContactSolver.cs_xfA.p.x = cA.x - (b2ContactSolver.cs_xfA.q.c * localCenterA.x - b2ContactSolver.cs_xfA.q.s * localCenterA.y);
|
|
b2ContactSolver.cs_xfA.p.y = cA.y - (b2ContactSolver.cs_xfA.q.s * localCenterA.x + b2ContactSolver.cs_xfA.q.c * localCenterA.y);
|
|
b2ContactSolver.cs_xfB.p.x = cB.x - (b2ContactSolver.cs_xfB.q.c * localCenterB.x - b2ContactSolver.cs_xfB.q.s * localCenterB.y);
|
|
b2ContactSolver.cs_xfB.p.y = cB.y - (b2ContactSolver.cs_xfB.q.s * localCenterB.x + b2ContactSolver.cs_xfB.q.c * localCenterB.y);
|
|
b2ContactSolver.temp_solver_manifold.Initialize(pc, b2ContactSolver.cs_xfA, b2ContactSolver.cs_xfB, j);
|
|
var normal = b2ContactSolver.temp_solver_manifold.normal;
|
|
var point = b2ContactSolver.temp_solver_manifold.point;
|
|
var separation = b2ContactSolver.temp_solver_manifold.separation;
|
|
var rAx = point.x - cA.x;
|
|
var rAy = point.y - cA.y;
|
|
var rBx = point.x - cB.x;
|
|
var rBy = point.y - cB.y;
|
|
minSeparation = b2Min(minSeparation, separation);
|
|
var C = b2Clamp(b2_baumgarte * (separation + b2_linearSlop), -b2_maxLinearCorrection, 0);
|
|
var rnA = rAx * normal.y - rAy * normal.x;
|
|
var rnB = rBx * normal.y - rBy * normal.x;
|
|
var K = mA + mB + iA * rnA * rnA + iB * rnB * rnB;
|
|
var impulse = K > 0 ? -C / K : 0;
|
|
var Px = impulse * normal.x;
|
|
var Py = impulse * normal.y;
|
|
cA.x -= mA * Px;
|
|
cA.y -= mA * Py;
|
|
aA -= iA * (rAx * Py - rAy * Px);
|
|
cB.x += mB * Px;
|
|
cB.y += mB * Py;
|
|
aB += iB * (rBx * Py - rBy * Px)
|
|
}
|
|
this.m_positions[indexA].a = aA;
|
|
this.m_positions[indexB].a = aB
|
|
}
|
|
return minSeparation >= -3 * b2_linearSlop
|
|
},
|
|
SolveTOIPositionConstraints: function (toiIndexA, toiIndexB) {
|
|
var minSeparation = 0;
|
|
for (var i = 0; i < this.m_count; ++i) {
|
|
var pc = this.m_positionConstraints[i];
|
|
var indexA = pc.indexA;
|
|
var indexB = pc.indexB;
|
|
var localCenterA = pc.localCenterA;
|
|
var localCenterB = pc.localCenterB;
|
|
var pointCount = pc.pointCount;
|
|
var mA = 0;
|
|
var iA = 0;
|
|
if (indexA == toiIndexA || indexA == toiIndexB) {
|
|
mA = pc.invMassA;
|
|
iA = pc.invIA
|
|
}
|
|
var mB = 0;
|
|
var iB = 0;
|
|
if (indexB == toiIndexA || indexB == toiIndexB) {
|
|
mB = pc.invMassB;
|
|
iB = pc.invIB
|
|
}
|
|
var cA = this.m_positions[indexA].c;
|
|
var aA = this.m_positions[indexA].a;
|
|
var cB = this.m_positions[indexB].c;
|
|
var aB = this.m_positions[indexB].a;
|
|
for (var j = 0; j < pointCount; ++j) {
|
|
b2ContactSolver.cs_xfA.q.Set(aA);
|
|
b2ContactSolver.cs_xfB.q.Set(aB);
|
|
b2ContactSolver.cs_xfA.p.Assign(b2Vec2.Subtract(cA, b2Mul_r_v2(b2ContactSolver.cs_xfA.q, localCenterA)));
|
|
b2ContactSolver.cs_xfB.p.Assign(b2Vec2.Subtract(cB, b2Mul_r_v2(b2ContactSolver.cs_xfB.q, localCenterB)));
|
|
b2ContactSolver.temp_solver_manifold.Initialize(pc, b2ContactSolver.cs_xfA, b2ContactSolver.cs_xfB, j);
|
|
var normal = b2ContactSolver.temp_solver_manifold.normal;
|
|
var point = b2ContactSolver.temp_solver_manifold.point;
|
|
var separation = b2ContactSolver.temp_solver_manifold.separation;
|
|
var rA = b2Vec2.Subtract(point, cA);
|
|
var rB = b2Vec2.Subtract(point, cB);
|
|
minSeparation = b2Min(minSeparation, separation);
|
|
var C = b2Clamp(b2_toiBaugarte * (separation + b2_linearSlop), -b2_maxLinearCorrection, 0);
|
|
var rnA = b2Cross_v2_v2(rA, normal);
|
|
var rnB = b2Cross_v2_v2(rB, normal);
|
|
var K = mA + mB + iA * rnA * rnA + iB * rnB * rnB;
|
|
var impulse = K > 0 ? -C / K : 0;
|
|
var P = b2Vec2.Multiply(impulse, normal);
|
|
cA.Subtract(b2Vec2.Multiply(mA, P));
|
|
aA -= iA * b2Cross_v2_v2(rA, P);
|
|
cB.Add(b2Vec2.Multiply(mB, P));
|
|
aB += iB * b2Cross_v2_v2(rB, P)
|
|
}
|
|
this.m_positions[indexA].a = aA;
|
|
this.m_positions[indexB].a = aB
|
|
}
|
|
return minSeparation >= -1.5 * b2_linearSlop
|
|
}
|
|
};
|
|
"use strict";
|
|
|
|
function b2Island() {
|
|
this.m_bodies = [];
|
|
this.m_contacts = [];
|
|
this.m_joints = [];
|
|
this.m_velocities = [];
|
|
this.m_positions = []
|
|
}
|
|
var profile_solve_init = b2Profiler.create("solve initialization", "solve");
|
|
var profile_solve_init_warmStarting = b2Profiler.create("warm starting", "solve initialization");
|
|
var profile_solve_velocity = b2Profiler.create("solve velocities", "solve");
|
|
var profile_solve_position = b2Profiler.create("solve positions", "solve");
|
|
b2Island._solverData = new b2SolverData();
|
|
b2Island._solverDef = new b2ContactSolverDef();
|
|
b2Island._solver = new b2ContactSolver();
|
|
b2Island.prototype = {
|
|
Clear: function () {
|
|
this.m_bodyCount = 0;
|
|
this.m_contactCount = 0;
|
|
this.m_jointCount = 0
|
|
},
|
|
Initialize: function (bodyCapacity, contactCapacity, jointCapacity, listener) {
|
|
this.m_listener = listener;
|
|
this.m_bodyCapacity = bodyCapacity;
|
|
this.m_contactCapacity = contactCapacity;
|
|
this.m_jointCapacity = jointCapacity;
|
|
this.m_bodyCount = 0;
|
|
this.m_contactCount = 0;
|
|
this.m_jointCount = 0;
|
|
this.m_bodies.length = bodyCapacity;
|
|
this.m_contacts.length = contactCapacity;
|
|
this.m_joints.length = jointCapacity;
|
|
this.m_velocities.length = bodyCapacity;
|
|
this.m_positions.length = bodyCapacity
|
|
},
|
|
Solve: function (step, gravity, allowSleep) {
|
|
profile_solve_init.start();
|
|
var h = step.dt;
|
|
for (var i = 0; i < this.m_bodyCount; ++i) {
|
|
var b = this.m_bodies[i];
|
|
this.m_positions[i].c.Assign(b.m_sweep.c);
|
|
var a = b.m_sweep.a;
|
|
this.m_velocities[i].v.Assign(b.m_linearVelocity);
|
|
var w = b.m_angularVelocity;
|
|
b.m_sweep.c0.Assign(b.m_sweep.c);
|
|
b.m_sweep.a0 = b.m_sweep.a;
|
|
if (b.m_type == b2Body.b2_dynamicBody) {
|
|
this.m_velocities[i].v.x += h * ((b.m_gravityScale * gravity.x) + (b.m_invMass * b.m_force.x));
|
|
this.m_velocities[i].v.y += h * ((b.m_gravityScale * gravity.y) + (b.m_invMass * b.m_force.y));
|
|
w += h * b.m_invI * b.m_torque;
|
|
this.m_velocities[i].v.x *= 1 / (1 + h * b.m_linearDamping);
|
|
this.m_velocities[i].v.y *= 1 / (1 + h * b.m_linearDamping);
|
|
w *= 1 / (1 + h * b.m_angularDamping)
|
|
}
|
|
this.m_positions[i].a = a;
|
|
this.m_velocities[i].w = w
|
|
}
|
|
b2Island._solverData.step = step;
|
|
b2Island._solverData.positions = this.m_positions;
|
|
b2Island._solverData.velocities = this.m_velocities;
|
|
b2Island._solverDef.step = step;
|
|
b2Island._solverDef.contacts = this.m_contacts;
|
|
b2Island._solverDef.count = this.m_contactCount;
|
|
b2Island._solverDef.positions = this.m_positions;
|
|
b2Island._solverDef.velocities = this.m_velocities;
|
|
b2Island._solverDef.allocator = this.m_allocator;
|
|
b2Island._solver.Init(b2Island._solverDef);
|
|
b2Island._solver.InitializeVelocityConstraints();
|
|
if (step.warmStarting) {
|
|
profile_solve_init_warmStarting.start();
|
|
b2Island._solver.WarmStart();
|
|
profile_solve_init_warmStarting.stop()
|
|
}
|
|
for (var i = 0; i < this.m_jointCount; ++i) {
|
|
this.m_joints[i].InitVelocityConstraints(b2Island._solverData)
|
|
}
|
|
profile_solve_init.stop();
|
|
profile_solve_velocity.start();
|
|
for (var i = 0; i < step.velocityIterations; ++i) {
|
|
for (var j = 0; j < this.m_jointCount; ++j) {
|
|
this.m_joints[j].SolveVelocityConstraints(b2Island._solverData)
|
|
}
|
|
b2Island._solver.SolveVelocityConstraints()
|
|
}
|
|
b2Island._solver.StoreImpulses();
|
|
profile_solve_velocity.stop();
|
|
profile_solve_position.start();
|
|
for (var i = 0; i < this.m_bodyCount; ++i) {
|
|
var c = this.m_positions[i].c;
|
|
var a = this.m_positions[i].a;
|
|
var v = this.m_velocities[i].v;
|
|
var w = this.m_velocities[i].w;
|
|
var translationx = h * v.x;
|
|
var translationy = h * v.y;
|
|
var translationl = translationx * translationx + translationy * translationy;
|
|
if (translationl > b2_maxTranslationSquared) {
|
|
var ratio = b2_maxTranslation / b2Sqrt(translationl);
|
|
v.x *= ratio;
|
|
v.y *= ratio
|
|
}
|
|
var rotation = h * w;
|
|
if (rotation * rotation > b2_maxRotationSquared) {
|
|
var ratio = b2_maxRotation / b2Abs(rotation);
|
|
w *= ratio
|
|
}
|
|
c.x += h * v.x;
|
|
c.y += h * v.y;
|
|
a += h * w;
|
|
this.m_positions[i].a = a;
|
|
this.m_velocities[i].w = w
|
|
}
|
|
var positionSolved = false;
|
|
for (var i = 0; i < step.positionIterations; ++i) {
|
|
var contactsOkay = b2Island._solver.SolvePositionConstraints();
|
|
var jointsOkay = true;
|
|
for (var j = 0; j < this.m_jointCount; ++j) {
|
|
var jointOkay = this.m_joints[j].SolvePositionConstraints(b2Island._solverData);
|
|
jointsOkay = jointsOkay && jointOkay
|
|
}
|
|
if (contactsOkay && jointsOkay) {
|
|
positionSolved = true;
|
|
break
|
|
}
|
|
}
|
|
for (var i = 0; i < this.m_bodyCount; ++i) {
|
|
var body = this.m_bodies[i];
|
|
body.m_sweep.c.Assign(this.m_positions[i].c);
|
|
body.m_sweep.a = this.m_positions[i].a;
|
|
body.m_linearVelocity.Assign(this.m_velocities[i].v);
|
|
body.m_angularVelocity = this.m_velocities[i].w;
|
|
body.SynchronizeTransform()
|
|
}
|
|
profile_solve_position.stop();
|
|
this.Report(b2Island._solver.m_velocityConstraints);
|
|
if (allowSleep) {
|
|
var minSleepTime = b2_maxFloat;
|
|
var linTolSqr = b2_linearSleepTolerance * b2_linearSleepTolerance;
|
|
var angTolSqr = b2_angularSleepTolerance * b2_angularSleepTolerance;
|
|
for (var i = 0; i < this.m_bodyCount; ++i) {
|
|
var b = this.m_bodies[i];
|
|
if (b.GetType() == b2Body.b2_staticBody) {
|
|
continue
|
|
}
|
|
if ((b.m_flags & b2Body.e_autoSleepFlag) == 0 || b.m_angularVelocity * b.m_angularVelocity > angTolSqr || b2Dot_v2_v2(b.m_linearVelocity, b.m_linearVelocity) > linTolSqr) {
|
|
b.m_sleepTime = 0;
|
|
minSleepTime = 0
|
|
} else {
|
|
b.m_sleepTime += h;
|
|
minSleepTime = b2Min(minSleepTime, b.m_sleepTime)
|
|
}
|
|
}
|
|
if (minSleepTime >= b2_timeToSleep && positionSolved) {
|
|
for (var i = 0; i < this.m_bodyCount; ++i) {
|
|
var b = this.m_bodies[i];
|
|
b.SetAwake(false)
|
|
}
|
|
}
|
|
}
|
|
},
|
|
SolveTOI: function (subStep, toiIndexA, toiIndexB) {
|
|
for (var i = 0; i < this.m_bodyCount; ++i) {
|
|
var b = this.m_bodies[i];
|
|
this.m_positions[i].c.Assign(b.m_sweep.c);
|
|
this.m_positions[i].a = b.m_sweep.a;
|
|
this.m_velocities[i].v.Assign(b.m_linearVelocity);
|
|
this.m_velocities[i].w = b.m_angularVelocity
|
|
}
|
|
b2Island._solverDef.contacts = this.m_contacts;
|
|
b2Island._solverDef.count = this.m_contactCount;
|
|
b2Island._solverDef.step = subStep;
|
|
b2Island._solverDef.positions = this.m_positions;
|
|
b2Island._solverDef.velocities = this.m_velocities;
|
|
b2Island._solver.Init(b2Island._solverDef);
|
|
for (var i = 0; i < subStep.positionIterations; ++i) {
|
|
var contactsOkay = b2Island._solver.SolveTOIPositionConstraints(toiIndexA, toiIndexB);
|
|
if (contactsOkay) {
|
|
break
|
|
}
|
|
}
|
|
this.m_bodies[toiIndexA].m_sweep.c0.Assign(this.m_positions[toiIndexA].c);
|
|
this.m_bodies[toiIndexA].m_sweep.a0 = this.m_positions[toiIndexA].a;
|
|
this.m_bodies[toiIndexB].m_sweep.c0.Assign(this.m_positions[toiIndexB].c);
|
|
this.m_bodies[toiIndexB].m_sweep.a0 = this.m_positions[toiIndexB].a;
|
|
b2Island._solver.InitializeVelocityConstraints();
|
|
for (var i = 0; i < subStep.velocityIterations; ++i) {
|
|
b2Island._solver.SolveVelocityConstraints()
|
|
}
|
|
var h = subStep.dt;
|
|
for (var i = 0; i < this.m_bodyCount; ++i) {
|
|
var c = this.m_positions[i].c;
|
|
var a = this.m_positions[i].a;
|
|
var v = this.m_velocities[i].v;
|
|
var w = this.m_velocities[i].w;
|
|
var translation = b2Vec2.Multiply(h, v);
|
|
if (b2Dot_v2_v2(translation, translation) > b2_maxTranslationSquared) {
|
|
var ratio = b2_maxTranslation / translation.Length();
|
|
v.Multiply(ratio)
|
|
}
|
|
var rotation = h * w;
|
|
if (rotation * rotation > b2_maxRotationSquared) {
|
|
var ratio = b2_maxRotation / b2Abs(rotation);
|
|
w *= ratio
|
|
}
|
|
c.Add(b2Vec2.Multiply(h, v));
|
|
a += h * w;
|
|
this.m_positions[i].a = a;
|
|
this.m_velocities[i].w = w;
|
|
var body = this.m_bodies[i];
|
|
body.m_sweep.c.Assign(c);
|
|
body.m_sweep.a = a;
|
|
body.m_linearVelocity.Assign(v);
|
|
body.m_angularVelocity = w;
|
|
body.SynchronizeTransform()
|
|
}
|
|
this.Report(b2Island._solver.m_velocityConstraints)
|
|
},
|
|
AddBody: function (body) {
|
|
body.m_islandIndex = this.m_bodyCount;
|
|
this.m_bodies[this.m_bodyCount] = body;
|
|
if (!this.m_positions[this.m_bodyCount]) {
|
|
this.m_positions[this.m_bodyCount] = new b2Position();
|
|
this.m_velocities[this.m_bodyCount] = new b2Velocity()
|
|
}++this.m_bodyCount
|
|
},
|
|
AddContact: function (contact) {
|
|
this.m_contacts[this.m_contactCount++] = contact
|
|
},
|
|
AddJoint: function (joint) {
|
|
this.m_joints[this.m_jointCount++] = joint
|
|
},
|
|
Report: function (constraints) {
|
|
if (this.m_listener == null) {
|
|
return
|
|
}
|
|
for (var i = 0; i < this.m_contactCount; ++i) {
|
|
var c = this.m_contacts[i];
|
|
var vc = constraints[i];
|
|
var impulse = new b2ContactImpulse();
|
|
impulse.count = vc.pointCount;
|
|
for (var j = 0; j < vc.pointCount; ++j) {
|
|
impulse.normalImpulses[j] = vc.points[j].normalImpulse;
|
|
impulse.tangentImpulses[j] = vc.points[j].tangentImpulse
|
|
}
|
|
this.m_listener.PostSolve(c, impulse)
|
|
}
|
|
}
|
|
};
|
|
|
|
function b2Jacobian() {
|
|
this.linear = new b2Vec2();
|
|
this.angularA = 0;
|
|
this.angularB = 0
|
|
}
|
|
|
|
function b2JointEdge() {
|
|
this.other = null;
|
|
this.joint = null;
|
|
this.prev = null;
|
|
this.next = null
|
|
}
|
|
|
|
function b2JointDef() {
|
|
this.type = b2Joint.e_unknownJoint;
|
|
this.userData = null;
|
|
this.bodyA = null;
|
|
this.bodyB = null;
|
|
this.collideConnected = false
|
|
}
|
|
b2JointDef.prototype = {
|
|
_deserialize: function (data, bodies, joints) {
|
|
this.bodyA = bodies[data.bodyA];
|
|
this.bodyB = bodies[data.bodyB];
|
|
this.collideConnected = data.collideConnected
|
|
}
|
|
};
|
|
|
|
function b2Joint(def) {
|
|
this.m_type = def.type;
|
|
this.m_prev = null;
|
|
this.m_next = null;
|
|
this.m_bodyA = def.bodyA;
|
|
this.m_bodyB = def.bodyB;
|
|
this.m_index = 0;
|
|
this.m_collideConnected = def.collideConnected;
|
|
this.m_islandFlag = false;
|
|
this.m_userData = def.userData;
|
|
this.m_edgeA = new b2JointEdge();
|
|
this.m_edgeA.joint = null;
|
|
this.m_edgeA.other = null;
|
|
this.m_edgeA.prev = null;
|
|
this.m_edgeA.next = null;
|
|
this.m_edgeB = new b2JointEdge();
|
|
this.m_edgeB.joint = null;
|
|
this.m_edgeB.other = null;
|
|
this.m_edgeB.prev = null;
|
|
this.m_edgeB.next = null
|
|
}
|
|
b2Joint.prototype = {
|
|
GetType: function () {
|
|
return this.m_type
|
|
},
|
|
GetBodyA: function () {
|
|
return this.m_bodyA
|
|
},
|
|
GetBodyB: function () {
|
|
return this.m_bodyB
|
|
},
|
|
GetAnchorA: function () {},
|
|
GetAnchorB: function () {},
|
|
GetReactionForce: function (inv_dt) {},
|
|
GetReactionTorque: function (inv_dt) {},
|
|
GetNext: function () {
|
|
return this.m_next
|
|
},
|
|
GetUserData: function () {
|
|
return this.m_userData
|
|
},
|
|
SetUserData: function (data) {
|
|
this.m_userData = data
|
|
},
|
|
IsActive: function () {
|
|
return this.m_bodyA.IsActive() && this.m_bodyB.IsActive()
|
|
},
|
|
GetCollideConnected: function () {
|
|
return this.m_collideConnected
|
|
},
|
|
ShiftOrigin: function (newOrigin) {},
|
|
InitVelocityConstraints: function (data) {},
|
|
SolveVelocityConstraints: function (data) {},
|
|
SolvePositionConstraints: function (data) {},
|
|
_serialize: function (out) {
|
|
var obj = out || {};
|
|
obj.bodyA = null;
|
|
obj.bodyB = null;
|
|
obj.type = this.m_type;
|
|
obj.collideConnected = this.m_collideConnected;
|
|
return obj
|
|
}
|
|
};
|
|
b2Joint.e_inactiveLimit = 0;
|
|
b2Joint.e_atLowerLimit = 1;
|
|
b2Joint.e_atUpperLimit = 2;
|
|
b2Joint.e_equalLimits = 3;
|
|
b2Joint.e_unknownJoint = 0;
|
|
b2Joint.e_revoluteJoint = 1;
|
|
b2Joint.e_prismaticJoint = 2;
|
|
b2Joint.e_distanceJoint = 3;
|
|
b2Joint.e_pulleyJoint = 4;
|
|
b2Joint.e_mouseJoint = 5;
|
|
b2Joint.e_gearJoint = 6;
|
|
b2Joint.e_wheelJoint = 7;
|
|
b2Joint.e_weldJoint = 8;
|
|
b2Joint.e_frictionJoint = 9;
|
|
b2Joint.e_ropeJoint = 10;
|
|
b2Joint.e_motorJoint = 11;
|
|
b2Joint.Create = function (def) {
|
|
var joint = null;
|
|
switch (def.type) {
|
|
case b2Joint.e_distanceJoint:
|
|
joint = new b2DistanceJoint(def);
|
|
break;
|
|
case b2Joint.e_mouseJoint:
|
|
joint = new b2MouseJoint(def);
|
|
break;
|
|
case b2Joint.e_prismaticJoint:
|
|
joint = new b2PrismaticJoint(def);
|
|
break;
|
|
case b2Joint.e_revoluteJoint:
|
|
joint = new b2RevoluteJoint(def);
|
|
break;
|
|
case b2Joint.e_pulleyJoint:
|
|
joint = new b2PulleyJoint(def);
|
|
break;
|
|
case b2Joint.e_gearJoint:
|
|
joint = new b2GearJoint(def);
|
|
break;
|
|
case b2Joint.e_wheelJoint:
|
|
joint = new b2WheelJoint(def);
|
|
break;
|
|
case b2Joint.e_weldJoint:
|
|
joint = new b2WeldJoint(def);
|
|
break;
|
|
case b2Joint.e_frictionJoint:
|
|
joint = new b2FrictionJoint(def);
|
|
break;
|
|
case b2Joint.e_ropeJoint:
|
|
joint = new b2RopeJoint(def);
|
|
break;
|
|
case b2Joint.e_motorJoint:
|
|
joint = new b2MotorJoint(def);
|
|
break
|
|
}
|
|
return joint
|
|
};
|
|
b2Joint.Destroy = function (joint) {};
|
|
|
|
function b2RevoluteJointDef() {
|
|
this.parent.call(this);
|
|
this.type = b2Joint.e_revoluteJoint;
|
|
this.localAnchorA = new b2Vec2();
|
|
this.localAnchorB = new b2Vec2();
|
|
this.referenceAngle = 0;
|
|
this.lowerAngle = 0;
|
|
this.upperAngle = 0;
|
|
this.maxMotorTorque = 0;
|
|
this.motorSpeed = 0;
|
|
this.enableLimit = false;
|
|
this.enableMotor = false;
|
|
Object.seal(this)
|
|
}
|
|
b2RevoluteJointDef.prototype = {
|
|
Initialize: function (bA, bB, anchor) {
|
|
this.bodyA = bA;
|
|
this.bodyB = bB;
|
|
this.localAnchorA = this.bodyA.GetLocalPoint(anchor);
|
|
this.localAnchorB = this.bodyB.GetLocalPoint(anchor);
|
|
this.referenceAngle = this.bodyB.GetAngle() - this.bodyA.GetAngle()
|
|
},
|
|
_deserialize: function (data, bodies, joints) {
|
|
this.parent.prototype._deserialize.call(this, data, bodies, joints);
|
|
this.localAnchorA._deserialize(data.localAnchorA);
|
|
this.localAnchorB._deserialize(data.localAnchorB);
|
|
this.referenceAngle = data.referenceAngle;
|
|
this.lowerAngle = data.lowerAngle;
|
|
this.upperAngle = data.upperAngle;
|
|
this.maxMotorTorque = data.maxMotorTorque;
|
|
this.motorSpeed = data.motorSpeed;
|
|
this.enableLimit = data.enableLimit;
|
|
this.enableMotor = data.enableMotor
|
|
}
|
|
};
|
|
b2RevoluteJointDef._extend(b2JointDef);
|
|
|
|
function b2RevoluteJoint(def) {
|
|
this.parent.call(this, def);
|
|
this.m_localAnchorA = def.localAnchorA.Clone();
|
|
this.m_localAnchorB = def.localAnchorB.Clone();
|
|
this.m_referenceAngle = def.referenceAngle;
|
|
this.m_impulse = new b2Vec3();
|
|
this.m_motorImpulse = 0;
|
|
this.m_lowerAngle = def.lowerAngle;
|
|
this.m_upperAngle = def.upperAngle;
|
|
this.m_maxMotorTorque = def.maxMotorTorque;
|
|
this.m_motorSpeed = def.motorSpeed;
|
|
this.m_enableLimit = def.enableLimit;
|
|
this.m_enableMotor = def.enableMotor;
|
|
this.m_limitState = b2Joint.e_inactiveLimit;
|
|
this.m_indexA = 0;
|
|
this.m_indexB = 0;
|
|
this.m_rA = new b2Vec2();
|
|
this.m_rB = new b2Vec2();
|
|
this.m_localCenterA = new b2Vec2();
|
|
this.m_localCenterB = new b2Vec2();
|
|
this.m_invMassA = 0;
|
|
this.m_invMassB = 0;
|
|
this.m_invIA = 0;
|
|
this.m_invIB = 0;
|
|
this.m_mass = new b2Mat33();
|
|
this.m_motorMass = 0
|
|
}
|
|
b2RevoluteJoint.prototype = {
|
|
GetAnchorA: function () {
|
|
return this.m_bodyA.GetWorldPoint(this.m_localAnchorA)
|
|
},
|
|
GetAnchorB: function () {
|
|
return this.m_bodyB.GetWorldPoint(this.m_localAnchorB)
|
|
},
|
|
GetLocalAnchorA: function () {
|
|
return this.m_localAnchorA
|
|
},
|
|
GetLocalAnchorB: function () {
|
|
return this.m_localAnchorB
|
|
},
|
|
GetReferenceAngle: function () {
|
|
return this.m_referenceAngle
|
|
},
|
|
GetJointAngle: function () {
|
|
var bA = this.m_bodyA;
|
|
var bB = this.m_bodyB;
|
|
return bB.m_sweep.a - bA.m_sweep.a - this.m_referenceAngle
|
|
},
|
|
GetJointSpeed: function () {
|
|
var bA = this.m_bodyA;
|
|
var bB = this.m_bodyB;
|
|
return bB.m_angularVelocity - bA.m_angularVelocity
|
|
},
|
|
IsLimitEnabled: function () {
|
|
return this.m_enableLimit
|
|
},
|
|
EnableLimit: function (flag) {
|
|
if (flag != this.m_enableLimit) {
|
|
this.m_bodyA.SetAwake(true);
|
|
this.m_bodyB.SetAwake(true);
|
|
this.m_enableLimit = flag;
|
|
this.m_impulse.z = 0
|
|
}
|
|
},
|
|
GetLowerLimit: function () {
|
|
return this.m_lowerAngle
|
|
},
|
|
GetUpperLimit: function () {
|
|
return this.m_upperAngle
|
|
},
|
|
SetLimits: function (lower, upper) {
|
|
if (lower != this.m_lowerAngle || upper != this.m_upperAngle) {
|
|
this.m_bodyA.SetAwake(true);
|
|
this.m_bodyB.SetAwake(true);
|
|
this.m_impulse.z = 0;
|
|
this.m_lowerAngle = lower;
|
|
this.m_upperAngle = upper
|
|
}
|
|
},
|
|
IsMotorEnabled: function () {
|
|
return this.m_enableMotor
|
|
},
|
|
EnableMotor: function (flag) {
|
|
this.m_bodyA.SetAwake(true);
|
|
this.m_bodyB.SetAwake(true);
|
|
this.m_enableMotor = flag
|
|
},
|
|
SetMotorSpeed: function (speed) {
|
|
this.m_bodyA.SetAwake(true);
|
|
this.m_bodyB.SetAwake(true);
|
|
this.m_motorSpeed = speed
|
|
},
|
|
GetMotorSpeed: function () {
|
|
return this.m_motorSpeed
|
|
},
|
|
SetMaxMotorTorque: function (torque) {
|
|
this.m_bodyA.SetAwake(true);
|
|
this.m_bodyB.SetAwake(true);
|
|
this.m_maxMotorTorque = torque
|
|
},
|
|
GetMaxMotorTorque: function () {
|
|
return this.m_maxMotorTorque
|
|
},
|
|
GetReactionForce: function (inv_dt) {
|
|
var P = new b2Vec2(this.m_impulse.x, this.m_impulse.y);
|
|
return b2Vec2.Multiply(inv_dt, P)
|
|
},
|
|
GetReactionTorque: function (inv_dt) {
|
|
return inv_dt * this.m_impulse.z
|
|
},
|
|
GetMotorTorque: function (inv_dt) {
|
|
return inv_dt * this.m_motorImpulse
|
|
},
|
|
InitVelocityConstraints: function (data) {
|
|
this.m_indexA = this.m_bodyA.m_islandIndex;
|
|
this.m_indexB = this.m_bodyB.m_islandIndex;
|
|
this.m_localCenterA = this.m_bodyA.m_sweep.localCenter;
|
|
this.m_localCenterB = this.m_bodyB.m_sweep.localCenter;
|
|
this.m_invMassA = this.m_bodyA.m_invMass;
|
|
this.m_invMassB = this.m_bodyB.m_invMass;
|
|
this.m_invIA = this.m_bodyA.m_invI;
|
|
this.m_invIB = this.m_bodyB.m_invI;
|
|
var aA = data.positions[this.m_indexA].a;
|
|
var vA = data.velocities[this.m_indexA].v.Clone();
|
|
var wA = data.velocities[this.m_indexA].w;
|
|
var aB = data.positions[this.m_indexB].a;
|
|
var vB = data.velocities[this.m_indexB].v.Clone();
|
|
var wB = data.velocities[this.m_indexB].w;
|
|
var qA = new b2Rot(aA),
|
|
qB = new b2Rot(aB);
|
|
this.m_rA = b2Mul_r_v2(qA, b2Vec2.Subtract(this.m_localAnchorA, this.m_localCenterA));
|
|
this.m_rB = b2Mul_r_v2(qB, b2Vec2.Subtract(this.m_localAnchorB, this.m_localCenterB));
|
|
var mA = this.m_invMassA,
|
|
mB = this.m_invMassB;
|
|
var iA = this.m_invIA,
|
|
iB = this.m_invIB;
|
|
var fixedRotation = (iA + iB == 0);
|
|
this.m_mass.ex.x = mA + mB + this.m_rA.y * this.m_rA.y * iA + this.m_rB.y * this.m_rB.y * iB;
|
|
this.m_mass.ey.x = -this.m_rA.y * this.m_rA.x * iA - this.m_rB.y * this.m_rB.x * iB;
|
|
this.m_mass.ez.x = -this.m_rA.y * iA - this.m_rB.y * iB;
|
|
this.m_mass.ex.y = this.m_mass.ey.x;
|
|
this.m_mass.ey.y = mA + mB + this.m_rA.x * this.m_rA.x * iA + this.m_rB.x * this.m_rB.x * iB;
|
|
this.m_mass.ez.y = this.m_rA.x * iA + this.m_rB.x * iB;
|
|
this.m_mass.ex.z = this.m_mass.ez.x;
|
|
this.m_mass.ey.z = this.m_mass.ez.y;
|
|
this.m_mass.ez.z = iA + iB;
|
|
this.m_motorMass = iA + iB;
|
|
if (this.m_motorMass > 0) {
|
|
this.m_motorMass = 1 / this.m_motorMass
|
|
}
|
|
if (this.m_enableMotor == false || fixedRotation) {
|
|
this.m_motorImpulse = 0
|
|
}
|
|
if (this.m_enableLimit && fixedRotation == false) {
|
|
var jointAngle = aB - aA - this.m_referenceAngle;
|
|
if (b2Abs(this.m_upperAngle - this.m_lowerAngle) < 2 * b2_angularSlop) {
|
|
this.m_limitState = b2Joint.e_equalLimits
|
|
} else {
|
|
if (jointAngle <= this.m_lowerAngle) {
|
|
if (this.m_limitState != b2Joint.e_atLowerLimit) {
|
|
this.m_impulse.z = 0
|
|
}
|
|
this.m_limitState = b2Joint.e_atLowerLimit
|
|
} else {
|
|
if (jointAngle >= this.m_upperAngle) {
|
|
if (this.m_limitState != b2Joint.e_atUpperLimit) {
|
|
this.m_impulse.z = 0
|
|
}
|
|
this.m_limitState = b2Joint.e_atUpperLimit
|
|
} else {
|
|
this.m_limitState = b2Joint.e_inactiveLimit;
|
|
this.m_impulse.z = 0
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
this.m_limitState = b2Joint.e_inactiveLimit
|
|
}
|
|
if (data.step.warmStarting) {
|
|
this.m_impulse.Multiply(data.step.dtRatio);
|
|
this.m_motorImpulse *= data.step.dtRatio;
|
|
var P = new b2Vec2(this.m_impulse.x, this.m_impulse.y);
|
|
vA.Subtract(b2Vec2.Multiply(mA, P));
|
|
wA -= iA * (b2Cross_v2_v2(this.m_rA, P) + this.m_motorImpulse + this.m_impulse.z);
|
|
vB.Add(b2Vec2.Multiply(mB, P));
|
|
wB += iB * (b2Cross_v2_v2(this.m_rB, P) + this.m_motorImpulse + this.m_impulse.z)
|
|
} else {
|
|
this.m_impulse.SetZero();
|
|
this.m_motorImpulse = 0
|
|
}
|
|
data.velocities[this.m_indexA].v.Assign(vA);
|
|
data.velocities[this.m_indexA].w = wA;
|
|
data.velocities[this.m_indexB].v.Assign(vB);
|
|
data.velocities[this.m_indexB].w = wB
|
|
},
|
|
SolveVelocityConstraints: function (data) {
|
|
var vA = data.velocities[this.m_indexA].v.Clone();
|
|
var wA = data.velocities[this.m_indexA].w;
|
|
var vB = data.velocities[this.m_indexB].v.Clone();
|
|
var wB = data.velocities[this.m_indexB].w;
|
|
var mA = this.m_invMassA,
|
|
mB = this.m_invMassB;
|
|
var iA = this.m_invIA,
|
|
iB = this.m_invIB;
|
|
var fixedRotation = (iA + iB == 0);
|
|
if (this.m_enableMotor && this.m_limitState != b2Joint.e_equalLimits && fixedRotation == false) {
|
|
var Cdot = wB - wA - this.m_motorSpeed;
|
|
var impulse = -this.m_motorMass * Cdot;
|
|
var oldImpulse = this.m_motorImpulse;
|
|
var maxImpulse = data.step.dt * this.m_maxMotorTorque;
|
|
this.m_motorImpulse = b2Clamp(this.m_motorImpulse + impulse, -maxImpulse, maxImpulse);
|
|
impulse = this.m_motorImpulse - oldImpulse;
|
|
wA -= iA * impulse;
|
|
wB += iB * impulse
|
|
}
|
|
if (this.m_enableLimit && this.m_limitState != b2Joint.e_inactiveLimit && fixedRotation == false) {
|
|
var Cdot1 = b2Vec2.Subtract(b2Vec2.Subtract(b2Vec2.Add(vB, b2Cross_f_v2(wB, this.m_rB)), vA), b2Cross_f_v2(wA, this.m_rA));
|
|
var Cdot2 = wB - wA;
|
|
var Cdot = new b2Vec3(Cdot1.x, Cdot1.y, Cdot2);
|
|
var impulse = this.m_mass.Solve33(Cdot).Negate();
|
|
if (this.m_limitState == b2Joint.e_equalLimits) {
|
|
this.m_impulse.Add(impulse)
|
|
} else {
|
|
if (this.m_limitState == b2Joint.e_atLowerLimit) {
|
|
var newImpulse = this.m_impulse.z + impulse.z;
|
|
if (newImpulse < 0) {
|
|
var rhs = b2Vec2.Add(Cdot1.Negate(), b2Vec2.Multiply(this.m_impulse.z, new b2Vec2(this.m_mass.ez.x, this.m_mass.ez.y)));
|
|
var reduced = this.m_mass.Solve22(rhs);
|
|
impulse.x = reduced.x;
|
|
impulse.y = reduced.y;
|
|
impulse.z = -this.m_impulse.z;
|
|
this.m_impulse.x += reduced.x;
|
|
this.m_impulse.y += reduced.y;
|
|
this.m_impulse.z = 0
|
|
} else {
|
|
this.m_impulse.Add(impulse)
|
|
}
|
|
} else {
|
|
if (this.m_limitState == b2Joint.e_atUpperLimit) {
|
|
var newImpulse = this.m_impulse.z + impulse.z;
|
|
if (newImpulse > 0) {
|
|
var rhs = b2Vec2.Add(Cdot1.Negate(), b2Vec2.Multiply(this.m_impulse.z, new b2Vec2(this.m_mass.ez.x, this.m_mass.ez.y)));
|
|
var reduced = this.m_mass.Solve22(rhs);
|
|
impulse.x = reduced.x;
|
|
impulse.y = reduced.y;
|
|
impulse.z = -this.m_impulse.z;
|
|
this.m_impulse.x += reduced.x;
|
|
this.m_impulse.y += reduced.y;
|
|
this.m_impulse.z = 0
|
|
} else {
|
|
this.m_impulse.Add(impulse)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
var P = new b2Vec2(impulse.x, impulse.y);
|
|
vA.Subtract(b2Vec2.Multiply(mA, P));
|
|
wA -= iA * (b2Cross_v2_v2(this.m_rA, P) + impulse.z);
|
|
vB.Add(b2Vec2.Multiply(mB, P));
|
|
wB += iB * (b2Cross_v2_v2(this.m_rB, P) + impulse.z)
|
|
} else {
|
|
var Cdot = b2Vec2.Subtract(b2Vec2.Subtract(b2Vec2.Add(vB, b2Cross_f_v2(wB, this.m_rB)), vA), b2Cross_f_v2(wA, this.m_rA));
|
|
var impulse = this.m_mass.Solve22(Cdot.Negate());
|
|
this.m_impulse.x += impulse.x;
|
|
this.m_impulse.y += impulse.y;
|
|
vA.Subtract(b2Vec2.Multiply(mA, impulse));
|
|
wA -= iA * b2Cross_v2_v2(this.m_rA, impulse);
|
|
vB.Add(b2Vec2.Multiply(mB, impulse));
|
|
wB += iB * b2Cross_v2_v2(this.m_rB, impulse)
|
|
}
|
|
data.velocities[this.m_indexA].v.Assign(vA);
|
|
data.velocities[this.m_indexA].w = wA;
|
|
data.velocities[this.m_indexB].v.Assign(vB);
|
|
data.velocities[this.m_indexB].w = wB
|
|
},
|
|
SolvePositionConstraints: function (data) {
|
|
var cA = data.positions[this.m_indexA].c.Clone();
|
|
var aA = data.positions[this.m_indexA].a;
|
|
var cB = data.positions[this.m_indexB].c.Clone();
|
|
var aB = data.positions[this.m_indexB].a;
|
|
var qA = new b2Rot(aA),
|
|
qB = new b2Rot(aB);
|
|
var angularError = 0;
|
|
var positionError = 0;
|
|
var fixedRotation = (this.m_invIA + this.m_invIB == 0);
|
|
if (this.m_enableLimit && this.m_limitState != b2Joint.e_inactiveLimit && fixedRotation == false) {
|
|
var angle = aB - aA - this.m_referenceAngle;
|
|
var limitImpulse = 0;
|
|
if (this.m_limitState == b2Joint.e_equalLimits) {
|
|
var C = b2Clamp(angle - this.m_lowerAngle, -b2_maxAngularCorrection, b2_maxAngularCorrection);
|
|
limitImpulse = -this.m_motorMass * C;
|
|
angularError = b2Abs(C)
|
|
} else {
|
|
if (this.m_limitState == b2Joint.e_atLowerLimit) {
|
|
var C = angle - this.m_lowerAngle;
|
|
angularError = -C;
|
|
C = b2Clamp(C + b2_angularSlop, -b2_maxAngularCorrection, 0);
|
|
limitImpulse = -this.m_motorMass * C
|
|
} else {
|
|
if (this.m_limitState == b2Joint.e_atUpperLimit) {
|
|
var C = angle - this.m_upperAngle;
|
|
angularError = C;
|
|
C = b2Clamp(C - b2_angularSlop, 0, b2_maxAngularCorrection);
|
|
limitImpulse = -this.m_motorMass * C
|
|
}
|
|
}
|
|
}
|
|
aA -= this.m_invIA * limitImpulse;
|
|
aB += this.m_invIB * limitImpulse
|
|
}
|
|
qA.Set(aA);
|
|
qB.Set(aB);
|
|
var rA = b2Mul_r_v2(qA, b2Vec2.Subtract(this.m_localAnchorA, this.m_localCenterA));
|
|
var rB = b2Mul_r_v2(qB, b2Vec2.Subtract(this.m_localAnchorB, this.m_localCenterB));
|
|
var C = b2Vec2.Subtract(b2Vec2.Subtract(b2Vec2.Add(cB, rB), cA), rA);
|
|
positionError = C.Length();
|
|
var mA = this.m_invMassA,
|
|
mB = this.m_invMassB;
|
|
var iA = this.m_invIA,
|
|
iB = this.m_invIB;
|
|
var K = new b2Mat22();
|
|
K.ex.x = mA + mB + iA * rA.y * rA.y + iB * rB.y * rB.y;
|
|
K.ex.y = -iA * rA.x * rA.y - iB * rB.x * rB.y;
|
|
K.ey.x = K.ex.y;
|
|
K.ey.y = mA + mB + iA * rA.x * rA.x + iB * rB.x * rB.x;
|
|
var impulse = K.Solve(C).Negate();
|
|
cA.Subtract(b2Vec2.Multiply(mA, impulse));
|
|
aA -= iA * b2Cross_v2_v2(rA, impulse);
|
|
cB.Add(b2Vec2.Multiply(mB, impulse));
|
|
aB += iB * b2Cross_v2_v2(rB, impulse);
|
|
data.positions[this.m_indexA].c.Assign(cA);
|
|
data.positions[this.m_indexA].a = aA;
|
|
data.positions[this.m_indexB].c.Assign(cB);
|
|
data.positions[this.m_indexB].a = aB;
|
|
return positionError <= b2_linearSlop && angularError <= b2_angularSlop
|
|
},
|
|
_serialize: function (out) {
|
|
var obj = out || {};
|
|
this.parent.prototype._serialize.call(this, obj);
|
|
obj.localAnchorA = this.m_localAnchorA._serialize();
|
|
obj.localAnchorB = this.m_localAnchorB._serialize();
|
|
obj.referenceAngle = this.m_referenceAngle;
|
|
obj.lowerAngle = this.m_lowerAngle;
|
|
obj.upperAngle = this.m_upperAngle;
|
|
obj.maxMotorTorque = this.m_maxMotorTorque;
|
|
obj.motorSpeed = this.m_motorSpeed;
|
|
obj.enableLimit = this.m_enableLimit;
|
|
obj.enableMotor = this.m_enableMotor;
|
|
return obj
|
|
}
|
|
};
|
|
b2RevoluteJoint._extend(b2Joint);
|
|
|
|
function b2MouseJointDef() {
|
|
this.parent.call(this);
|
|
this.type = b2Joint.e_mouseJoint;
|
|
this.target = new b2Vec2(0, 0);
|
|
this.maxForce = 0;
|
|
this.frequencyHz = 5;
|
|
this.dampingRatio = 0.7;
|
|
Object.seal(this)
|
|
}
|
|
b2MouseJointDef._extend(b2JointDef);
|
|
|
|
function b2MouseJoint(def) {
|
|
this.parent.call(this, def);
|
|
this.m_targetA = def.target.Clone();
|
|
this.m_localAnchorB = b2MulT_t_v2(this.m_bodyB.GetTransform(), this.m_targetA);
|
|
this.m_maxForce = def.maxForce;
|
|
this.m_impulse = new b2Vec2();
|
|
this.m_frequencyHz = def.frequencyHz;
|
|
this.m_dampingRatio = def.dampingRatio;
|
|
this.m_beta = 0;
|
|
this.m_gamma = 0;
|
|
this.m_indexA = 0;
|
|
this.m_indexB = 0;
|
|
this.m_rB = new b2Vec2();
|
|
this.m_localCenterB = new b2Vec2();
|
|
this.m_invMassB = 0;
|
|
this.m_invIB = 0;
|
|
this.m_mass = new b2Mat22();
|
|
this.m_C = new b2Vec2()
|
|
}
|
|
b2MouseJoint.prototype = {
|
|
GetAnchorA: function () {
|
|
return this.m_targetA
|
|
},
|
|
GetAnchorB: function () {
|
|
return this.m_bodyB.GetWorldPoint(this.m_localAnchorB)
|
|
},
|
|
GetReactionForce: function (inv_dt) {
|
|
return b2Vec2.Multiply(inv_dt, this.m_impulse)
|
|
},
|
|
GetReactionTorque: function (inv_dt) {
|
|
return inv_dt * 0
|
|
},
|
|
SetTarget: function (target) {
|
|
if (this.m_bodyB.IsAwake() == false) {
|
|
this.m_bodyB.SetAwake(true)
|
|
}
|
|
this.m_targetA.Assign(target)
|
|
},
|
|
GetTarget: function () {
|
|
return this.m_targetA
|
|
},
|
|
SetMaxForce: function (force) {
|
|
this.m_maxForce = force
|
|
},
|
|
GetMaxForce: function () {
|
|
return this.m_maxForce
|
|
},
|
|
SetFrequency: function (hz) {
|
|
this.m_frequencyHz = hz
|
|
},
|
|
GetFrequency: function () {
|
|
return this.m_frequencyHz
|
|
},
|
|
SetDampingRatio: function (ratio) {
|
|
this.m_dampingRatio = ratio
|
|
},
|
|
GetDampingRatio: function () {
|
|
return this.m_dampingRatio
|
|
},
|
|
ShiftOrigin: function (newOrigin) {
|
|
this.m_targetA.Subtract(newOrigin)
|
|
},
|
|
InitVelocityConstraints: function (data) {
|
|
this.m_indexB = this.m_bodyB.m_islandIndex;
|
|
this.m_localCenterB.Assign(this.m_bodyB.m_sweep.localCenter);
|
|
this.m_invMassB = this.m_bodyB.m_invMass;
|
|
this.m_invIB = this.m_bodyB.m_invI;
|
|
var cB = data.positions[this.m_indexB].c.Clone();
|
|
var aB = data.positions[this.m_indexB].a;
|
|
var vB = data.velocities[this.m_indexB].v.Clone();
|
|
var wB = data.velocities[this.m_indexB].w;
|
|
var qB = new b2Rot(aB);
|
|
var mass = this.m_bodyB.GetMass();
|
|
var omega = 2 * b2_pi * this.m_frequencyHz;
|
|
var d = 2 * mass * this.m_dampingRatio * omega;
|
|
var k = mass * (omega * omega);
|
|
var h = data.step.dt;
|
|
this.m_gamma = h * (d + h * k);
|
|
if (this.m_gamma != 0) {
|
|
this.m_gamma = 1 / this.m_gamma
|
|
}
|
|
this.m_beta = h * k * this.m_gamma;
|
|
this.m_rB.Assign(b2Mul_r_v2(qB, b2Vec2.Subtract(this.m_localAnchorB, this.m_localCenterB)));
|
|
var K = new b2Mat22();
|
|
K.ex.x = this.m_invMassB + this.m_invIB * this.m_rB.y * this.m_rB.y + this.m_gamma;
|
|
K.ex.y = -this.m_invIB * this.m_rB.x * this.m_rB.y;
|
|
K.ey.x = K.ex.y;
|
|
K.ey.y = this.m_invMassB + this.m_invIB * this.m_rB.x * this.m_rB.x + this.m_gamma;
|
|
this.m_mass.Assign(K.GetInverse());
|
|
this.m_C.Assign(b2Vec2.Subtract(b2Vec2.Add(cB, this.m_rB), this.m_targetA));
|
|
this.m_C.Multiply(this.m_beta);
|
|
wB *= 0.98;
|
|
if (data.step.warmStarting) {
|
|
this.m_impulse.Multiply(data.step.dtRatio);
|
|
vB.Add(b2Vec2.Multiply(this.m_invMassB, this.m_impulse));
|
|
wB += this.m_invIB * b2Cross_v2_v2(this.m_rB, this.m_impulse)
|
|
} else {
|
|
this.m_impulse.SetZero()
|
|
}
|
|
data.velocities[this.m_indexB].v.Assign(vB);
|
|
data.velocities[this.m_indexB].w = wB
|
|
},
|
|
SolveVelocityConstraints: function (data) {
|
|
var vB = data.velocities[this.m_indexB].v.Clone();
|
|
var wB = data.velocities[this.m_indexB].w;
|
|
var Cdot = b2Vec2.Add(vB, b2Cross_f_v2(wB, this.m_rB));
|
|
var impulse = b2Mul_m22_v2(this.m_mass, (b2Vec2.Add(b2Vec2.Add(Cdot, this.m_C), b2Vec2.Multiply(this.m_gamma, this.m_impulse))).Negate());
|
|
var oldImpulse = this.m_impulse.Clone();
|
|
this.m_impulse.Add(impulse);
|
|
var maxImpulse = data.step.dt * this.m_maxForce;
|
|
if (this.m_impulse.LengthSquared() > maxImpulse * maxImpulse) {
|
|
this.m_impulse.Multiply(maxImpulse / this.m_impulse.Length())
|
|
}
|
|
impulse.Assign(b2Vec2.Subtract(this.m_impulse, oldImpulse));
|
|
vB.Add(b2Vec2.Multiply(this.m_invMassB, impulse));
|
|
wB += this.m_invIB * b2Cross_v2_v2(this.m_rB, impulse);
|
|
data.velocities[this.m_indexB].v.Assign(vB);
|
|
data.velocities[this.m_indexB].w = wB
|
|
},
|
|
SolvePositionConstraints: function (data) {
|
|
return true
|
|
}
|
|
};
|
|
b2MouseJoint._extend(b2Joint);
|
|
|
|
function b2DistanceJointDef() {
|
|
this.parent.call(this);
|
|
this.type = b2Joint.e_distanceJoint;
|
|
this.localAnchorA = new b2Vec2(0, 0);
|
|
this.localAnchorB = new b2Vec2(0, 0);
|
|
this.length = 1;
|
|
this.frequencyHz = 0;
|
|
this.dampingRatio = 0;
|
|
Object.seal(this)
|
|
}
|
|
b2DistanceJointDef.prototype = {
|
|
Initialize: function (b1, b2, anchor1, anchor2) {
|
|
this.bodyA = b1;
|
|
this.bodyB = b2;
|
|
this.localAnchorA = this.bodyA.GetLocalPoint(anchor1);
|
|
this.localAnchorB = this.bodyB.GetLocalPoint(anchor2);
|
|
var d = b2Vec2.Subtract(anchor2, anchor1);
|
|
this.length = d.Length()
|
|
},
|
|
_deserialize: function (data, bodies, joints) {
|
|
this.parent.prototype._deserialize.call(this, data, bodies, joints);
|
|
this.localAnchorA._deserialize(data.localAnchorA);
|
|
this.localAnchorB._deserialize(data.localAnchorB);
|
|
this.length = data.length;
|
|
this.frequencyHz = data.frequencyHz;
|
|
this.dampingRatio = data.dampingRatio
|
|
}
|
|
};
|
|
b2DistanceJointDef._extend(b2JointDef);
|
|
|
|
function b2DistanceJoint(def) {
|
|
this.parent.call(this, def);
|
|
this.m_localAnchorA = def.localAnchorA.Clone();
|
|
this.m_localAnchorB = def.localAnchorB.Clone();
|
|
this.m_length = def.length;
|
|
this.m_frequencyHz = def.frequencyHz;
|
|
this.m_dampingRatio = def.dampingRatio;
|
|
this.m_impulse = 0;
|
|
this.m_gamma = 0;
|
|
this.m_bias = 0;
|
|
this.m_indexA = 0;
|
|
this.m_indexB = 0;
|
|
this.m_u = new b2Vec2();
|
|
this.m_rA = new b2Vec2();
|
|
this.m_rB = new b2Vec2();
|
|
this.m_localCenterA = new b2Vec2();
|
|
this.m_localCenterB = new b2Vec2();
|
|
this.m_invMassA = 0;
|
|
this.m_invMassB = 0;
|
|
this.m_invIA = 0;
|
|
this.m_invIB = 0;
|
|
this.m_mass = 0
|
|
}
|
|
b2DistanceJoint.prototype = {
|
|
GetAnchorA: function () {
|
|
return this.m_bodyA.GetWorldPoint(this.m_localAnchorA)
|
|
},
|
|
GetAnchorB: function () {
|
|
return this.m_bodyB.GetWorldPoint(this.m_localAnchorB)
|
|
},
|
|
GetReactionForce: function (inv_dt) {
|
|
var F = b2Vec2.Multiply((inv_dt * this.m_impulse), this.m_u);
|
|
return F
|
|
},
|
|
GetReactionTorque: function (inv_dt) {
|
|
return 0
|
|
},
|
|
GetLocalAnchorA: function () {
|
|
return this.m_localAnchorA
|
|
},
|
|
GetLocalAnchorB: function () {
|
|
return this.m_localAnchorB
|
|
},
|
|
SetLength: function (length) {
|
|
this.m_length = length
|
|
},
|
|
GetLength: function () {
|
|
return this.m_length
|
|
},
|
|
SetFrequency: function (hz) {
|
|
this.m_frequencyHz = hz
|
|
},
|
|
GetFrequency: function () {
|
|
return this.m_frequencyHz
|
|
},
|
|
SetDampingRatio: function (ratio) {
|
|
this.m_dampingRatio = ratio
|
|
},
|
|
GetDampingRatio: function () {
|
|
return this.m_dampingRatio
|
|
},
|
|
InitVelocityConstraints: function (data) {
|
|
this.m_indexA = this.m_bodyA.m_islandIndex;
|
|
this.m_indexB = this.m_bodyB.m_islandIndex;
|
|
this.m_localCenterA.Assign(this.m_bodyA.m_sweep.localCenter);
|
|
this.m_localCenterB.Assign(this.m_bodyB.m_sweep.localCenter);
|
|
this.m_invMassA = this.m_bodyA.m_invMass;
|
|
this.m_invMassB = this.m_bodyB.m_invMass;
|
|
this.m_invIA = this.m_bodyA.m_invI;
|
|
this.m_invIB = this.m_bodyB.m_invI;
|
|
var cA = data.positions[this.m_indexA].c.Clone();
|
|
var aA = data.positions[this.m_indexA].a;
|
|
var vA = data.velocities[this.m_indexA].v.Clone();
|
|
var wA = data.velocities[this.m_indexA].w;
|
|
var cB = data.positions[this.m_indexB].c.Clone();
|
|
var aB = data.positions[this.m_indexB].a;
|
|
var vB = data.velocities[this.m_indexB].v.Clone();
|
|
var wB = data.velocities[this.m_indexB].w;
|
|
var qA = new b2Rot(aA),
|
|
qB = new b2Rot(aB);
|
|
this.m_rA = b2Mul_r_v2(qA, b2Vec2.Subtract(this.m_localAnchorA, this.m_localCenterA));
|
|
this.m_rB = b2Mul_r_v2(qB, b2Vec2.Subtract(this.m_localAnchorB, this.m_localCenterB));
|
|
this.m_u = b2Vec2.Subtract(b2Vec2.Subtract(b2Vec2.Add(cB, this.m_rB), cA), this.m_rA);
|
|
var length = this.m_u.Length();
|
|
if (length > b2_linearSlop) {
|
|
this.m_u.Multiply(1 / length)
|
|
} else {
|
|
this.m_u.Set(0, 0)
|
|
}
|
|
var crAu = b2Cross_v2_v2(this.m_rA, this.m_u);
|
|
var crBu = b2Cross_v2_v2(this.m_rB, this.m_u);
|
|
var invMass = this.m_invMassA + this.m_invIA * crAu * crAu + this.m_invMassB + this.m_invIB * crBu * crBu;
|
|
this.m_mass = invMass != 0 ? 1 / invMass : 0;
|
|
if (this.m_frequencyHz > 0) {
|
|
var C = length - this.m_length;
|
|
var omega = 2 * b2_pi * this.m_frequencyHz;
|
|
var d = 2 * this.m_mass * this.m_dampingRatio * omega;
|
|
var k = this.m_mass * omega * omega;
|
|
var h = data.step.dt;
|
|
this.m_gamma = h * (d + h * k);
|
|
this.m_gamma = this.m_gamma != 0 ? 1 / this.m_gamma : 0;
|
|
this.m_bias = C * h * k * this.m_gamma;
|
|
invMass += this.m_gamma;
|
|
this.m_mass = invMass != 0 ? 1 / invMass : 0
|
|
} else {
|
|
this.m_gamma = 0;
|
|
this.m_bias = 0
|
|
}
|
|
if (data.step.warmStarting) {
|
|
this.m_impulse *= data.step.dtRatio;
|
|
var P = b2Vec2.Multiply(this.m_impulse, this.m_u);
|
|
vA.Subtract(b2Vec2.Multiply(this.m_invMassA, P));
|
|
wA -= this.m_invIA * b2Cross_v2_v2(this.m_rA, P);
|
|
vB.Add(b2Vec2.Multiply(this.m_invMassB, P));
|
|
wB += this.m_invIB * b2Cross_v2_v2(this.m_rB, P)
|
|
} else {
|
|
this.m_impulse = 0
|
|
}
|
|
data.velocities[this.m_indexA].v.Assign(vA);
|
|
data.velocities[this.m_indexA].w = wA;
|
|
data.velocities[this.m_indexB].v.Assign(vB);
|
|
data.velocities[this.m_indexB].w = wB
|
|
},
|
|
SolveVelocityConstraints: function (data) {
|
|
var vA = data.velocities[this.m_indexA].v.Clone();
|
|
var wA = data.velocities[this.m_indexA].w;
|
|
var vB = data.velocities[this.m_indexB].v.Clone();
|
|
var wB = data.velocities[this.m_indexB].w;
|
|
var vpA = b2Vec2.Add(vA, b2Cross_f_v2(wA, this.m_rA));
|
|
var vpB = b2Vec2.Add(vB, b2Cross_f_v2(wB, this.m_rB));
|
|
var Cdot = b2Dot_v2_v2(this.m_u, b2Vec2.Subtract(vpB, vpA));
|
|
var impulse = -this.m_mass * (Cdot + this.m_bias + this.m_gamma * this.m_impulse);
|
|
this.m_impulse += impulse;
|
|
var P = b2Vec2.Multiply(impulse, this.m_u);
|
|
vA.Subtract(b2Vec2.Multiply(this.m_invMassA, P));
|
|
wA -= this.m_invIA * b2Cross_v2_v2(this.m_rA, P);
|
|
vB.Add(b2Vec2.Multiply(this.m_invMassB, P));
|
|
wB += this.m_invIB * b2Cross_v2_v2(this.m_rB, P);
|
|
data.velocities[this.m_indexA].v.Assign(vA);
|
|
data.velocities[this.m_indexA].w = wA;
|
|
data.velocities[this.m_indexB].v.Assign(vB);
|
|
data.velocities[this.m_indexB].w = wB
|
|
},
|
|
SolvePositionConstraints: function (data) {
|
|
if (this.m_frequencyHz > 0) {
|
|
return true
|
|
}
|
|
var cA = data.positions[this.m_indexA].c.Clone();
|
|
var aA = data.positions[this.m_indexA].a;
|
|
var cB = data.positions[this.m_indexB].c.Clone();
|
|
var aB = data.positions[this.m_indexB].a;
|
|
var qA = new b2Rot(aA),
|
|
qB = new b2Rot(aB);
|
|
var rA = b2Mul_r_v2(qA, b2Vec2.Subtract(this.m_localAnchorA, this.m_localCenterA));
|
|
var rB = b2Mul_r_v2(qB, b2Vec2.Subtract(this.m_localAnchorB, this.m_localCenterB));
|
|
var u = b2Vec2.Subtract(b2Vec2.Subtract(b2Vec2.Add(cB, rB), cA), rA);
|
|
var length = u.Normalize();
|
|
var C = length - this.m_length;
|
|
C = b2Clamp(C, -b2_maxLinearCorrection, b2_maxLinearCorrection);
|
|
var impulse = -this.m_mass * C;
|
|
var P = b2Vec2.Multiply(impulse, u);
|
|
cA.Subtract(b2Vec2.Multiply(this.m_invMassA, P));
|
|
aA -= this.m_invIA * b2Cross_v2_v2(rA, P);
|
|
cB.Add(b2Vec2.Multiply(this.m_invMassB, P));
|
|
aB += this.m_invIB * b2Cross_v2_v2(rB, P);
|
|
data.positions[this.m_indexA].c.Assign(cA);
|
|
data.positions[this.m_indexA].a = aA;
|
|
data.positions[this.m_indexB].c.Assign(cB);
|
|
data.positions[this.m_indexB].a = aB;
|
|
return b2Abs(C) < b2_linearSlop
|
|
},
|
|
_serialize: function (out) {
|
|
var obj = out || {};
|
|
this.parent.prototype._serialize.call(this, obj);
|
|
obj.localAnchorA = this.m_localAnchorA._serialize();
|
|
obj.localAnchorB = this.m_localAnchorB._serialize();
|
|
obj.length = this.m_length;
|
|
obj.frequencyHz = this.m_frequencyHz;
|
|
obj.dampingRatio = this.m_dampingRatio;
|
|
return obj
|
|
}
|
|
};
|
|
b2DistanceJoint._extend(b2Joint);
|
|
|
|
function b2PrismaticJointDef() {
|
|
this.parent.call(this);
|
|
this.type = b2Joint.e_prismaticJoint;
|
|
this.localAnchorA = new b2Vec2();
|
|
this.localAnchorB = new b2Vec2();
|
|
this.localAxisA = new b2Vec2(1, 0);
|
|
this.referenceAngle = 0;
|
|
this.enableLimit = false;
|
|
this.lowerTranslation = 0;
|
|
this.upperTranslation = 0;
|
|
this.enableMotor = false;
|
|
this.maxMotorForce = 0;
|
|
this.motorSpeed = 0;
|
|
Object.seal(this)
|
|
}
|
|
b2PrismaticJointDef.prototype = {
|
|
Initialize: function (bA, bB, anchor, axis) {
|
|
this.bodyA = bA;
|
|
this.bodyB = bB;
|
|
this.localAnchorA = this.bodyA.GetLocalPoint(anchor);
|
|
this.localAnchorB = this.bodyB.GetLocalPoint(anchor);
|
|
this.localAxisA = this.bodyA.GetLocalVector(axis);
|
|
this.referenceAngle = this.bodyB.GetAngle() - this.bodyA.GetAngle()
|
|
},
|
|
_deserialize: function (data, bodies, joints) {
|
|
this.parent.prototype._deserialize.call(this, data, bodies, joints);
|
|
this.localAnchorA._deserialize(data.localAnchorA);
|
|
this.localAnchorB._deserialize(data.localAnchorB);
|
|
this.localAxisA._deserialize(data.localAxisA);
|
|
this.referenceAngle = data.referenceAngle;
|
|
this.enableLimit = data.enableLimit;
|
|
this.lowerTranslation = data.lowerTranslation;
|
|
this.upperTranslation = data.upperTranslation;
|
|
this.enableMotor = data.enableMotor;
|
|
this.maxMotorForce = data.maxMotorForce;
|
|
this.motorSpeed = data.motorSpeed
|
|
}
|
|
};
|
|
b2PrismaticJointDef._extend(b2JointDef);
|
|
|
|
function b2PrismaticJoint(def) {
|
|
this.parent.call(this, def);
|
|
this.m_localAnchorA = def.localAnchorA.Clone();
|
|
this.m_localAnchorB = def.localAnchorB.Clone();
|
|
this.m_localXAxisA = def.localAxisA.Clone();
|
|
this.m_localXAxisA.Normalize();
|
|
this.m_localYAxisA = b2Cross_f_v2(1, this.m_localXAxisA);
|
|
this.m_referenceAngle = def.referenceAngle;
|
|
this.m_impulse = new b2Vec3();
|
|
this.m_motorMass = 0;
|
|
this.m_motorImpulse = 0;
|
|
this.m_lowerTranslation = def.lowerTranslation;
|
|
this.m_upperTranslation = def.upperTranslation;
|
|
this.m_maxMotorForce = def.maxMotorForce;
|
|
this.m_motorSpeed = def.motorSpeed;
|
|
this.m_enableLimit = def.enableLimit;
|
|
this.m_enableMotor = def.enableMotor;
|
|
this.m_limitState = b2Joint.e_inactiveLimit;
|
|
this.m_axis = new b2Vec2();
|
|
this.m_perp = new b2Vec2();
|
|
this.m_indexA = 0;
|
|
this.m_indexB = 0;
|
|
this.m_localCenterA = new b2Vec2();
|
|
this.m_localCenterB = new b2Vec2();
|
|
this.m_invMassA = 0;
|
|
this.m_invMassB = 0;
|
|
this.m_invIA = 0;
|
|
this.m_invIB = 0;
|
|
this.m_s1 = 0, this.m_s2 = 0;
|
|
this.m_a1 = 0, this.m_a2 = 0;
|
|
this.m_K = new b2Mat33();
|
|
this.m_motorMass = 0
|
|
}
|
|
b2PrismaticJoint.prototype = {
|
|
GetAnchorA: function () {
|
|
return this.m_bodyA.GetWorldPoint(this.m_localAnchorA)
|
|
},
|
|
GetAnchorB: function () {
|
|
return this.m_bodyB.GetWorldPoint(this.m_localAnchorB)
|
|
},
|
|
GetReactionForce: function (inv_dt) {
|
|
return b2Vec2.Multiply(inv_dt, b2Vec2.Add(b2Vec2.Multiply(this.m_impulse.x, this.m_perp), b2Vec2.Multiply((this.m_motorImpulse + this.m_impulse.z), this.m_axis)))
|
|
},
|
|
GetReactionTorque: function (inv_dt) {
|
|
return inv_dt * this.m_impulse.y
|
|
},
|
|
GetLocalAnchorA: function () {
|
|
return this.m_localAnchorA
|
|
},
|
|
GetLocalAnchorB: function () {
|
|
return this.m_localAnchorB
|
|
},
|
|
GetLocalAxisA: function () {
|
|
return this.m_localXAxisA
|
|
},
|
|
GetReferenceAngle: function () {
|
|
return this.m_referenceAngle
|
|
},
|
|
GetJointTranslation: function () {
|
|
var pA = this.m_bodyA.GetWorldPoint(this.m_localAnchorA);
|
|
var pB = this.m_bodyB.GetWorldPoint(this.m_localAnchorB);
|
|
var d = b2Vec2.Subtract(pB, pA);
|
|
var axis = this.m_bodyA.GetWorldVector(this.m_localXAxisA);
|
|
var translation = b2Dot_v2_v2(d, axis);
|
|
return translation
|
|
},
|
|
GetJointSpeed: function () {
|
|
var bA = this.m_bodyA;
|
|
var bB = this.m_bodyB;
|
|
var rA = b2Mul_r_v2(bA.m_xf.q, b2Vec2.Subtract(this.m_localAnchorA, bA.m_sweep.localCenter));
|
|
var rB = b2Mul_r_v2(bB.m_xf.q, b2Vec2.Subtract(this.m_localAnchorB, bB.m_sweep.localCenter));
|
|
var p1 = b2Vec2.Add(bA.m_sweep.c, rA);
|
|
var p2 = b2Vec2.Add(bB.m_sweep.c, rB);
|
|
var d = b2Vec2.Subtract(p2, p1);
|
|
var axis = b2Mul_r_v2(bA.m_xf.q, this.m_localXAxisA);
|
|
var vA = bA.m_linearVelocity;
|
|
var vB = bB.m_linearVelocity;
|
|
var wA = bA.m_angularVelocity;
|
|
var wB = bB.m_angularVelocity;
|
|
var speed = b2Dot_v2_v2(d, b2Cross_f_v2(wA, axis)) + b2Dot_v2_v2(axis, b2Vec2.Subtract(b2Vec2.Subtract(b2Vec2.Add(vB, b2Cross_f_v2(wB, rB)), vA), b2Cross_f_v2(wA, rA)));
|
|
return speed
|
|
},
|
|
IsLimitEnabled: function () {
|
|
return this.m_enableLimit
|
|
},
|
|
EnableLimit: function (flag) {
|
|
if (flag != this.m_enableLimit) {
|
|
this.m_bodyA.SetAwake(true);
|
|
this.m_bodyB.SetAwake(true);
|
|
this.m_enableLimit = flag;
|
|
this.m_impulse.z = 0
|
|
}
|
|
},
|
|
GetLowerLimit: function () {
|
|
return this.m_lowerTranslation
|
|
},
|
|
GetUpperLimit: function () {
|
|
return this.m_upperTranslation
|
|
},
|
|
SetLimits: function (lower, upper) {
|
|
if (lower != this.m_lowerTranslation || upper != this.m_upperTranslation) {
|
|
this.m_bodyA.SetAwake(true);
|
|
this.m_bodyB.SetAwake(true);
|
|
this.m_lowerTranslation = lower;
|
|
this.m_upperTranslation = upper;
|
|
this.m_impulse.z = 0
|
|
}
|
|
},
|
|
IsMotorEnabled: function () {
|
|
return this.m_enableMotor
|
|
},
|
|
EnableMotor: function (flag) {
|
|
this.m_bodyA.SetAwake(true);
|
|
this.m_bodyB.SetAwake(true);
|
|
this.m_enableMotor = flag
|
|
},
|
|
SetMotorSpeed: function (speed) {
|
|
this.m_bodyA.SetAwake(true);
|
|
this.m_bodyB.SetAwake(true);
|
|
this.m_motorSpeed = speed
|
|
},
|
|
GetMotorSpeed: function () {
|
|
return this.m_motorSpeed
|
|
},
|
|
SetMaxMotorForce: function (force) {
|
|
this.m_bodyA.SetAwake(true);
|
|
this.m_bodyB.SetAwake(true);
|
|
this.m_maxMotorForce = force
|
|
},
|
|
GetMaxMotorForce: function () {
|
|
return this.m_maxMotorForce
|
|
},
|
|
GetMotorForce: function (inv_dt) {
|
|
return inv_dt * this.m_motorImpulse
|
|
},
|
|
InitVelocityConstraints: function (data) {
|
|
this.m_indexA = this.m_bodyA.m_islandIndex;
|
|
this.m_indexB = this.m_bodyB.m_islandIndex;
|
|
this.m_localCenterA = this.m_bodyA.m_sweep.localCenter;
|
|
this.m_localCenterB = this.m_bodyB.m_sweep.localCenter;
|
|
this.m_invMassA = this.m_bodyA.m_invMass;
|
|
this.m_invMassB = this.m_bodyB.m_invMass;
|
|
this.m_invIA = this.m_bodyA.m_invI;
|
|
this.m_invIB = this.m_bodyB.m_invI;
|
|
var cA = data.positions[this.m_indexA].c.Clone();
|
|
var aA = data.positions[this.m_indexA].a;
|
|
var vA = data.velocities[this.m_indexA].v.Clone();
|
|
var wA = data.velocities[this.m_indexA].w;
|
|
var cB = data.positions[this.m_indexB].c.Clone();
|
|
var aB = data.positions[this.m_indexB].a;
|
|
var vB = data.velocities[this.m_indexB].v.Clone();
|
|
var wB = data.velocities[this.m_indexB].w;
|
|
var qA = new b2Rot(aA),
|
|
qB = new b2Rot(aB);
|
|
var rA = b2Mul_r_v2(qA, b2Vec2.Subtract(this.m_localAnchorA, this.m_localCenterA));
|
|
var rB = b2Mul_r_v2(qB, b2Vec2.Subtract(this.m_localAnchorB, this.m_localCenterB));
|
|
var d = b2Vec2.Add(b2Vec2.Subtract(cB, cA), b2Vec2.Subtract(rB, rA));
|
|
var mA = this.m_invMassA,
|
|
mB = this.m_invMassB;
|
|
var iA = this.m_invIA,
|
|
iB = this.m_invIB;
|
|
this.m_axis = b2Mul_r_v2(qA, this.m_localXAxisA);
|
|
this.m_a1 = b2Cross_v2_v2(b2Vec2.Add(d, rA), this.m_axis);
|
|
this.m_a2 = b2Cross_v2_v2(rB, this.m_axis);
|
|
this.m_motorMass = mA + mB + iA * this.m_a1 * this.m_a1 + iB * this.m_a2 * this.m_a2;
|
|
if (this.m_motorMass > 0) {
|
|
this.m_motorMass = 1 / this.m_motorMass
|
|
}
|
|
this.m_perp = b2Mul_r_v2(qA, this.m_localYAxisA);
|
|
this.m_s1 = b2Cross_v2_v2(b2Vec2.Add(d, rA), this.m_perp);
|
|
this.m_s2 = b2Cross_v2_v2(rB, this.m_perp);
|
|
var k11 = mA + mB + iA * this.m_s1 * this.m_s1 + iB * this.m_s2 * this.m_s2;
|
|
var k12 = iA * this.m_s1 + iB * this.m_s2;
|
|
var k13 = iA * this.m_s1 * this.m_a1 + iB * this.m_s2 * this.m_a2;
|
|
var k22 = iA + iB;
|
|
if (k22 == 0) {
|
|
k22 = 1
|
|
}
|
|
var k23 = iA * this.m_a1 + iB * this.m_a2;
|
|
var k33 = mA + mB + iA * this.m_a1 * this.m_a1 + iB * this.m_a2 * this.m_a2;
|
|
this.m_K.ex.Set(k11, k12, k13);
|
|
this.m_K.ey.Set(k12, k22, k23);
|
|
this.m_K.ez.Set(k13, k23, k33);
|
|
if (this.m_enableLimit) {
|
|
var jointTranslation = b2Dot_v2_v2(this.m_axis, d);
|
|
if (b2Abs(this.m_upperTranslation - this.m_lowerTranslation) < 2 * b2_linearSlop) {
|
|
this.m_limitState = b2Joint.e_equalLimits
|
|
} else {
|
|
if (jointTranslation <= this.m_lowerTranslation) {
|
|
if (this.m_limitState != b2Joint.e_atLowerLimit) {
|
|
this.m_limitState = b2Joint.e_atLowerLimit;
|
|
this.m_impulse.z = 0
|
|
}
|
|
} else {
|
|
if (jointTranslation >= this.m_upperTranslation) {
|
|
if (this.m_limitState != b2Joint.e_atUpperLimit) {
|
|
this.m_limitState = b2Joint.e_atUpperLimit;
|
|
this.m_impulse.z = 0
|
|
}
|
|
} else {
|
|
this.m_limitState = b2Joint.e_inactiveLimit;
|
|
this.m_impulse.z = 0
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
this.m_limitState = b2Joint.e_inactiveLimit;
|
|
this.m_impulse.z = 0
|
|
}
|
|
if (this.m_enableMotor == false) {
|
|
this.m_motorImpulse = 0
|
|
}
|
|
if (data.step.warmStarting) {
|
|
this.m_impulse.Multiply(data.step.dtRatio);
|
|
this.m_motorImpulse *= data.step.dtRatio;
|
|
var P = b2Vec2.Add(b2Vec2.Multiply(this.m_impulse.x, this.m_perp), b2Vec2.Multiply((this.m_motorImpulse + this.m_impulse.z), this.m_axis));
|
|
var LA = this.m_impulse.x * this.m_s1 + this.m_impulse.y + (this.m_motorImpulse + this.m_impulse.z) * this.m_a1;
|
|
var LB = this.m_impulse.x * this.m_s2 + this.m_impulse.y + (this.m_motorImpulse + this.m_impulse.z) * this.m_a2;
|
|
vA.Subtract(b2Vec2.Multiply(mA, P));
|
|
wA -= iA * LA;
|
|
vB.Add(b2Vec2.Multiply(mB, P));
|
|
wB += iB * LB
|
|
} else {
|
|
this.m_impulse.SetZero();
|
|
this.m_motorImpulse = 0
|
|
}
|
|
data.velocities[this.m_indexA].v.Assign(vA);
|
|
data.velocities[this.m_indexA].w = wA;
|
|
data.velocities[this.m_indexB].v.Assign(vB);
|
|
data.velocities[this.m_indexB].w = wB
|
|
},
|
|
SolveVelocityConstraints: function (data) {
|
|
var vA = data.velocities[this.m_indexA].v.Clone();
|
|
var wA = data.velocities[this.m_indexA].w;
|
|
var vB = data.velocities[this.m_indexB].v.Clone();
|
|
var wB = data.velocities[this.m_indexB].w;
|
|
var mA = this.m_invMassA,
|
|
mB = this.m_invMassB;
|
|
var iA = this.m_invIA,
|
|
iB = this.m_invIB;
|
|
if (this.m_enableMotor && this.m_limitState != b2Joint.e_equalLimits) {
|
|
var Cdot = b2Dot_v2_v2(this.m_axis, b2Vec2.Subtract(vB, vA)) + this.m_a2 * wB - this.m_a1 * wA;
|
|
var impulse = this.m_motorMass * (this.m_motorSpeed - Cdot);
|
|
var oldImpulse = this.m_motorImpulse;
|
|
var maxImpulse = data.step.dt * this.m_maxMotorForce;
|
|
this.m_motorImpulse = b2Clamp(this.m_motorImpulse + impulse, -maxImpulse, maxImpulse);
|
|
impulse = this.m_motorImpulse - oldImpulse;
|
|
var P = b2Vec2.Multiply(impulse, this.m_axis);
|
|
var LA = impulse * this.m_a1;
|
|
var LB = impulse * this.m_a2;
|
|
vA.Subtract(b2Vec2.Multiply(mA, P));
|
|
wA -= iA * LA;
|
|
vB.Add(b2Vec2.Multiply(mB, P));
|
|
wB += iB * LB
|
|
}
|
|
var Cdot1 = new b2Vec2();
|
|
Cdot1.x = b2Dot_v2_v2(this.m_perp, b2Vec2.Subtract(vB, vA)) + this.m_s2 * wB - this.m_s1 * wA;
|
|
Cdot1.y = wB - wA;
|
|
if (this.m_enableLimit && this.m_limitState != b2Joint.e_inactiveLimit) {
|
|
var Cdot2;
|
|
Cdot2 = b2Dot_v2_v2(this.m_axis, b2Vec2.Subtract(vB, vA)) + this.m_a2 * wB - this.m_a1 * wA;
|
|
var Cdot = new b2Vec3(Cdot1.x, Cdot1.y, Cdot2);
|
|
var f1 = this.m_impulse.Clone();
|
|
var df = this.m_K.Solve33(Cdot.Negate());
|
|
this.m_impulse.Add(df);
|
|
if (this.m_limitState == b2Joint.e_atLowerLimit) {
|
|
this.m_impulse.z = b2Max(this.m_impulse.z, 0)
|
|
} else {
|
|
if (this.m_limitState == b2Joint.e_atUpperLimit) {
|
|
this.m_impulse.z = b2Min(this.m_impulse.z, 0)
|
|
}
|
|
}
|
|
var b = b2Vec2.Subtract(Cdot1.Negate(), b2Vec2.Multiply((this.m_impulse.z - f1.z), new b2Vec2(this.m_K.ez.x, this.m_K.ez.y)));
|
|
var f2r = b2Vec2.Add(this.m_K.Solve22(b), new b2Vec2(f1.x, f1.y));
|
|
this.m_impulse.x = f2r.x;
|
|
this.m_impulse.y = f2r.y;
|
|
df = b2Vec3.Subtract(this.m_impulse, f1);
|
|
var P = b2Vec2.Add(b2Vec2.Multiply(df.x, this.m_perp), b2Vec2.Multiply(df.z, this.m_axis));
|
|
var LA = df.x * this.m_s1 + df.y + df.z * this.m_a1;
|
|
var LB = df.x * this.m_s2 + df.y + df.z * this.m_a2;
|
|
vA.Subtract(b2Vec2.Multiply(mA, P));
|
|
wA -= iA * LA;
|
|
vB.Add(b2Vec2.Multiply(mB, P));
|
|
wB += iB * LB
|
|
} else {
|
|
var df = this.m_K.Solve22(Cdot1.Negate());
|
|
this.m_impulse.x += df.x;
|
|
this.m_impulse.y += df.y;
|
|
var P = b2Vec2.Multiply(df.x, this.m_perp);
|
|
var LA = df.x * this.m_s1 + df.y;
|
|
var LB = df.x * this.m_s2 + df.y;
|
|
vA.Subtract(b2Vec2.Multiply(mA, P));
|
|
wA -= iA * LA;
|
|
vB.Add(b2Vec2.Multiply(mB, P));
|
|
wB += iB * LB
|
|
}
|
|
data.velocities[this.m_indexA].v.Assign(vA);
|
|
data.velocities[this.m_indexA].w = wA;
|
|
data.velocities[this.m_indexB].v.Assign(vB);
|
|
data.velocities[this.m_indexB].w = wB
|
|
},
|
|
SolvePositionConstraints: function (data) {
|
|
var cA = data.positions[this.m_indexA].c.Clone();
|
|
var aA = data.positions[this.m_indexA].a;
|
|
var cB = data.positions[this.m_indexB].c.Clone();
|
|
var aB = data.positions[this.m_indexB].a;
|
|
var qA = new b2Rot(aA),
|
|
qB = new b2Rot(aB);
|
|
var mA = this.m_invMassA,
|
|
mB = this.m_invMassB;
|
|
var iA = this.m_invIA,
|
|
iB = this.m_invIB;
|
|
var rA = b2Mul_r_v2(qA, b2Vec2.Subtract(this.m_localAnchorA, this.m_localCenterA));
|
|
var rB = b2Mul_r_v2(qB, b2Vec2.Subtract(this.m_localAnchorB, this.m_localCenterB));
|
|
var d = b2Vec2.Subtract(b2Vec2.Subtract(b2Vec2.Add(cB, rB), cA), rA);
|
|
var axis = b2Mul_r_v2(qA, this.m_localXAxisA);
|
|
var a1 = b2Cross_v2_v2(b2Vec2.Add(d, rA), axis);
|
|
var a2 = b2Cross_v2_v2(rB, axis);
|
|
var perp = b2Mul_r_v2(qA, this.m_localYAxisA);
|
|
var s1 = b2Cross_v2_v2(b2Vec2.Add(d, rA), perp);
|
|
var s2 = b2Cross_v2_v2(rB, perp);
|
|
var impulse = new b2Vec3();
|
|
var C1 = new b2Vec2();
|
|
C1.x = b2Dot_v2_v2(perp, d);
|
|
C1.y = aB - aA - this.m_referenceAngle;
|
|
var linearError = b2Abs(C1.x);
|
|
var angularError = b2Abs(C1.y);
|
|
var active = false;
|
|
var C2 = 0;
|
|
if (this.m_enableLimit) {
|
|
var translation = b2Dot_v2_v2(axis, d);
|
|
if (b2Abs(this.m_upperTranslation - this.m_lowerTranslation) < 2 * b2_linearSlop) {
|
|
C2 = b2Clamp(translation, -b2_maxLinearCorrection, b2_maxLinearCorrection);
|
|
linearError = b2Max(linearError, b2Abs(translation));
|
|
active = true
|
|
} else {
|
|
if (translation <= this.m_lowerTranslation) {
|
|
C2 = b2Clamp(translation - this.m_lowerTranslation + b2_linearSlop, -b2_maxLinearCorrection, 0);
|
|
linearError = b2Max(linearError, this.m_lowerTranslation - translation);
|
|
active = true
|
|
} else {
|
|
if (translation >= this.m_upperTranslation) {
|
|
C2 = b2Clamp(translation - this.m_upperTranslation - b2_linearSlop, 0, b2_maxLinearCorrection);
|
|
linearError = b2Max(linearError, translation - this.m_upperTranslation);
|
|
active = true
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (active) {
|
|
var k11 = mA + mB + iA * s1 * s1 + iB * s2 * s2;
|
|
var k12 = iA * s1 + iB * s2;
|
|
var k13 = iA * s1 * a1 + iB * s2 * a2;
|
|
var k22 = iA + iB;
|
|
if (k22 == 0) {
|
|
k22 = 1
|
|
}
|
|
var k23 = iA * a1 + iB * a2;
|
|
var k33 = mA + mB + iA * a1 * a1 + iB * a2 * a2;
|
|
var K = new b2Mat33();
|
|
K.ex.Set(k11, k12, k13);
|
|
K.ey.Set(k12, k22, k23);
|
|
K.ez.Set(k13, k23, k33);
|
|
var C = new b2Vec3();
|
|
C.x = C1.x;
|
|
C.y = C1.y;
|
|
C.z = C2;
|
|
impulse = K.Solve33(C.Negate())
|
|
} else {
|
|
var k11 = mA + mB + iA * s1 * s1 + iB * s2 * s2;
|
|
var k12 = iA * s1 + iB * s2;
|
|
var k22 = iA + iB;
|
|
if (k22 == 0) {
|
|
k22 = 1
|
|
}
|
|
var K = new b2Mat22();
|
|
K.ex.Set(k11, k12);
|
|
K.ey.Set(k12, k22);
|
|
var impulse1 = K.Solve(C1.Negate());
|
|
impulse.x = impulse1.x;
|
|
impulse.y = impulse1.y;
|
|
impulse.z = 0
|
|
}
|
|
var P = b2Vec2.Add(b2Vec2.Multiply(impulse.x, perp), b2Vec2.Multiply(impulse.z, axis));
|
|
var LA = impulse.x * s1 + impulse.y + impulse.z * a1;
|
|
var LB = impulse.x * s2 + impulse.y + impulse.z * a2;
|
|
cA.Subtract(b2Vec2.Multiply(mA, P));
|
|
aA -= iA * LA;
|
|
cB.Add(b2Vec2.Multiply(mB, P));
|
|
aB += iB * LB;
|
|
data.positions[this.m_indexA].c.Assign(cA);
|
|
data.positions[this.m_indexA].a = aA;
|
|
data.positions[this.m_indexB].c.Assign(cB);
|
|
data.positions[this.m_indexB].a = aB;
|
|
return linearError <= b2_linearSlop && angularError <= b2_angularSlop
|
|
},
|
|
_serialize: function (out) {
|
|
var obj = out || {};
|
|
this.parent.prototype._serialize.call(this, obj);
|
|
obj.localAnchorA = this.m_localAnchorA._serialize();
|
|
obj.localAnchorB = this.m_localAnchorB._serialize();
|
|
obj.localAxisA = this.m_localXAxisA._serialize();
|
|
obj.referenceAngle = this.m_referenceAngle;
|
|
obj.enableLimit = this.m_enableLimit;
|
|
obj.lowerTranslation = this.m_lowerTranslation;
|
|
obj.upperTranslation = this.m_upperTranslation;
|
|
obj.enableMotor = this.m_enableMotor;
|
|
obj.maxMotorForce = this.m_maxMotorForce;
|
|
obj.motorSpeed = this.m_motorSpeed;
|
|
return obj
|
|
}
|
|
};
|
|
b2PrismaticJoint._extend(b2Joint);
|
|
|
|
function b2FrictionJointDef() {
|
|
this.parent.call(this);
|
|
this.type = b2Joint.e_frictionJoint;
|
|
this.localAnchorA = new b2Vec2();
|
|
this.localAnchorB = new b2Vec2();
|
|
this.maxForce = 0;
|
|
this.maxTorque = 0;
|
|
Object.seal(this)
|
|
}
|
|
b2FrictionJointDef.prototype = {
|
|
Initialize: function (bA, bB, anchor) {
|
|
this.bodyA = bA;
|
|
this.bodyB = bB;
|
|
this.localAnchorA.Assign(this.bodyA.GetLocalPoint(anchor));
|
|
this.localAnchorB.Assign(this.bodyB.GetLocalPoint(anchor))
|
|
},
|
|
_deserialize: function (data, bodies, joints) {
|
|
this.parent.prototype._deserialize.call(this, data, bodies, joints);
|
|
this.localAnchorA._deserialize(data.localAnchorA);
|
|
this.localAnchorB._deserialize(data.localAnchorB);
|
|
this.maxForce = data.maxForce;
|
|
this.maxTorque = data.maxTorque
|
|
}
|
|
};
|
|
b2FrictionJointDef._extend(b2JointDef);
|
|
|
|
function b2FrictionJoint(def) {
|
|
this.parent.call(this, def);
|
|
this.m_localAnchorA = def.localAnchorA.Clone();
|
|
this.m_localAnchorB = def.localAnchorB.Clone();
|
|
this.m_linearImpulse = new b2Vec2();
|
|
this.m_angularImpulse = 0;
|
|
this.m_maxForce = def.maxForce;
|
|
this.m_maxTorque = def.maxTorque;
|
|
this.m_indexA = 0;
|
|
this.m_indexB = 0;
|
|
this.m_rA = new b2Vec2();
|
|
this.m_rB = new b2Vec2();
|
|
this.m_localCenterA = new b2Vec2();
|
|
this.m_localCenterB = new b2Vec2();
|
|
this.m_invMassA = 0;
|
|
this.m_invMassB = 0;
|
|
this.m_invIA = 0;
|
|
this.m_invIB = 0;
|
|
this.m_linearMass = new b2Mat22();
|
|
this.m_angularMass = 0
|
|
}
|
|
b2FrictionJoint.prototype = {
|
|
GetAnchorA: function () {
|
|
return this.m_bodyA.GetWorldPoint(this.m_localAnchorA)
|
|
},
|
|
GetAnchorB: function () {
|
|
return this.m_bodyB.GetWorldPoint(this.m_localAnchorB)
|
|
},
|
|
GetReactionForce: function (inv_dt) {
|
|
return b2Vec2.Multiply(inv_dt, this.m_linearImpulse)
|
|
},
|
|
GetReactionTorque: function (inv_dt) {
|
|
return inv_dt * this.m_angularImpulse
|
|
},
|
|
GetLocalAnchorA: function () {
|
|
return this.m_localAnchorA
|
|
},
|
|
GetLocalAnchorB: function () {
|
|
return this.m_localAnchorB
|
|
},
|
|
SetMaxForce: function (force) {
|
|
this.m_maxForce = force
|
|
},
|
|
GetMaxForce: function () {
|
|
return this.m_maxForce
|
|
},
|
|
SetMaxTorque: function (torque) {
|
|
this.m_maxTorque = torque
|
|
},
|
|
GetMaxTorque: function () {
|
|
return this.m_maxTorque
|
|
},
|
|
InitVelocityConstraints: function (data) {
|
|
this.m_indexA = this.m_bodyA.m_islandIndex;
|
|
this.m_indexB = this.m_bodyB.m_islandIndex;
|
|
this.m_localCenterA.Assign(this.m_bodyA.m_sweep.localCenter);
|
|
this.m_localCenterB.Assign(this.m_bodyB.m_sweep.localCenter);
|
|
this.m_invMassA = this.m_bodyA.m_invMass;
|
|
this.m_invMassB = this.m_bodyB.m_invMass;
|
|
this.m_invIA = this.m_bodyA.m_invI;
|
|
this.m_invIB = this.m_bodyB.m_invI;
|
|
var aA = data.positions[this.m_indexA].a;
|
|
var vA = data.velocities[this.m_indexA].v.Clone();
|
|
var wA = data.velocities[this.m_indexA].w;
|
|
var aB = data.positions[this.m_indexB].a;
|
|
var vB = data.velocities[this.m_indexB].v.Clone();
|
|
var wB = data.velocities[this.m_indexB].w;
|
|
var qA = new b2Rot(aA),
|
|
qB = new b2Rot(aB);
|
|
this.m_rA = b2Mul_r_v2(qA, b2Vec2.Subtract(this.m_localAnchorA, this.m_localCenterA));
|
|
this.m_rB = b2Mul_r_v2(qB, b2Vec2.Subtract(this.m_localAnchorB, this.m_localCenterB));
|
|
var mA = this.m_invMassA,
|
|
mB = this.m_invMassB;
|
|
var iA = this.m_invIA,
|
|
iB = this.m_invIB;
|
|
var K = new b2Mat22();
|
|
K.ex.x = mA + mB + iA * this.m_rA.y * this.m_rA.y + iB * this.m_rB.y * this.m_rB.y;
|
|
K.ex.y = -iA * this.m_rA.x * this.m_rA.y - iB * this.m_rB.x * this.m_rB.y;
|
|
K.ey.x = K.ex.y;
|
|
K.ey.y = mA + mB + iA * this.m_rA.x * this.m_rA.x + iB * this.m_rB.x * this.m_rB.x;
|
|
this.m_linearMass = K.GetInverse();
|
|
this.m_angularMass = iA + iB;
|
|
if (this.m_angularMass > 0) {
|
|
this.m_angularMass = 1 / this.m_angularMass
|
|
}
|
|
if (data.step.warmStarting) {
|
|
this.m_linearImpulse.Multiply(data.step.dtRatio);
|
|
this.m_angularImpulse *= data.step.dtRatio;
|
|
var P = new b2Vec2(this.m_linearImpulse.x, this.m_linearImpulse.y);
|
|
vA.Subtract(b2Vec2.Multiply(mA, P));
|
|
wA -= iA * (b2Cross_v2_v2(this.m_rA, P) + this.m_angularImpulse);
|
|
vB.Add(b2Vec2.Multiply(mB, P));
|
|
wB += iB * (b2Cross_v2_v2(this.m_rB, P) + this.m_angularImpulse)
|
|
} else {
|
|
this.m_linearImpulse.SetZero();
|
|
this.m_angularImpulse = 0
|
|
}
|
|
data.velocities[this.m_indexA].v.Assign(vA);
|
|
data.velocities[this.m_indexA].w = wA;
|
|
data.velocities[this.m_indexB].v.Assign(vB);
|
|
data.velocities[this.m_indexB].w = wB
|
|
},
|
|
SolveVelocityConstraints: function (data) {
|
|
var vA = data.velocities[this.m_indexA].v.Clone();
|
|
var wA = data.velocities[this.m_indexA].w;
|
|
var vB = data.velocities[this.m_indexB].v.Clone();
|
|
var wB = data.velocities[this.m_indexB].w;
|
|
var mA = this.m_invMassA,
|
|
mB = this.m_invMassB;
|
|
var iA = this.m_invIA,
|
|
iB = this.m_invIB;
|
|
var h = data.step.dt;
|
|
var Cdot = wB - wA;
|
|
var impulse = -this.m_angularMass * Cdot;
|
|
var oldImpulse = this.m_angularImpulse;
|
|
var maxImpulse = h * this.m_maxTorque;
|
|
this.m_angularImpulse = b2Clamp(this.m_angularImpulse + impulse, -maxImpulse, maxImpulse);
|
|
impulse = this.m_angularImpulse - oldImpulse;
|
|
wA -= iA * impulse;
|
|
wB += iB * impulse;
|
|
var Cdot = b2Vec2.Add(vB, b2Vec2.Subtract(b2Cross_f_v2(wB, this.m_rB), b2Vec2.Subtract(vA, b2Cross_f_v2(wA, this.m_rA))));
|
|
var impulse = b2Mul_m22_v2(this.m_linearMass, Cdot).Negate();
|
|
var oldImpulse = this.m_linearImpulse.Clone();
|
|
this.m_linearImpulse.Add(impulse);
|
|
var maxImpulse = h * this.m_maxForce;
|
|
if (this.m_linearImpulse.LengthSquared() > maxImpulse * maxImpulse) {
|
|
this.m_linearImpulse.Normalize();
|
|
this.m_linearImpulse.Multiply(maxImpulse)
|
|
}
|
|
impulse = b2Vec2.Subtract(this.m_linearImpulse, oldImpulse);
|
|
vA.Subtract(b2Vec2.Multiply(mA, impulse));
|
|
wA -= iA * b2Cross_v2_v2(this.m_rA, impulse);
|
|
vB.Add(b2Vec2.Multiply(mB, impulse));
|
|
wB += iB * b2Cross_v2_v2(this.m_rB, impulse);
|
|
data.velocities[this.m_indexA].v.Assign(vA);
|
|
data.velocities[this.m_indexA].w = wA;
|
|
data.velocities[this.m_indexB].v.Assign(vB);
|
|
data.velocities[this.m_indexB].w = wB
|
|
},
|
|
SolvePositionConstraints: function (data) {
|
|
return true
|
|
},
|
|
_serialize: function (out) {
|
|
var obj = out || {};
|
|
this.parent.prototype._serialize.call(this, obj);
|
|
obj.localAnchorA = this.m_localAnchorA._serialize();
|
|
obj.localAnchorB = this.m_localAnchorB._serialize();
|
|
obj.maxForce = this.m_maxForce;
|
|
obj.maxTorque = this.m_maxTorque;
|
|
return obj
|
|
}
|
|
};
|
|
b2FrictionJoint._extend(b2Joint);
|
|
|
|
function b2WeldJointDef() {
|
|
this.parent.call(this);
|
|
this.type = b2Joint.e_weldJoint;
|
|
this.localAnchorA = new b2Vec2(0, 0);
|
|
this.localAnchorB = new b2Vec2(0, 0);
|
|
this.referenceAngle = 0;
|
|
this.frequencyHz = 0;
|
|
this.dampingRatio = 0;
|
|
Object.seal(this)
|
|
}
|
|
b2WeldJointDef.prototype = {
|
|
Initialize: function (bA, bB, anchor) {
|
|
this.bodyA = bA;
|
|
this.bodyB = bB;
|
|
this.localAnchorA.Assign(this.bodyA.GetLocalPoint(anchor));
|
|
this.localAnchorB.Assign(this.bodyB.GetLocalPoint(anchor));
|
|
this.referenceAngle = this.bodyB.GetAngle() - this.bodyA.GetAngle()
|
|
},
|
|
_deserialize: function (data, bodies, joints) {
|
|
this.parent.prototype._deserialize.call(this, data, bodies, joints);
|
|
this.localAnchorA._deserialize(data.localAnchorA);
|
|
this.localAnchorB._deserialize(data.localAnchorB);
|
|
this.referenceAngle = data.referenceAngle;
|
|
this.frequencyHz = data.frequencyHz;
|
|
this.dampingRatio = data.dampingRatio
|
|
}
|
|
};
|
|
b2WeldJointDef._extend(b2JointDef);
|
|
|
|
function b2WeldJoint(def) {
|
|
this.parent.call(this, def);
|
|
this.m_bias = 0;
|
|
this.m_gamma = 0;
|
|
this.m_indexA = 0;
|
|
this.m_indexB = 0;
|
|
this.m_rA = new b2Vec2();
|
|
this.m_rB = new b2Vec2();
|
|
this.m_localCenterA = new b2Vec2();
|
|
this.m_localCenterB = new b2Vec2();
|
|
this.m_invMassA = 0;
|
|
this.m_invMassB = 0;
|
|
this.m_invIA = 0;
|
|
this.m_invIB = 0;
|
|
this.m_mass = new b2Mat33();
|
|
this.m_localAnchorA = def.localAnchorA.Clone();
|
|
this.m_localAnchorB = def.localAnchorB.Clone();
|
|
this.m_referenceAngle = def.referenceAngle;
|
|
this.m_frequencyHz = def.frequencyHz;
|
|
this.m_dampingRatio = def.dampingRatio;
|
|
this.m_impulse = new b2Vec3()
|
|
}
|
|
b2WeldJoint.prototype = {
|
|
GetAnchorA: function () {
|
|
return this.m_bodyA.GetWorldPoint(this.m_localAnchorA)
|
|
},
|
|
GetAnchorB: function () {
|
|
return this.m_bodyB.GetWorldPoint(this.m_localAnchorB)
|
|
},
|
|
GetReactionForce: function (inv_dt) {
|
|
var P = new b2Vec2(this.m_impulse.x, this.m_impulse.y);
|
|
return b2Vec2.Multiply(inv_dt, P)
|
|
},
|
|
GetReactionTorque: function (inv_dt) {
|
|
return inv_dt * this.m_impulse.z
|
|
},
|
|
GetLocalAnchorA: function () {
|
|
return this.m_localAnchorA
|
|
},
|
|
GetLocalAnchorB: function () {
|
|
return this.m_localAnchorB
|
|
},
|
|
GetReferenceAngle: function () {
|
|
return this.m_referenceAngle
|
|
},
|
|
SetFrequency: function (hz) {
|
|
this.m_frequencyHz = hz
|
|
},
|
|
GetFrequency: function () {
|
|
return this.m_frequencyHz
|
|
},
|
|
SetDampingRatio: function (ratio) {
|
|
this.m_dampingRatio = ratio
|
|
},
|
|
GetDampingRatio: function () {
|
|
return this.m_dampingRatio
|
|
},
|
|
InitVelocityConstraints: function (data) {
|
|
this.m_indexA = this.m_bodyA.m_islandIndex;
|
|
this.m_indexB = this.m_bodyB.m_islandIndex;
|
|
this.m_localCenterA.Assign(this.m_bodyA.m_sweep.localCenter);
|
|
this.m_localCenterB.Assign(this.m_bodyB.m_sweep.localCenter);
|
|
this.m_invMassA = this.m_bodyA.m_invMass;
|
|
this.m_invMassB = this.m_bodyB.m_invMass;
|
|
this.m_invIA = this.m_bodyA.m_invI;
|
|
this.m_invIB = this.m_bodyB.m_invI;
|
|
var aA = data.positions[this.m_indexA].a;
|
|
var vA = data.velocities[this.m_indexA].v.Clone();
|
|
var wA = data.velocities[this.m_indexA].w;
|
|
var aB = data.positions[this.m_indexB].a;
|
|
var vB = data.velocities[this.m_indexB].v.Clone();
|
|
var wB = data.velocities[this.m_indexB].w;
|
|
var qA = new b2Rot(aA),
|
|
qB = new b2Rot(aB);
|
|
this.m_rA.Assign(b2Mul_r_v2(qA, b2Vec2.Subtract(this.m_localAnchorA, this.m_localCenterA)));
|
|
this.m_rB.Assign(b2Mul_r_v2(qB, b2Vec2.Subtract(this.m_localAnchorB, this.m_localCenterB)));
|
|
var mA = this.m_invMassA,
|
|
mB = this.m_invMassB;
|
|
var iA = this.m_invIA,
|
|
iB = this.m_invIB;
|
|
var K = new b2Mat33();
|
|
K.ex.x = mA + mB + this.m_rA.y * this.m_rA.y * iA + this.m_rB.y * this.m_rB.y * iB;
|
|
K.ey.x = -this.m_rA.y * this.m_rA.x * iA - this.m_rB.y * this.m_rB.x * iB;
|
|
K.ez.x = -this.m_rA.y * iA - this.m_rB.y * iB;
|
|
K.ex.y = K.ey.x;
|
|
K.ey.y = mA + mB + this.m_rA.x * this.m_rA.x * iA + this.m_rB.x * this.m_rB.x * iB;
|
|
K.ez.y = this.m_rA.x * iA + this.m_rB.x * iB;
|
|
K.ex.z = K.ez.x;
|
|
K.ey.z = K.ez.y;
|
|
K.ez.z = iA + iB;
|
|
if (this.m_frequencyHz > 0) {
|
|
K.GetInverse22(this.m_mass);
|
|
var invM = iA + iB;
|
|
var m = invM > 0 ? 1 / invM : 0;
|
|
var C = aB - aA - this.m_referenceAngle;
|
|
var omega = 2 * b2_pi * this.m_frequencyHz;
|
|
var d = 2 * m * this.m_dampingRatio * omega;
|
|
var k = m * omega * omega;
|
|
var h = data.step.dt;
|
|
this.m_gamma = h * (d + h * k);
|
|
this.m_gamma = this.m_gamma != 0 ? 1 / this.m_gamma : 0;
|
|
this.m_bias = C * h * k * this.m_gamma;
|
|
invM += this.m_gamma;
|
|
this.m_mass.ez.z = invM != 0 ? 1 / invM : 0
|
|
} else {
|
|
K.GetSymInverse33(this.m_mass);
|
|
this.m_gamma = 0;
|
|
this.m_bias = 0
|
|
}
|
|
if (data.step.warmStarting) {
|
|
this.m_impulse.Multiply(data.step.dtRatio);
|
|
var P = new b2Vec2(this.m_impulse.x, this.m_impulse.y);
|
|
vA.Subtract(b2Vec2.Multiply(mA, P));
|
|
wA -= iA * (b2Cross_v2_v2(this.m_rA, P) + this.m_impulse.z);
|
|
vB.Add(b2Vec2.Multiply(mB, P));
|
|
wB += iB * (b2Cross_v2_v2(this.m_rB, P) + this.m_impulse.z)
|
|
} else {
|
|
this.m_impulse.SetZero()
|
|
}
|
|
data.velocities[this.m_indexA].v.Assign(vA);
|
|
data.velocities[this.m_indexA].w = wA;
|
|
data.velocities[this.m_indexB].v.Assign(vB);
|
|
data.velocities[this.m_indexB].w = wB
|
|
},
|
|
SolveVelocityConstraints: function (data) {
|
|
var vA = data.velocities[this.m_indexA].v.Clone();
|
|
var wA = data.velocities[this.m_indexA].w;
|
|
var vB = data.velocities[this.m_indexB].v.Clone();
|
|
var wB = data.velocities[this.m_indexB].w;
|
|
var mA = this.m_invMassA,
|
|
mB = this.m_invMassB;
|
|
var iA = this.m_invIA,
|
|
iB = this.m_invIB;
|
|
if (this.m_frequencyHz > 0) {
|
|
var Cdot2 = wB - wA;
|
|
var impulse2 = -this.m_mass.ez.z * (Cdot2 + this.m_bias + this.m_gamma * this.m_impulse.z);
|
|
this.m_impulse.z += impulse2;
|
|
wA -= iA * impulse2;
|
|
wB += iB * impulse2;
|
|
var Cdot1 = b2Vec2.Subtract(b2Vec2.Subtract(b2Vec2.Add(vB, b2Cross_f_v2(wB, this.m_rB)), vA), b2Cross_f_v2(wA, this.m_rA));
|
|
var impulse1 = b2Mul22_m33_v2(this.m_mass, Cdot1).Negate();
|
|
this.m_impulse.x += impulse1.x;
|
|
this.m_impulse.y += impulse1.y;
|
|
var P = impulse1.Clone();
|
|
vA.Subtract(b2Vec2.Multiply(mA, P));
|
|
wA -= iA * b2Cross_v2_v2(this.m_rA, P);
|
|
vB.Add(b2Vec2.Multiply(mB, P));
|
|
wB += iB * b2Cross_v2_v2(this.m_rB, P)
|
|
} else {
|
|
var Cdot1 = b2Vec2.Subtract(b2Vec2.Subtract(b2Vec2.Add(vB, b2Cross_f_v2(wB, this.m_rB)), vA), b2Cross_f_v2(wA, this.m_rA));
|
|
var Cdot2 = wB - wA;
|
|
var Cdot = new b2Vec3(Cdot1.x, Cdot1.y, Cdot2);
|
|
var impulse = b2Mul_m33_v3(this.m_mass, Cdot).Negate();
|
|
this.m_impulse.Add(impulse);
|
|
var P = new b2Vec2(impulse.x, impulse.y);
|
|
vA.Subtract(b2Vec2.Multiply(mA, P));
|
|
wA -= iA * (b2Cross_v2_v2(this.m_rA, P) + impulse.z);
|
|
vB.Add(b2Vec2.Multiply(mB, P));
|
|
wB += iB * (b2Cross_v2_v2(this.m_rB, P) + impulse.z)
|
|
}
|
|
data.velocities[this.m_indexA].v.Assign(vA);
|
|
data.velocities[this.m_indexA].w = wA;
|
|
data.velocities[this.m_indexB].v.Assign(vB);
|
|
data.velocities[this.m_indexB].w = wB
|
|
},
|
|
SolvePositionConstraints: function (data) {
|
|
var cA = data.positions[this.m_indexA].c.Clone();
|
|
var aA = data.positions[this.m_indexA].a;
|
|
var cB = data.positions[this.m_indexB].c.Clone();
|
|
var aB = data.positions[this.m_indexB].a;
|
|
var qA = new b2Rot(aA),
|
|
qB = new b2Rot(aB);
|
|
var mA = this.m_invMassA,
|
|
mB = this.m_invMassB;
|
|
var iA = this.m_invIA,
|
|
iB = this.m_invIB;
|
|
var rA = b2Mul_r_v2(qA, b2Vec2.Subtract(this.m_localAnchorA, this.m_localCenterA));
|
|
var rB = b2Mul_r_v2(qB, b2Vec2.Subtract(this.m_localAnchorB, this.m_localCenterB));
|
|
var positionError, angularError;
|
|
var K = new b2Mat33();
|
|
K.ex.x = mA + mB + rA.y * rA.y * iA + rB.y * rB.y * iB;
|
|
K.ey.x = -rA.y * rA.x * iA - rB.y * rB.x * iB;
|
|
K.ez.x = -rA.y * iA - rB.y * iB;
|
|
K.ex.y = K.ey.x;
|
|
K.ey.y = mA + mB + rA.x * rA.x * iA + rB.x * rB.x * iB;
|
|
K.ez.y = rA.x * iA + rB.x * iB;
|
|
K.ex.z = K.ez.x;
|
|
K.ey.z = K.ez.y;
|
|
K.ez.z = iA + iB;
|
|
if (this.m_frequencyHz > 0) {
|
|
var C1 = b2Vec2.Subtract(b2Vec2.Subtract(b2Vec2.Add(cB, rB), cA), rA);
|
|
positionError = C1.Length();
|
|
angularError = 0;
|
|
var P = K.Solve22(C1).Negate();
|
|
cA.Subtract(b2Vec2.Multiply(mA, P));
|
|
aA -= iA * b2Cross_v2_v2(rA, P);
|
|
cB.Add(b2Vec2.Multiply(mB, P));
|
|
aB += iB * b2Cross_v2_v2(rB, P)
|
|
} else {
|
|
var C1 = b2Vec2.Subtract(b2Vec2.Subtract(b2Vec2.Add(cB, rB), cA), rA);
|
|
var C2 = aB - aA - this.m_referenceAngle;
|
|
positionError = C1.Length();
|
|
angularError = b2Abs(C2);
|
|
var C = new b2Vec3(C1.x, C1.y, C2);
|
|
var impulse = K.Solve33(C).Negate();
|
|
var P = new b2Vec2(impulse.x, impulse.y);
|
|
cA.Subtract(b2Vec2.Multiply(mA, P));
|
|
aA -= iA * (b2Cross_v2_v2(rA, P) + impulse.z);
|
|
cB.Add(b2Vec2.Multiply(mB, P));
|
|
aB += iB * (b2Cross_v2_v2(rB, P) + impulse.z)
|
|
}
|
|
data.positions[this.m_indexA].c.Assign(cA);
|
|
data.positions[this.m_indexA].a = aA;
|
|
data.positions[this.m_indexB].c.Assign(cB);
|
|
data.positions[this.m_indexB].a = aB;
|
|
return positionError <= b2_linearSlop && angularError <= b2_angularSlop
|
|
},
|
|
_serialize: function (out) {
|
|
var obj = out || {};
|
|
this.parent.prototype._serialize.call(this, obj);
|
|
obj.localAnchorA = this.m_localAnchorA._serialize();
|
|
obj.localAnchorB = this.m_localAnchorB._serialize();
|
|
obj.referenceAngle = this.m_referenceAngle;
|
|
obj.frequencyHz = this.m_frequencyHz;
|
|
obj.dampingRatio = this.m_dampingRatio;
|
|
return obj
|
|
}
|
|
};
|
|
b2WeldJoint._extend(b2Joint);
|
|
|
|
function b2WheelJointDef() {
|
|
this.parent.call(this);
|
|
this.type = b2Joint.e_wheelJoint;
|
|
this.localAnchorA = new b2Vec2();
|
|
this.localAnchorB = new b2Vec2();
|
|
this.localAxisA = new b2Vec2(1, 0);
|
|
this.enableMotor = false;
|
|
this.maxMotorTorque = 0;
|
|
this.motorSpeed = 0;
|
|
this.frequencyHz = 2;
|
|
this.dampingRatio = 0.7;
|
|
Object.seal(this)
|
|
}
|
|
b2WheelJointDef.prototype = {
|
|
Initialize: function (bA, bB, anchor, axis) {
|
|
this.bodyA = bA;
|
|
this.bodyB = bB;
|
|
this.localAnchorA.Assign(this.bodyA.GetLocalPoint(anchor));
|
|
this.localAnchorB.Assign(this.bodyB.GetLocalPoint(anchor));
|
|
this.localAxisA.Assign(this.bodyA.GetLocalVector(axis))
|
|
},
|
|
_deserialize: function (data, bodies, joints) {
|
|
this.parent.prototype._deserialize.call(this, data, bodies, joints);
|
|
this.localAnchorA._deserialize(data.localAnchorA);
|
|
this.localAnchorB._deserialize(data.localAnchorB);
|
|
this.localAxisA._deserialize(data.localAxisA);
|
|
this.enableMotor = data.enableMotor;
|
|
this.maxMotorTorque = data.maxMotorTorque;
|
|
this.motorSpeed = data.motorSpeed;
|
|
this.frequencyHz = data.frequencyHz;
|
|
this.dampingRatio = data.dampingRatio
|
|
}
|
|
};
|
|
b2WheelJointDef._extend(b2JointDef);
|
|
|
|
function b2WheelJoint(def) {
|
|
this.parent.call(this, def);
|
|
this.m_indexA = 0;
|
|
this.m_indexB = 0;
|
|
this.m_localCenterA = new b2Vec2();
|
|
this.m_localCenterB = new b2Vec2();
|
|
this.m_invMassA = 0;
|
|
this.m_invMassB = 0;
|
|
this.m_invIA = 0;
|
|
this.m_invIB = 0;
|
|
this.m_localAnchorA = def.localAnchorA.Clone();
|
|
this.m_localAnchorB = def.localAnchorB.Clone();
|
|
this.m_localXAxisA = def.localAxisA.Clone();
|
|
this.m_localYAxisA = b2Cross_f_v2(1, this.m_localXAxisA);
|
|
this.m_mass = 0;
|
|
this.m_impulse = 0;
|
|
this.m_motorMass = 0;
|
|
this.m_motorImpulse = 0;
|
|
this.m_springMass = 0;
|
|
this.m_springImpulse = 0;
|
|
this.m_maxMotorTorque = def.maxMotorTorque;
|
|
this.m_motorSpeed = def.motorSpeed;
|
|
this.m_enableMotor = def.enableMotor;
|
|
this.m_frequencyHz = def.frequencyHz;
|
|
this.m_dampingRatio = def.dampingRatio;
|
|
this.m_bias = 0;
|
|
this.m_gamma = 0;
|
|
this.m_ax = new b2Vec2();
|
|
this.m_ay = new b2Vec2();
|
|
this.m_sAx = this.m_sBx = 0;
|
|
this.m_sAy = this.m_sBy = 0
|
|
}
|
|
b2WheelJoint.prototype = {
|
|
GetAnchorA: function () {
|
|
return this.m_bodyA.GetWorldPoint(this.m_localAnchorA)
|
|
},
|
|
GetAnchorB: function () {
|
|
return this.m_bodyB.GetWorldPoint(this.m_localAnchorB)
|
|
},
|
|
GetReactionForce: function (inv_dt) {
|
|
return b2Vec2.Multiply(inv_dt, b2Vec2.Add(b2Vec2.Multiply(this.m_impulse, this.m_ay), b2Vec2.Multiply(this.m_springImpulse, this.m_ax)))
|
|
},
|
|
GetReactionTorque: function (inv_dt) {
|
|
return inv_dt * this.m_motorImpulse
|
|
},
|
|
GetLocalAnchorA: function () {
|
|
return this.m_localAnchorA
|
|
},
|
|
GetLocalAnchorB: function () {
|
|
return this.m_localAnchorB
|
|
},
|
|
GetLocalAxisA: function () {
|
|
return this.m_localXAxisA
|
|
},
|
|
GetJointTranslation: function () {
|
|
var bA = this.m_bodyA;
|
|
var bB = this.m_bodyB;
|
|
var pA = bA.GetWorldPoint(this.m_localAnchorA);
|
|
var pB = bB.GetWorldPoint(this.m_localAnchorB);
|
|
var d = b2Vec2.Subtract(pB, pA);
|
|
var axis = bA.GetWorldVector(this.m_localXAxisA);
|
|
var translation = b2Dot_v2_v2(d, axis);
|
|
return translation
|
|
},
|
|
GetJointSpeed: function () {
|
|
var wA = this.m_bodyA.m_angularVelocity;
|
|
var wB = this.m_bodyB.m_angularVelocity;
|
|
return wB - wA
|
|
},
|
|
IsMotorEnabled: function () {
|
|
return this.m_enableMotor
|
|
},
|
|
EnableMotor: function (flag) {
|
|
this.m_bodyA.SetAwake(true);
|
|
this.m_bodyB.SetAwake(true);
|
|
this.m_enableMotor = flag
|
|
},
|
|
SetMotorSpeed: function (speed) {
|
|
this.m_bodyA.SetAwake(true);
|
|
this.m_bodyB.SetAwake(true);
|
|
this.m_motorSpeed = speed
|
|
},
|
|
GetMotorSpeed: function () {
|
|
return this.m_motorSpeed
|
|
},
|
|
SetMaxMotorTorque: function (torque) {
|
|
this.m_bodyA.SetAwake(true);
|
|
this.m_bodyB.SetAwake(true);
|
|
this.m_maxMotorTorque = torque
|
|
},
|
|
GetMaxMotorTorque: function () {
|
|
return this.m_maxMotorTorque
|
|
},
|
|
GetMotorTorque: function (inv_dt) {
|
|
return inv_dt * this.m_motorImpulse
|
|
},
|
|
SetSpringFrequencyHz: function (hz) {
|
|
this.m_frequencyHz = hz
|
|
},
|
|
GetSpringFrequencyHz: function () {
|
|
return this.m_frequencyHz
|
|
},
|
|
SetSpringDampingRatio: function (ratio) {
|
|
this.m_dampingRatio = ratio
|
|
},
|
|
GetSpringDampingRatio: function () {
|
|
return this.m_dampingRatio
|
|
},
|
|
InitVelocityConstraints: function (data) {
|
|
this.m_indexA = this.m_bodyA.m_islandIndex;
|
|
this.m_indexB = this.m_bodyB.m_islandIndex;
|
|
this.m_localCenterA.Assign(this.m_bodyA.m_sweep.localCenter);
|
|
this.m_localCenterB.Assign(this.m_bodyB.m_sweep.localCenter);
|
|
this.m_invMassA = this.m_bodyA.m_invMass;
|
|
this.m_invMassB = this.m_bodyB.m_invMass;
|
|
this.m_invIA = this.m_bodyA.m_invI;
|
|
this.m_invIB = this.m_bodyB.m_invI;
|
|
var mA = this.m_invMassA,
|
|
mB = this.m_invMassB;
|
|
var iA = this.m_invIA,
|
|
iB = this.m_invIB;
|
|
var cA = data.positions[this.m_indexA].c.Clone();
|
|
var aA = data.positions[this.m_indexA].a;
|
|
var vA = data.velocities[this.m_indexA].v.Clone();
|
|
var wA = data.velocities[this.m_indexA].w;
|
|
var cB = data.positions[this.m_indexB].c.Clone();
|
|
var aB = data.positions[this.m_indexB].a;
|
|
var vB = data.velocities[this.m_indexB].v.Clone();
|
|
var wB = data.velocities[this.m_indexB].w;
|
|
var qA = new b2Rot(aA),
|
|
qB = new b2Rot(aB);
|
|
var rA = b2Mul_r_v2(qA, b2Vec2.Subtract(this.m_localAnchorA, this.m_localCenterA));
|
|
var rB = b2Mul_r_v2(qB, b2Vec2.Subtract(this.m_localAnchorB, this.m_localCenterB));
|
|
var d = b2Vec2.Subtract(b2Vec2.Subtract(b2Vec2.Add(cB, rB), cA), rA);
|
|
this.m_ay.Assign(b2Mul_r_v2(qA, this.m_localYAxisA));
|
|
this.m_sAy = b2Cross_v2_v2(b2Vec2.Add(d, rA), this.m_ay);
|
|
this.m_sBy = b2Cross_v2_v2(rB, this.m_ay);
|
|
this.m_mass = mA + mB + iA * this.m_sAy * this.m_sAy + iB * this.m_sBy * this.m_sBy;
|
|
if (this.m_mass > 0) {
|
|
this.m_mass = 1 / this.m_mass
|
|
}
|
|
this.m_springMass = 0;
|
|
this.m_bias = 0;
|
|
this.m_gamma = 0;
|
|
if (this.m_frequencyHz > 0) {
|
|
this.m_ax.Assign(b2Mul_r_v2(qA, this.m_localXAxisA));
|
|
this.m_sAx = b2Cross_v2_v2(b2Vec2.Add(d, rA), this.m_ax);
|
|
this.m_sBx = b2Cross_v2_v2(rB, this.m_ax);
|
|
var invMass = mA + mB + iA * this.m_sAx * this.m_sAx + iB * this.m_sBx * this.m_sBx;
|
|
if (invMass > 0) {
|
|
this.m_springMass = 1 / invMass;
|
|
var C = b2Dot_v2_v2(d, this.m_ax);
|
|
var omega = 2 * b2_pi * this.m_frequencyHz;
|
|
var d = 2 * this.m_springMass * this.m_dampingRatio * omega;
|
|
var k = this.m_springMass * omega * omega;
|
|
var h = data.step.dt;
|
|
this.m_gamma = h * (d + h * k);
|
|
if (this.m_gamma > 0) {
|
|
this.m_gamma = 1 / this.m_gamma
|
|
}
|
|
this.m_bias = C * h * k * this.m_gamma;
|
|
this.m_springMass = invMass + this.m_gamma;
|
|
if (this.m_springMass > 0) {
|
|
this.m_springMass = 1 / this.m_springMass
|
|
}
|
|
}
|
|
} else {
|
|
this.m_springImpulse = 0
|
|
}
|
|
if (this.m_enableMotor) {
|
|
this.m_motorMass = iA + iB;
|
|
if (this.m_motorMass > 0) {
|
|
this.m_motorMass = 1 / this.m_motorMass
|
|
}
|
|
} else {
|
|
this.m_motorMass = 0;
|
|
this.m_motorImpulse = 0
|
|
}
|
|
if (data.step.warmStarting) {
|
|
this.m_impulse *= data.step.dtRatio;
|
|
this.m_springImpulse *= data.step.dtRatio;
|
|
this.m_motorImpulse *= data.step.dtRatio;
|
|
var P = b2Vec2.Add(b2Vec2.Multiply(this.m_impulse, this.m_ay), b2Vec2.Multiply(this.m_springImpulse, this.m_ax));
|
|
var LA = this.m_impulse * this.m_sAy + this.m_springImpulse * this.m_sAx + this.m_motorImpulse;
|
|
var LB = this.m_impulse * this.m_sBy + this.m_springImpulse * this.m_sBx + this.m_motorImpulse;
|
|
vA.Subtract(b2Vec2.Multiply(this.m_invMassA, P));
|
|
wA -= this.m_invIA * LA;
|
|
vB.Add(b2Vec2.Multiply(this.m_invMassB, P));
|
|
wB += this.m_invIB * LB
|
|
} else {
|
|
this.m_impulse = 0;
|
|
this.m_springImpulse = 0;
|
|
this.m_motorImpulse = 0
|
|
}
|
|
data.velocities[this.m_indexA].v.Assign(vA);
|
|
data.velocities[this.m_indexA].w = wA;
|
|
data.velocities[this.m_indexB].v.Assign(vB);
|
|
data.velocities[this.m_indexB].w = wB
|
|
},
|
|
SolveVelocityConstraints: function (data) {
|
|
var mA = this.m_invMassA,
|
|
mB = this.m_invMassB;
|
|
var iA = this.m_invIA,
|
|
iB = this.m_invIB;
|
|
var vA = data.velocities[this.m_indexA].v.Clone();
|
|
var wA = data.velocities[this.m_indexA].w;
|
|
var vB = data.velocities[this.m_indexB].v.Clone();
|
|
var wB = data.velocities[this.m_indexB].w;
|
|
var Cdot = b2Dot_v2_v2(this.m_ax, b2Vec2.Subtract(vB, vA)) + this.m_sBx * wB - this.m_sAx * wA;
|
|
var impulse = -this.m_springMass * (Cdot + this.m_bias + this.m_gamma * this.m_springImpulse);
|
|
this.m_springImpulse += impulse;
|
|
var P = b2Vec2.Multiply(impulse, this.m_ax);
|
|
var LA = impulse * this.m_sAx;
|
|
var LB = impulse * this.m_sBx;
|
|
vA.Subtract(b2Vec2.Multiply(mA, P));
|
|
wA -= iA * LA;
|
|
vB.Add(b2Vec2.Multiply(mB, P));
|
|
wB += iB * LB;
|
|
var Cdot = wB - wA - this.m_motorSpeed;
|
|
var impulse = -this.m_motorMass * Cdot;
|
|
var oldImpulse = this.m_motorImpulse;
|
|
var maxImpulse = data.step.dt * this.m_maxMotorTorque;
|
|
this.m_motorImpulse = b2Clamp(this.m_motorImpulse + impulse, -maxImpulse, maxImpulse);
|
|
impulse = this.m_motorImpulse - oldImpulse;
|
|
wA -= iA * impulse;
|
|
wB += iB * impulse;
|
|
var Cdot = b2Dot_v2_v2(this.m_ay, b2Vec2.Subtract(vB, vA)) + this.m_sBy * wB - this.m_sAy * wA;
|
|
var impulse = -this.m_mass * Cdot;
|
|
this.m_impulse += impulse;
|
|
var P = b2Vec2.Multiply(impulse, this.m_ay);
|
|
var LA = impulse * this.m_sAy;
|
|
var LB = impulse * this.m_sBy;
|
|
vA.Subtract(b2Vec2.Multiply(mA, P));
|
|
wA -= iA * LA;
|
|
vB.Add(b2Vec2.Multiply(mB, P));
|
|
wB += iB * LB;
|
|
data.velocities[this.m_indexA].v.Assign(vA);
|
|
data.velocities[this.m_indexA].w = wA;
|
|
data.velocities[this.m_indexB].v.Assign(vB);
|
|
data.velocities[this.m_indexB].w = wB
|
|
},
|
|
SolvePositionConstraints: function (data) {
|
|
var cA = data.positions[this.m_indexA].c.Clone();
|
|
var aA = data.positions[this.m_indexA].a;
|
|
var cB = data.positions[this.m_indexB].c.Clone();
|
|
var aB = data.positions[this.m_indexB].a;
|
|
var qA = new b2Rot(aA),
|
|
qB = new b2Rot(aB);
|
|
var rA = b2Mul_r_v2(qA, b2Vec2.Subtract(this.m_localAnchorA, this.m_localCenterA));
|
|
var rB = b2Mul_r_v2(qB, b2Vec2.Subtract(this.m_localAnchorB, this.m_localCenterB));
|
|
var d = b2Vec2.Add(b2Vec2.Subtract(cB, cA), b2Vec2.Subtract(rB, rA));
|
|
var ay = b2Mul_r_v2(qA, this.m_localYAxisA);
|
|
var sAy = b2Cross_v2_v2(b2Vec2.Add(d, rA), ay);
|
|
var sBy = b2Cross_v2_v2(rB, ay);
|
|
var C = b2Dot_v2_v2(d, ay);
|
|
var k = this.m_invMassA + this.m_invMassB + this.m_invIA * this.m_sAy * this.m_sAy + this.m_invIB * this.m_sBy * this.m_sBy;
|
|
var impulse;
|
|
if (k != 0) {
|
|
impulse = -C / k
|
|
} else {
|
|
impulse = 0
|
|
}
|
|
var P = b2Vec2.Multiply(impulse, ay);
|
|
var LA = impulse * sAy;
|
|
var LB = impulse * sBy;
|
|
cA.Subtract(b2Vec2.Multiply(this.m_invMassA, P));
|
|
aA -= this.m_invIA * LA;
|
|
cB.Add(b2Vec2.Multiply(this.m_invMassB, P));
|
|
aB += this.m_invIB * LB;
|
|
data.positions[this.m_indexA].c.Assign(cA);
|
|
data.positions[this.m_indexA].a = aA;
|
|
data.positions[this.m_indexB].c.Assign(cB);
|
|
data.positions[this.m_indexB].a = aB;
|
|
return b2Abs(C) <= b2_linearSlop
|
|
},
|
|
_serialize: function (out) {
|
|
var obj = out || {};
|
|
this.parent.prototype._serialize.call(this, obj);
|
|
obj.localAnchorA = this.m_localAnchorA._serialize();
|
|
obj.localAnchorB = this.m_localAnchorB._serialize();
|
|
obj.localAxisA = this.m_localAxisA._serialize();
|
|
obj.enableMotor = this.m_enableMotor;
|
|
obj.maxMotorTorque = this.m_maxMotorTorque;
|
|
obj.motorSpeed = this.m_motorSpeed;
|
|
obj.frequencyHz = this.m_frequencyHz;
|
|
obj.dampingRatio = this.m_dampingRatio;
|
|
return obj
|
|
}
|
|
};
|
|
b2WheelJoint._extend(b2Joint);
|
|
|
|
function b2GearJointDef() {
|
|
this.parent.call(this);
|
|
this.type = b2Joint.e_gearJoint;
|
|
this.joint1 = null;
|
|
this.joint2 = null;
|
|
this.ratio = 1;
|
|
Object.seal(this)
|
|
}
|
|
b2GearJointDef.prototype = {
|
|
_deserialize: function (data, bodies, joints) {
|
|
this.parent.prototype._deserialize.call(this, data, bodies, joints);
|
|
this.joint1 = data.joint1;
|
|
this.joint2 = data.joint2;
|
|
this.ratio = data.ratio
|
|
}
|
|
};
|
|
b2GearJointDef._extend(b2JointDef);
|
|
|
|
function b2GearJoint(def) {
|
|
this.parent.call(this, def);
|
|
this.m_joint1 = def.joint1;
|
|
this.m_joint2 = def.joint2;
|
|
this.m_typeA = this.m_joint1.GetType();
|
|
this.m_typeB = this.m_joint2.GetType();
|
|
var coordinateA, coordinateB;
|
|
this.m_bodyC = this.m_joint1.GetBodyA();
|
|
this.m_bodyA = this.m_joint1.GetBodyB();
|
|
var xfA = this.m_bodyA.m_xf;
|
|
var aA = this.m_bodyA.m_sweep.a;
|
|
var xfC = this.m_bodyC.m_xf;
|
|
var aC = this.m_bodyC.m_sweep.a;
|
|
this.m_localAnchorA = new b2Vec2();
|
|
this.m_localAnchorB = new b2Vec2();
|
|
this.m_localAnchorC = new b2Vec2();
|
|
this.m_localAnchorD = new b2Vec2();
|
|
this.m_localAxisC = new b2Vec2();
|
|
this.m_localAxisD = new b2Vec2();
|
|
if (this.m_typeA == b2Joint.e_revoluteJoint) {
|
|
var revolute = def.joint1;
|
|
this.m_localAnchorC.Assign(revolute.m_localAnchorA);
|
|
this.m_localAnchorA.Assign(revolute.m_localAnchorB);
|
|
this.m_referenceAngleA = revolute.m_referenceAngle;
|
|
this.m_localAxisC.SetZero();
|
|
coordinateA = aA - aC - this.m_referenceAngleA
|
|
} else {
|
|
var prismatic = def.joint1;
|
|
this.m_localAnchorC.Assign(prismatic.m_localAnchorA);
|
|
this.m_localAnchorA.Assign(prismatic.m_localAnchorB);
|
|
this.m_referenceAngleA = prismatic.m_referenceAngle;
|
|
this.m_localAxisC.Assign(prismatic.m_localXAxisA);
|
|
var pC = this.m_localAnchorC;
|
|
var pA = b2MulT_r_v2(xfC.q, b2Vec2.Add(b2Mul_r_v2(xfA.q, this.m_localAnchorA), b2Vec2.Subtract(xfA.p, xfC.p)));
|
|
coordinateA = b2Dot_v2_v2(b2Vec2.Subtract(pA, pC), this.m_localAxisC)
|
|
}
|
|
this.m_bodyD = this.m_joint2.GetBodyA();
|
|
this.m_bodyB = this.m_joint2.GetBodyB();
|
|
var xfB = this.m_bodyB.m_xf;
|
|
var aB = this.m_bodyB.m_sweep.a;
|
|
var xfD = this.m_bodyD.m_xf;
|
|
var aD = this.m_bodyD.m_sweep.a;
|
|
if (this.m_typeB == b2Joint.e_revoluteJoint) {
|
|
var revolute = def.joint2;
|
|
this.m_localAnchorD.Assign(revolute.m_localAnchorA);
|
|
this.m_localAnchorB.Assign(revolute.m_localAnchorB);
|
|
this.m_referenceAngleB = revolute.m_referenceAngle;
|
|
this.m_localAxisD.SetZero();
|
|
coordinateB = aB - aD - this.m_referenceAngleB
|
|
} else {
|
|
var prismatic = def.joint2;
|
|
this.m_localAnchorD.Assign(prismatic.m_localAnchorA);
|
|
this.m_localAnchorB.Assign(prismatic.m_localAnchorB);
|
|
this.m_referenceAngleB = prismatic.m_referenceAngle;
|
|
this.m_localAxisD.Assign(prismatic.m_localXAxisA);
|
|
var pD = this.m_localAnchorD;
|
|
var pB = b2MulT_r_v2(xfD.q, b2Vec2.Add(b2Mul_r_v2(xfB.q, this.m_localAnchorB), b2Vec2.Subtract(xfB.p, xfD.p)));
|
|
coordinateB = b2Dot_v2_v2(b2Vec2.Subtract(pB, pD), this.m_localAxisD)
|
|
}
|
|
this.m_ratio = def.ratio;
|
|
this.m_constant = coordinateA + this.m_ratio * coordinateB;
|
|
this.m_impulse = 0;
|
|
this.m_indexA = this.m_indexB = this.m_indexC = this.m_indexD = 0;
|
|
this.m_lcA = new b2Vec2();
|
|
this.m_lcB = new b2Vec2();
|
|
this.m_lcC = new b2Vec2();
|
|
this.m_lcD = new b2Vec2();
|
|
this.m_mA = this.m_mB = this.m_mC = this.m_mD = 0;
|
|
this.m_iA = this.m_iB = this.m_iC = this.m_iD = 0;
|
|
this.m_JvAC = new b2Vec2(), this.m_JvBD = new b2Vec2();
|
|
this.m_JwA = this.m_JwB = this.m_JwC = this.m_JwD = 0;
|
|
this.m_mass = 0
|
|
}
|
|
b2GearJoint.prototype = {
|
|
GetAnchorA: function () {
|
|
return this.m_bodyA.GetWorldPoint(this.m_localAnchorA)
|
|
},
|
|
GetAnchorB: function () {
|
|
return this.m_bodyB.GetWorldPoint(this.m_localAnchorB)
|
|
},
|
|
GetReactionForce: function (inv_dt) {
|
|
var P = b2Vec2.Multiply(this.m_impulse, this.m_JvAC);
|
|
return b2Vec2.Multiply(inv_dt, P)
|
|
},
|
|
GetReactionTorque: function (inv_dt) {
|
|
var L = this.m_impulse * this.m_JwA;
|
|
return inv_dt * L
|
|
},
|
|
GetJoint1: function () {
|
|
return this.m_joint1
|
|
},
|
|
GetJoint2: function () {
|
|
return this.m_joint2
|
|
},
|
|
SetRatio: function (ratio) {
|
|
this.m_ratio = ratio
|
|
},
|
|
GetRatio: function () {
|
|
return this.m_ratio
|
|
},
|
|
InitVelocityConstraints: function (data) {
|
|
this.m_indexA = this.m_bodyA.m_islandIndex;
|
|
this.m_indexB = this.m_bodyB.m_islandIndex;
|
|
this.m_indexC = this.m_bodyC.m_islandIndex;
|
|
this.m_indexD = this.m_bodyD.m_islandIndex;
|
|
this.m_lcA.Assign(this.m_bodyA.m_sweep.localCenter);
|
|
this.m_lcB.Assign(this.m_bodyB.m_sweep.localCenter);
|
|
this.m_lcC.Assign(this.m_bodyC.m_sweep.localCenter);
|
|
this.m_lcD.Assign(this.m_bodyD.m_sweep.localCenter);
|
|
this.m_mA = this.m_bodyA.m_invMass;
|
|
this.m_mB = this.m_bodyB.m_invMass;
|
|
this.m_mC = this.m_bodyC.m_invMass;
|
|
this.m_mD = this.m_bodyD.m_invMass;
|
|
this.m_iA = this.m_bodyA.m_invI;
|
|
this.m_iB = this.m_bodyB.m_invI;
|
|
this.m_iC = this.m_bodyC.m_invI;
|
|
this.m_iD = this.m_bodyD.m_invI;
|
|
var aA = data.positions[this.m_indexA].a;
|
|
var vA = data.velocities[this.m_indexA].v.Clone();
|
|
var wA = data.velocities[this.m_indexA].w;
|
|
var aB = data.positions[this.m_indexB].a;
|
|
var vB = data.velocities[this.m_indexB].v.Clone();
|
|
var wB = data.velocities[this.m_indexB].w;
|
|
var aC = data.positions[this.m_indexC].a;
|
|
var vC = data.velocities[this.m_indexC].v.Clone();
|
|
var wC = data.velocities[this.m_indexC].w;
|
|
var aD = data.positions[this.m_indexD].a;
|
|
var vD = data.velocities[this.m_indexD].v.Clone();
|
|
var wD = data.velocities[this.m_indexD].w;
|
|
var qA = new b2Rot(aA),
|
|
qB = new b2Rot(aB),
|
|
qC = new b2Rot(aC),
|
|
qD = new b2Rot(aD);
|
|
this.m_mass = 0;
|
|
if (this.m_typeA == b2Joint.e_revoluteJoint) {
|
|
this.m_JvAC.SetZero();
|
|
this.m_JwA = 1;
|
|
this.m_JwC = 1;
|
|
this.m_mass += this.m_iA + this.m_iC
|
|
} else {
|
|
var u = b2Mul_r_v2(qC, this.m_localAxisC);
|
|
var rC = b2Mul_r_v2(qC, b2Vec2.Subtract(this.m_localAnchorC, this.m_lcC));
|
|
var rA = b2Mul_r_v2(qA, b2Vec2.Subtract(this.m_localAnchorA, this.m_lcA));
|
|
this.m_JvAC.Assign(u);
|
|
this.m_JwC = b2Cross_v2_v2(rC, u);
|
|
this.m_JwA = b2Cross_v2_v2(rA, u);
|
|
this.m_mass += this.m_mC + this.m_mA + this.m_iC * this.m_JwC * this.m_JwC + this.m_iA * this.m_JwA * this.m_JwA
|
|
}
|
|
if (this.m_typeB == b2Joint.e_revoluteJoint) {
|
|
this.m_JvBD.SetZero();
|
|
this.m_JwB = this.m_ratio;
|
|
this.m_JwD = this.m_ratio;
|
|
this.m_mass += this.m_ratio * this.m_ratio * (this.m_iB + this.m_iD)
|
|
} else {
|
|
var u = b2Mul_r_v2(qD, this.m_localAxisD);
|
|
var rD = b2Mul_r_v2(qD, b2Vec2.Subtract(this.m_localAnchorD, this.m_lcD));
|
|
var rB = b2Mul_r_v2(qB, b2Vec2.Subtract(this.m_localAnchorB, this.m_lcB));
|
|
this.m_JvBD.Assign(b2Vec2.Multiply(this.m_ratio, u));
|
|
this.m_JwD = this.m_ratio * b2Cross_v2_v2(rD, u);
|
|
this.m_JwB = this.m_ratio * b2Cross_v2_v2(rB, u);
|
|
this.m_mass += this.m_ratio * this.m_ratio * (this.m_mD + this.m_mB) + this.m_iD * this.m_JwD * this.m_JwD + this.m_iB * this.m_JwB * this.m_JwB
|
|
}
|
|
this.m_mass = this.m_mass > 0 ? 1 / this.m_mass : 0;
|
|
if (data.step.warmStarting) {
|
|
vA.Add(b2Vec2.Multiply((this.m_mA * this.m_impulse), this.m_JvAC));
|
|
wA += this.m_iA * this.m_impulse * this.m_JwA;
|
|
vB.Add(b2Vec2.Multiply((this.m_mB * this.m_impulse), this.m_JvBD));
|
|
wB += this.m_iB * this.m_impulse * this.m_JwB;
|
|
vC.Subtract(b2Vec2.Multiply((this.m_mC * this.m_impulse), this.m_JvAC));
|
|
wC -= this.m_iC * this.m_impulse * this.m_JwC;
|
|
vD.Subtract(b2Vec2.Multiply((this.m_mD * this.m_impulse), this.m_JvBD));
|
|
wD -= this.m_iD * this.m_impulse * this.m_JwD
|
|
} else {
|
|
this.m_impulse = 0
|
|
}
|
|
data.velocities[this.m_indexA].v.Assign(vA);
|
|
data.velocities[this.m_indexA].w = wA;
|
|
data.velocities[this.m_indexB].v.Assign(vB);
|
|
data.velocities[this.m_indexB].w = wB;
|
|
data.velocities[this.m_indexC].v.Assign(vC);
|
|
data.velocities[this.m_indexC].w = wC;
|
|
data.velocities[this.m_indexD].v.Assign(vD);
|
|
data.velocities[this.m_indexD].w = wD
|
|
},
|
|
SolveVelocityConstraints: function (data) {
|
|
var vA = data.velocities[this.m_indexA].v.Clone();
|
|
var wA = data.velocities[this.m_indexA].w;
|
|
var vB = data.velocities[this.m_indexB].v.Clone();
|
|
var wB = data.velocities[this.m_indexB].w;
|
|
var vC = data.velocities[this.m_indexC].v.Clone();
|
|
var wC = data.velocities[this.m_indexC].w;
|
|
var vD = data.velocities[this.m_indexD].v.Clone();
|
|
var wD = data.velocities[this.m_indexD].w;
|
|
var Cdot = b2Dot_v2_v2(this.m_JvAC, b2Vec2.Subtract(vA, vC)) + b2Dot_v2_v2(this.m_JvBD, b2Vec2.Subtract(vB, vD));
|
|
Cdot += (this.m_JwA * wA - this.m_JwC * wC) + (this.m_JwB * wB - this.m_JwD * wD);
|
|
var impulse = -this.m_mass * Cdot;
|
|
this.m_impulse += impulse;
|
|
vA.Add(b2Vec2.Multiply((this.m_mA * impulse), this.m_JvAC));
|
|
wA += this.m_iA * impulse * this.m_JwA;
|
|
vB.Add(b2Vec2.Multiply((this.m_mB * impulse), this.m_JvBD));
|
|
wB += this.m_iB * impulse * this.m_JwB;
|
|
vC.Subtract(b2Vec2.Multiply((this.m_mC * impulse), this.m_JvAC));
|
|
wC -= this.m_iC * impulse * this.m_JwC;
|
|
vD.Subtract(b2Vec2.Multiply((this.m_mD * impulse), this.m_JvBD));
|
|
wD -= this.m_iD * impulse * this.m_JwD;
|
|
data.velocities[this.m_indexA].v.Assign(vA);
|
|
data.velocities[this.m_indexA].w = wA;
|
|
data.velocities[this.m_indexB].v.Assign(vB);
|
|
data.velocities[this.m_indexB].w = wB;
|
|
data.velocities[this.m_indexC].v.Assign(vC);
|
|
data.velocities[this.m_indexC].w = wC;
|
|
data.velocities[this.m_indexD].v.Assign(vD);
|
|
data.velocities[this.m_indexD].w = wD
|
|
},
|
|
SolvePositionConstraints: function (data) {
|
|
var cA = data.positions[this.m_indexA].c.Clone();
|
|
var aA = data.positions[this.m_indexA].a;
|
|
var cB = data.positions[this.m_indexB].c.Clone();
|
|
var aB = data.positions[this.m_indexB].a;
|
|
var cC = data.positions[this.m_indexC].c.Clone();
|
|
var aC = data.positions[this.m_indexC].a;
|
|
var cD = data.positions[this.m_indexD].c.Clone();
|
|
var aD = data.positions[this.m_indexD].a;
|
|
var qA = new b2Rot(aA),
|
|
qB = new b2Rot(aB),
|
|
qC = new b2Rot(aC),
|
|
qD = new b2Rot(aD);
|
|
var linearError = 0;
|
|
var coordinateA, coordinateB;
|
|
var JvAC = new b2Vec2(),
|
|
JvBD = new b2Vec2();
|
|
var JwA, JwB, JwC, JwD;
|
|
var mass = 0;
|
|
if (this.m_typeA == b2Joint.e_revoluteJoint) {
|
|
JvAC.SetZero();
|
|
JwA = 1;
|
|
JwC = 1;
|
|
mass += this.m_iA + this.m_iC;
|
|
coordinateA = aA - aC - this.m_referenceAngleA
|
|
} else {
|
|
var u = b2Mul_r_v2(qC, this.m_localAxisC);
|
|
var rC = b2Mul_r_v2(qC, b2Vec2.Subtract(this.m_localAnchorC, this.m_lcC));
|
|
var rA = b2Mul_r_v2(qA, b2Vec2.Subtract(this.m_localAnchorA, this.m_lcA));
|
|
JvAC.Assign(u);
|
|
JwC = b2Cross_v2_v2(rC, u);
|
|
JwA = b2Cross_v2_v2(rA, u);
|
|
mass += this.m_mC + this.m_mA + this.m_iC * JwC * JwC + this.m_iA * JwA * JwA;
|
|
var pC = b2Vec2.Subtract(this.m_localAnchorC, this.m_lcC);
|
|
var pA = b2MulT_r_v2(qC, b2Vec2.Add(rA, b2Vec2.Subtract(cA, cC)));
|
|
coordinateA = b2Dot_v2_v2(b2Vec2.Subtract(pA, pC), this.m_localAxisC)
|
|
}
|
|
if (this.m_typeB == b2Joint.e_revoluteJoint) {
|
|
JvBD.SetZero();
|
|
JwB = this.m_ratio;
|
|
JwD = this.m_ratio;
|
|
mass += this.m_ratio * this.m_ratio * (this.m_iB + this.m_iD);
|
|
coordinateB = aB - aD - this.m_referenceAngleB
|
|
} else {
|
|
var u = b2Mul_r_v2(qD, this.m_localAxisD);
|
|
var rD = b2Mul_r_v2(qD, b2Vec2.Subtract(this.m_localAnchorD, this.m_lcD));
|
|
var rB = b2Mul_r_v2(qB, b2Vec2.Subtract(this.m_localAnchorB, this.m_lcB));
|
|
JvBD.Assign(b2Vec2.Multiply(this.m_ratio, u));
|
|
JwD = this.m_ratio * b2Cross_v2_v2(rD, u);
|
|
JwB = this.m_ratio * b2Cross_v2_v2(rB, u);
|
|
mass += this.m_ratio * this.m_ratio * (this.m_mD + this.m_mB) + this.m_iD * JwD * JwD + this.m_iB * JwB * JwB;
|
|
var pD = b2Vec2.Subtract(this.m_localAnchorD, this.m_lcD);
|
|
var pB = b2MulT_r_v2(qD, b2Vec2.Add(rB, b2Vec2.Subtract(cB, cD)));
|
|
coordinateB = b2Dot_v2_v2(b2Vec2.Subtract(pB, pD), this.m_localAxisD)
|
|
}
|
|
var C = (coordinateA + this.m_ratio * coordinateB) - this.m_constant;
|
|
var impulse = 0;
|
|
if (mass > 0) {
|
|
impulse = -C / mass
|
|
}
|
|
cA.Add(b2Vec2.Multiply(this.m_mA, b2Vec2.Multiply(impulse, JvAC)));
|
|
aA += this.m_iA * impulse * JwA;
|
|
cB.Add(b2Vec2.Multiply(this.m_mB, b2Vec2.Multiply(impulse, JvBD)));
|
|
aB += this.m_iB * impulse * JwB;
|
|
cC.Subtract(b2Vec2.Multiply(this.m_mC, b2Vec2.Multiply(impulse, JvAC)));
|
|
aC -= this.m_iC * impulse * JwC;
|
|
cD.Subtract(b2Vec2.Multiply(this.m_mD, b2Vec2.Multiply(impulse, JvBD)));
|
|
aD -= this.m_iD * impulse * JwD;
|
|
data.positions[this.m_indexA].c.Assign(cA);
|
|
data.positions[this.m_indexA].a = aA;
|
|
data.positions[this.m_indexB].c.Assign(cB);
|
|
data.positions[this.m_indexB].a = aB;
|
|
data.positions[this.m_indexC].c.Assign(cC);
|
|
data.positions[this.m_indexC].a = aC;
|
|
data.positions[this.m_indexD].c.Assign(cD);
|
|
data.positions[this.m_indexD].a = aD;
|
|
return linearError < b2_linearSlop
|
|
},
|
|
_serialize: function (out) {
|
|
var obj = out || {};
|
|
this.parent.prototype._serialize.call(this, obj);
|
|
obj.joint1 = this.m_joint1.__temp_joint_id;
|
|
obj.joint2 = this.m_joint2.__temp_joint_id;
|
|
obj.ratio = this.m_ratio;
|
|
return obj
|
|
}
|
|
};
|
|
b2GearJoint._extend(b2Joint);
|
|
|
|
function b2MotorJointDef() {
|
|
this.parent.call(this);
|
|
this.type = b2Joint.e_motorJoint;
|
|
this.linearOffset = new b2Vec2();
|
|
this.angularOffset = 0;
|
|
this.maxForce = 1;
|
|
this.maxTorque = 1;
|
|
this.correctionFactor = 0.3;
|
|
Object.seal(this)
|
|
}
|
|
b2MotorJointDef.prototype = {
|
|
Initialize: function (bA, bB) {
|
|
this.bodyA = bA;
|
|
this.bodyB = bB;
|
|
var xB = this.bodyB.GetPosition();
|
|
this.linearOffset.Assign(this.bodyA.GetLocalPoint(xB));
|
|
var angleA = this.bodyA.GetAngle();
|
|
var angleB = this.bodyB.GetAngle();
|
|
this.angularOffset = angleB - angleA
|
|
},
|
|
_deserialize: function (data, bodies, joints) {
|
|
this.parent.prototype._deserialize.call(this, data, bodies, joints);
|
|
this.linearOffset._deserialize(data.linearOffset);
|
|
this.angularOffset = data.angularOffset;
|
|
this.maxForce = data.maxForce;
|
|
this.maxTorque = data.maxTorque;
|
|
this.correctionFactor = data.correctionFactor
|
|
}
|
|
};
|
|
b2MotorJointDef._extend(b2JointDef);
|
|
|
|
function b2MotorJoint(def) {
|
|
this.parent.call(this, def);
|
|
this.m_linearOffset = def.linearOffset.Clone();
|
|
this.m_angularOffset = def.angularOffset;
|
|
this.m_linearImpulse = new b2Vec2();
|
|
this.m_angularImpulse = 0;
|
|
this.m_maxForce = def.maxForce;
|
|
this.m_maxTorque = def.maxTorque;
|
|
this.m_correctionFactor = def.correctionFactor;
|
|
this.m_indexA = 0;
|
|
this.m_indexB = 0;
|
|
this.m_rA = new b2Vec2();
|
|
this.m_rB = new b2Vec2();
|
|
this.m_localCenterA = new b2Vec2();
|
|
this.m_localCenterB = new b2Vec2();
|
|
this.m_linearError = new b2Vec2();
|
|
this.m_angularError = 0;
|
|
this.m_invMassA = 0;
|
|
this.m_invMassB = 0;
|
|
this.m_invIA = 0;
|
|
this.m_invIB = 0;
|
|
this.m_linearMass = new b2Mat22();
|
|
this.m_angularMass = 0
|
|
}
|
|
b2MotorJoint.prototype = {
|
|
GetAnchorA: function () {
|
|
return this.m_bodyA.GetPosition()
|
|
},
|
|
GetAnchorB: function () {
|
|
return this.m_bodyB.GetPosition()
|
|
},
|
|
GetReactionForce: function (inv_dt) {
|
|
return b2Vec2.Multiply(inv_dt, this.m_linearImpulse)
|
|
},
|
|
GetReactionTorque: function (inv_dt) {
|
|
return inv_dt * this.m_angularImpulse
|
|
},
|
|
SetLinearOffset: function (linearOffset) {
|
|
if (linearOffset.x != this.m_linearOffset.x || linearOffset.y != this.m_linearOffset.y) {
|
|
this.m_bodyA.SetAwake(true);
|
|
this.m_bodyB.SetAwake(true);
|
|
this.m_linearOffset.Assign(linearOffset)
|
|
}
|
|
},
|
|
GetLinearOffset: function () {
|
|
return this.m_linearOffset
|
|
},
|
|
SetAngularOffset: function (angularOffset) {
|
|
if (angularOffset != this.m_angularOffset) {
|
|
this.m_bodyA.SetAwake(true);
|
|
this.m_bodyB.SetAwake(true);
|
|
this.m_angularOffset = angularOffset
|
|
}
|
|
},
|
|
GetAngularOffset: function () {
|
|
return this.m_angularOffset
|
|
},
|
|
SetMaxForce: function (force) {
|
|
this.m_maxForce = force
|
|
},
|
|
GetMaxForce: function () {
|
|
return this.m_maxForce
|
|
},
|
|
SetMaxTorque: function (torque) {
|
|
this.m_maxTorque = torque
|
|
},
|
|
GetMaxTorque: function () {
|
|
return this.m_maxTorque
|
|
},
|
|
SetCorrectionFactor: function (factor) {
|
|
this.m_correctionFactor = factor
|
|
},
|
|
GetCorrectionFactor: function () {
|
|
return this.m_correctionFactor
|
|
},
|
|
InitVelocityConstraints: function (data) {
|
|
this.m_indexA = this.m_bodyA.m_islandIndex;
|
|
this.m_indexB = this.m_bodyB.m_islandIndex;
|
|
this.m_localCenterA.Assign(this.m_bodyA.m_sweep.localCenter);
|
|
this.m_localCenterB.Assign(this.m_bodyB.m_sweep.localCenter);
|
|
this.m_invMassA = this.m_bodyA.m_invMass;
|
|
this.m_invMassB = this.m_bodyB.m_invMass;
|
|
this.m_invIA = this.m_bodyA.m_invI;
|
|
this.m_invIB = this.m_bodyB.m_invI;
|
|
var cA = data.positions[this.m_indexA].c.Clone();
|
|
var aA = data.positions[this.m_indexA].a;
|
|
var vA = data.velocities[this.m_indexA].v.Clone();
|
|
var wA = data.velocities[this.m_indexA].w;
|
|
var cB = data.positions[this.m_indexB].c.Clone();
|
|
var aB = data.positions[this.m_indexB].a;
|
|
var vB = data.velocities[this.m_indexB].v.Clone();
|
|
var wB = data.velocities[this.m_indexB].w;
|
|
var qA = new b2Rot(aA),
|
|
qB = new b2Rot(aB);
|
|
this.m_rA.Assign(b2Mul_r_v2(qA, this.m_localCenterA.Negate()));
|
|
this.m_rB.Assign(b2Mul_r_v2(qB, this.m_localCenterB.Negate()));
|
|
var mA = this.m_invMassA,
|
|
mB = this.m_invMassB;
|
|
var iA = this.m_invIA,
|
|
iB = this.m_invIB;
|
|
var K = new b2Mat22();
|
|
K.ex.x = mA + mB + iA * this.m_rA.y * this.m_rA.y + iB * this.m_rB.y * this.m_rB.y;
|
|
K.ex.y = -iA * this.m_rA.x * this.m_rA.y - iB * this.m_rB.x * this.m_rB.y;
|
|
K.ey.x = K.ex.y;
|
|
K.ey.y = mA + mB + iA * this.m_rA.x * this.m_rA.x + iB * this.m_rB.x * this.m_rB.x;
|
|
this.m_linearMass.Assign(K.GetInverse());
|
|
this.m_angularMass = iA + iB;
|
|
if (this.m_angularMass > 0) {
|
|
this.m_angularMass = 1 / this.m_angularMass
|
|
}
|
|
this.m_linearError.Assign(b2Vec2.Subtract(b2Vec2.Subtract(b2Vec2.Subtract(b2Vec2.Add(cB, this.m_rB), cA), this.m_rA), b2Mul_r_v2(qA, this.m_linearOffset)));
|
|
this.m_angularError = aB - aA - this.m_angularOffset;
|
|
if (data.step.warmStarting) {
|
|
this.m_linearImpulse.Multiply(data.step.dtRatio);
|
|
this.m_angularImpulse *= data.step.dtRatio;
|
|
var P = new b2Vec2(this.m_linearImpulse.x, this.m_linearImpulse.y);
|
|
vA.Subtract(b2Vec2.Multiply(mA, P));
|
|
wA -= iA * (b2Cross_v2_v2(this.m_rA, P) + this.m_angularImpulse);
|
|
vB.Add(b2Vec2.Multiply(mB, P));
|
|
wB += iB * (b2Cross_v2_v2(this.m_rB, P) + this.m_angularImpulse)
|
|
} else {
|
|
this.m_linearImpulse.SetZero();
|
|
this.m_angularImpulse = 0
|
|
}
|
|
data.velocities[this.m_indexA].v.Assign(vA);
|
|
data.velocities[this.m_indexA].w = wA;
|
|
data.velocities[this.m_indexB].v.Assign(vB);
|
|
data.velocities[this.m_indexB].w = wB
|
|
},
|
|
SolveVelocityConstraints: function (data) {
|
|
var vA = data.velocities[this.m_indexA].v.Clone();
|
|
var wA = data.velocities[this.m_indexA].w;
|
|
var vB = data.velocities[this.m_indexB].v.Clone();
|
|
var wB = data.velocities[this.m_indexB].w;
|
|
var mA = this.m_invMassA,
|
|
mB = this.m_invMassB;
|
|
var iA = this.m_invIA,
|
|
iB = this.m_invIB;
|
|
var h = data.step.dt;
|
|
var inv_h = data.step.inv_dt;
|
|
var Cdot = wB - wA + inv_h * this.m_correctionFactor * this.m_angularError;
|
|
var impulse = -this.m_angularMass * Cdot;
|
|
var oldImpulse = this.m_angularImpulse;
|
|
var maxImpulse = h * this.m_maxTorque;
|
|
this.m_angularImpulse = b2Clamp(this.m_angularImpulse + impulse, -maxImpulse, maxImpulse);
|
|
impulse = this.m_angularImpulse - oldImpulse;
|
|
wA -= iA * impulse;
|
|
wB += iB * impulse;
|
|
var Cdot = b2Vec2.Add(b2Vec2.Subtract(b2Vec2.Subtract(b2Vec2.Add(vB, b2Cross_f_v2(wB, this.m_rB)), vA), b2Cross_f_v2(wA, this.m_rA)), b2Vec2.Multiply(inv_h, b2Vec2.Multiply(this.m_correctionFactor, this.m_linearError)));
|
|
var impulse = b2Mul_m22_v2(this.m_linearMass, Cdot).Negate();
|
|
var oldImpulse = this.m_linearImpulse;
|
|
this.m_linearImpulse.Add(impulse);
|
|
var maxImpulse = h * this.m_maxForce;
|
|
if (this.m_linearImpulse.LengthSquared() > maxImpulse * maxImpulse) {
|
|
this.m_linearImpulse.Normalize();
|
|
this.m_linearImpulse.Multiply(maxImpulse)
|
|
}
|
|
impulse.Assign(b2Vec2.Subtract(this.m_linearImpulse, oldImpulse));
|
|
vA.Subtract(b2Vec2.Multiply(mA, impulse));
|
|
wA -= iA * b2Cross_v2_v2(this.m_rA, impulse);
|
|
vB.Add(b2Vec2.Multiply(mB, impulse));
|
|
wB += iB * b2Cross_v2_v2(this.m_rB, impulse);
|
|
data.velocities[this.m_indexA].v.Assign(vA);
|
|
data.velocities[this.m_indexA].w = wA;
|
|
data.velocities[this.m_indexB].v.Assign(vB);
|
|
data.velocities[this.m_indexB].w = wB
|
|
},
|
|
SolvePositionConstraints: function (data) {
|
|
return true
|
|
},
|
|
_serialize: function (out) {
|
|
var obj = out || {};
|
|
this.parent.prototype._serialize.call(this, obj);
|
|
obj.linearOffset = this.m_linearOffset._serialize();
|
|
obj.angularOffset = this.m_angularOffset;
|
|
obj.maxForce = this.m_maxForce;
|
|
obj.maxTorque = this.m_maxTorque;
|
|
obj.correctionFactor = this.m_correctionFactor;
|
|
return obj
|
|
}
|
|
};
|
|
b2MotorJoint._extend(b2Joint);
|
|
var b2_minPulleyLength = 2;
|
|
|
|
function b2PulleyJointDef() {
|
|
this.parent.call(this);
|
|
this.type = b2Joint.e_pulleyJoint;
|
|
this.groundAnchorA = new b2Vec2(-1, 1);
|
|
this.groundAnchorB = new b2Vec2(1, 1);
|
|
this.localAnchorA = new b2Vec2(-1, 0);
|
|
this.localAnchorB = new b2Vec2(1, 0);
|
|
this.lengthA = 0;
|
|
this.lengthB = 0;
|
|
this.ratio = 1;
|
|
this.collideConnected = true;
|
|
Object.seal(this)
|
|
}
|
|
b2PulleyJointDef.prototype = {
|
|
Initialize: function (bA, bB, groundA, groundB, anchorA, anchorB, r) {
|
|
this.bodyA = bA;
|
|
this.bodyB = bB;
|
|
this.groundAnchorA.Assign(groundA);
|
|
this.groundAnchorB.Assign(groundB);
|
|
this.localAnchorA.Assign(this.bodyA.GetLocalPoint(anchorA));
|
|
this.localAnchorB.Assign(this.bodyB.GetLocalPoint(anchorB));
|
|
var dA = b2Vec2.Subtract(anchorA, groundA);
|
|
this.lengthA = dA.Length();
|
|
var dB = b2Vec2.Subtract(anchorB, groundB);
|
|
this.lengthB = dB.Length();
|
|
this.ratio = r
|
|
},
|
|
_deserialize: function (data, bodies, joints) {
|
|
this.parent.prototype._deserialize.call(this, data, bodies, joints);
|
|
this.groundAnchorA._deserialize(data.groundAnchorA);
|
|
this.groundAnchorB._deserialize(data.groundAnchorB);
|
|
this.localAnchorA._deserialize(data.localAnchorA);
|
|
this.localAnchorB._deserialize(data.localAnchorB);
|
|
this.lengthA = data.lengthA;
|
|
this.lengthB = data.lengthB;
|
|
this.ratio = data.ratio
|
|
}
|
|
};
|
|
b2PulleyJointDef._extend(b2JointDef);
|
|
|
|
function b2PulleyJoint(def) {
|
|
this.parent.call(this, def);
|
|
this.m_indexA = 0;
|
|
this.m_indexB = 0;
|
|
this.m_uA = new b2Vec2();
|
|
this.m_uB = new b2Vec2();
|
|
this.m_rA = new b2Vec2();
|
|
this.m_rB = new b2Vec2();
|
|
this.m_localCenterA = new b2Vec2();
|
|
this.m_localCenterB = new b2Vec2();
|
|
this.m_invMassA = 0;
|
|
this.m_invMassB = 0;
|
|
this.m_invIA = 0;
|
|
this.m_invIB = 0;
|
|
this.m_mass = 0;
|
|
this.m_groundAnchorA = def.groundAnchorA.Clone();
|
|
this.m_groundAnchorB = def.groundAnchorB.Clone();
|
|
this.m_localAnchorA = def.localAnchorA.Clone();
|
|
this.m_localAnchorB = def.localAnchorB.Clone();
|
|
this.m_lengthA = def.lengthA;
|
|
this.m_lengthB = def.lengthB;
|
|
this.m_ratio = def.ratio;
|
|
this.m_constant = def.lengthA + this.m_ratio * def.lengthB;
|
|
this.m_impulse = 0
|
|
}
|
|
b2PulleyJoint.prototype = {
|
|
GetAnchorA: function () {
|
|
return this.m_bodyA.GetWorldPoint(this.m_localAnchorA)
|
|
},
|
|
GetAnchorB: function () {
|
|
return this.m_bodyB.GetWorldPoint(this.m_localAnchorB)
|
|
},
|
|
GetReactionForce: function (inv_dt) {
|
|
var P = b2Vec2.Multiply(this.m_impulse, this.m_uB);
|
|
return b2Vec2.Multiply(inv_dt, P)
|
|
},
|
|
GetReactionTorque: function (inv_dt) {
|
|
return 0
|
|
},
|
|
GetGroundAnchorA: function () {
|
|
return this.m_groundAnchorA
|
|
},
|
|
GetGroundAnchorB: function () {
|
|
return this.m_groundAnchorB
|
|
},
|
|
GetLengthA: function () {
|
|
return this.m_lengthA
|
|
},
|
|
GetLengthB: function () {
|
|
return this.m_lengthB
|
|
},
|
|
GetRatio: function () {
|
|
return this.m_ratio
|
|
},
|
|
GetCurrentLengthA: function () {
|
|
var p = this.m_bodyA.GetWorldPoint(this.m_localAnchorA);
|
|
var s = this.m_groundAnchorA;
|
|
var d = b2Vec2.Subtract(p, s);
|
|
return d.Length()
|
|
},
|
|
GetCurrentLengthB: function () {
|
|
var p = this.m_bodyB.GetWorldPoint(this.m_localAnchorB);
|
|
var s = this.m_groundAnchorB;
|
|
var d = b2Vec2.Subtract(p, s);
|
|
return d.Length()
|
|
},
|
|
ShiftOrigin: function (newOrigin) {
|
|
this.m_groundAnchorA.Subtract(newOrigin);
|
|
this.m_groundAnchorB.Subtract(newOrigin)
|
|
},
|
|
InitVelocityConstraints: function (data) {
|
|
this.m_indexA = this.m_bodyA.m_islandIndex;
|
|
this.m_indexB = this.m_bodyB.m_islandIndex;
|
|
this.m_localCenterA.Assign(this.m_bodyA.m_sweep.localCenter);
|
|
this.m_localCenterB.Assign(this.m_bodyB.m_sweep.localCenter);
|
|
this.m_invMassA = this.m_bodyA.m_invMass;
|
|
this.m_invMassB = this.m_bodyB.m_invMass;
|
|
this.m_invIA = this.m_bodyA.m_invI;
|
|
this.m_invIB = this.m_bodyB.m_invI;
|
|
var cA = data.positions[this.m_indexA].c.Clone();
|
|
var aA = data.positions[this.m_indexA].a;
|
|
var vA = data.velocities[this.m_indexA].v.Clone();
|
|
var wA = data.velocities[this.m_indexA].w;
|
|
var cB = data.positions[this.m_indexB].c.Clone();
|
|
var aB = data.positions[this.m_indexB].a;
|
|
var vB = data.velocities[this.m_indexB].v.Clone();
|
|
var wB = data.velocities[this.m_indexB].w;
|
|
var qA = new b2Rot(aA),
|
|
qB = new b2Rot(aB);
|
|
this.m_rA.Assign(b2Mul_r_v2(qA, b2Vec2.Subtract(this.m_localAnchorA, this.m_localCenterA)));
|
|
this.m_rB.Assign(b2Mul_r_v2(qB, b2Vec2.Subtract(this.m_localAnchorB, this.m_localCenterB)));
|
|
this.m_uA.Assign(b2Vec2.Add(cA, b2Vec2.Subtract(this.m_rA, this.m_groundAnchorA)));
|
|
this.m_uB.Assign(b2Vec2.Add(cB, b2Vec2.Subtract(this.m_rB, this.m_groundAnchorB)));
|
|
var lengthA = this.m_uA.Length();
|
|
var lengthB = this.m_uB.Length();
|
|
if (lengthA > 10 * b2_linearSlop) {
|
|
this.m_uA.Multiply(1 / lengthA)
|
|
} else {
|
|
this.m_uA.SetZero()
|
|
}
|
|
if (lengthB > 10 * b2_linearSlop) {
|
|
this.m_uB.Multiply(1 / lengthB)
|
|
} else {
|
|
this.m_uB.SetZero()
|
|
}
|
|
var ruA = b2Cross_v2_v2(this.m_rA, this.m_uA);
|
|
var ruB = b2Cross_v2_v2(this.m_rB, this.m_uB);
|
|
var mA = this.m_invMassA + this.m_invIA * ruA * ruA;
|
|
var mB = this.m_invMassB + this.m_invIB * ruB * ruB;
|
|
this.m_mass = mA + this.m_ratio * this.m_ratio * mB;
|
|
if (this.m_mass > 0) {
|
|
this.m_mass = 1 / this.m_mass
|
|
}
|
|
if (data.step.warmStarting) {
|
|
this.m_impulse *= data.step.dtRatio;
|
|
var PA = b2Vec2.Multiply(-(this.m_impulse), this.m_uA);
|
|
var PB = b2Vec2.Multiply((-this.m_ratio * this.m_impulse), this.m_uB);
|
|
vA.Add(b2Vec2.Multiply(this.m_invMassA, PA));
|
|
wA += this.m_invIA * b2Cross_v2_v2(this.m_rA, PA);
|
|
vB.Add(b2Vec2.Multiply(this.m_invMassB, PB));
|
|
wB += this.m_invIB * b2Cross_v2_v2(this.m_rB, PB)
|
|
} else {
|
|
this.m_impulse = 0
|
|
}
|
|
data.velocities[this.m_indexA].v.Assign(vA);
|
|
data.velocities[this.m_indexA].w = wA;
|
|
data.velocities[this.m_indexB].v.Assign(vB);
|
|
data.velocities[this.m_indexB].w = wB
|
|
},
|
|
SolveVelocityConstraints: function (data) {
|
|
var vA = data.velocities[this.m_indexA].v.Clone();
|
|
var wA = data.velocities[this.m_indexA].w;
|
|
var vB = data.velocities[this.m_indexB].v.Clone();
|
|
var wB = data.velocities[this.m_indexB].w;
|
|
var vpA = b2Vec2.Add(vA, b2Cross_f_v2(wA, this.m_rA));
|
|
var vpB = b2Vec2.Add(vB, b2Cross_f_v2(wB, this.m_rB));
|
|
var Cdot = -b2Dot_v2_v2(this.m_uA, vpA) - this.m_ratio * b2Dot_v2_v2(this.m_uB, vpB);
|
|
var impulse = -this.m_mass * Cdot;
|
|
this.m_impulse += impulse;
|
|
var PA = b2Vec2.Multiply(-impulse, this.m_uA);
|
|
var PB = b2Vec2.Multiply(-this.m_ratio, b2Vec2.Multiply(impulse, this.m_uB));
|
|
vA.Add(b2Vec2.Multiply(this.m_invMassA, PA));
|
|
wA += this.m_invIA * b2Cross_v2_v2(this.m_rA, PA);
|
|
vB.Add(b2Vec2.Multiply(this.m_invMassB, PB));
|
|
wB += this.m_invIB * b2Cross_v2_v2(this.m_rB, PB);
|
|
data.velocities[this.m_indexA].v.Assign(vA);
|
|
data.velocities[this.m_indexA].w = wA;
|
|
data.velocities[this.m_indexB].v.Assign(vB);
|
|
data.velocities[this.m_indexB].w = wB
|
|
},
|
|
SolvePositionConstraints: function (data) {
|
|
var cA = data.positions[this.m_indexA].c.Clone();
|
|
var aA = data.positions[this.m_indexA].a;
|
|
var cB = data.positions[this.m_indexB].c.Clone();
|
|
var aB = data.positions[this.m_indexB].a;
|
|
var qA = new b2Rot(aA),
|
|
qB = new b2Rot(aB);
|
|
var rA = b2Mul_r_v2(qA, b2Vec2.Subtract(this.m_localAnchorA, this.m_localCenterA));
|
|
var rB = b2Mul_r_v2(qB, b2Vec2.Subtract(this.m_localAnchorB, this.m_localCenterB));
|
|
var uA = b2Vec2.Add(cA, b2Vec2.Subtract(rA, this.m_groundAnchorA));
|
|
var uB = b2Vec2.Add(cB, b2Vec2.Subtract(rB, this.m_groundAnchorB));
|
|
var lengthA = uA.Length();
|
|
var lengthB = uB.Length();
|
|
if (lengthA > 10 * b2_linearSlop) {
|
|
uA.Multiply(1 / lengthA)
|
|
} else {
|
|
uA.SetZero()
|
|
}
|
|
if (lengthB > 10 * b2_linearSlop) {
|
|
uB.Multiply(1 / lengthB)
|
|
} else {
|
|
uB.SetZero()
|
|
}
|
|
var ruA = b2Cross_v2_v2(rA, uA);
|
|
var ruB = b2Cross_v2_v2(rB, uB);
|
|
var mA = this.m_invMassA + this.m_invIA * ruA * ruA;
|
|
var mB = this.m_invMassB + this.m_invIB * ruB * ruB;
|
|
var mass = mA + this.m_ratio * this.m_ratio * mB;
|
|
if (mass > 0) {
|
|
mass = 1 / mass
|
|
}
|
|
var C = this.m_constant - lengthA - this.m_ratio * lengthB;
|
|
var linearError = b2Abs(C);
|
|
var impulse = -mass * C;
|
|
var PA = b2Vec2.Multiply(-impulse, uA);
|
|
var PB = b2Vec2.Multiply(-this.m_ratio, b2Vec2.Multiply(impulse, uB));
|
|
cA.Add(b2Vec2.Multiply(this.m_invMassA, PA));
|
|
aA += this.m_invIA * b2Cross_v2_v2(rA, PA);
|
|
cB.Add(b2Vec2.Multiply(this.m_invMassB, PB));
|
|
aB += this.m_invIB * b2Cross_v2_v2(rB, PB);
|
|
data.positions[this.m_indexA].c.Assign(cA);
|
|
data.positions[this.m_indexA].a = aA;
|
|
data.positions[this.m_indexB].c.Assign(cB);
|
|
data.positions[this.m_indexB].a = aB;
|
|
return linearError < b2_linearSlop
|
|
},
|
|
_serialize: function (out) {
|
|
var obj = out || {};
|
|
this.parent.prototype._serialize.call(this, obj);
|
|
obj.groundAnchorA = this.m_groundAnchorA._serialize();
|
|
obj.groundAnchorB = this.m_groundAnchorB._serialize();
|
|
obj.localAnchorA = this.m_localAnchorA._serialize();
|
|
obj.localAnchorB = this.m_localAnchorB._serialize();
|
|
obj.lengthA = this.m_lengthA;
|
|
obj.lengthB = this.m_lengthB;
|
|
obj.ratio = this.m_ratio;
|
|
return obj
|
|
}
|
|
};
|
|
b2PulleyJoint._extend(b2Joint);
|
|
|
|
function b2RopeJointDef() {
|
|
this.parent.call(this);
|
|
this.type = b2Joint.e_ropeJoint;
|
|
this.localAnchorA = new b2Vec2(-1, 0);
|
|
this.localAnchorB = new b2Vec2(1, 0);
|
|
this.maxLength = 0;
|
|
Object.seal(this)
|
|
}
|
|
b2RopeJointDef.prototype = {
|
|
_deserialize: function (data, bodies, joints) {
|
|
this.parent.prototype._deserialize.call(this, data, bodies, joints);
|
|
this.localAnchorA._deserialize(data.localAnchorA);
|
|
this.localAnchorB._deserialize(data.localAnchorB);
|
|
this.maxLength = data.maxLength
|
|
}
|
|
};
|
|
b2RopeJointDef._extend(b2JointDef);
|
|
|
|
function b2RopeJoint(def) {
|
|
this.parent.call(this, def);
|
|
this.m_localAnchorA = def.localAnchorA.Clone();
|
|
this.m_localAnchorB = def.localAnchorB.Clone();
|
|
this.m_maxLength = def.maxLength;
|
|
this.m_mass = 0;
|
|
this.m_impulse = 0;
|
|
this.m_state = b2Joint.e_inactiveLimit;
|
|
this.m_length = 0;
|
|
this.m_indexA = 0;
|
|
this.m_indexB = 0;
|
|
this.m_u = new b2Vec2();
|
|
this.m_rA = new b2Vec2();
|
|
this.m_rB = new b2Vec2();
|
|
this.m_localCenterA = new b2Vec2();
|
|
this.m_localCenterB = new b2Vec2();
|
|
this.m_invMassA = 0;
|
|
this.m_invMassB = 0;
|
|
this.m_invIA = 0;
|
|
this.m_invIB = 0
|
|
}
|
|
b2RopeJoint.prototype = {
|
|
GetAnchorA: function () {
|
|
return this.m_bodyA.GetWorldPoint(this.m_localAnchorA)
|
|
},
|
|
GetAnchorB: function () {
|
|
return this.m_bodyB.GetWorldPoint(this.m_localAnchorB)
|
|
},
|
|
GetReactionForce: function (inv_dt) {
|
|
var F = b2Vec2.Multiply((inv_dt * this.m_impulse), this.m_u);
|
|
return F
|
|
},
|
|
GetReactionTorque: function (inv_dt) {
|
|
return 0
|
|
},
|
|
GetLocalAnchorA: function () {
|
|
return this.m_localAnchorA
|
|
},
|
|
GetLocalAnchorB: function () {
|
|
return this.m_localAnchorB
|
|
},
|
|
SetMaxLength: function (length) {
|
|
this.m_maxLength = length
|
|
},
|
|
GetMaxLength: function () {
|
|
return this.m_maxLength
|
|
},
|
|
GetLimitState: function () {
|
|
return this.m_state
|
|
},
|
|
InitVelocityConstraints: function (data) {
|
|
this.m_indexA = this.m_bodyA.m_islandIndex;
|
|
this.m_indexB = this.m_bodyB.m_islandIndex;
|
|
this.m_localCenterA.Assign(this.m_bodyA.m_sweep.localCenter);
|
|
this.m_localCenterB.Assign(this.m_bodyB.m_sweep.localCenter);
|
|
this.m_invMassA = this.m_bodyA.m_invMass;
|
|
this.m_invMassB = this.m_bodyB.m_invMass;
|
|
this.m_invIA = this.m_bodyA.m_invI;
|
|
this.m_invIB = this.m_bodyB.m_invI;
|
|
var cA = data.positions[this.m_indexA].c.Clone();
|
|
var aA = data.positions[this.m_indexA].a;
|
|
var vA = data.velocities[this.m_indexA].v.Clone();
|
|
var wA = data.velocities[this.m_indexA].w;
|
|
var cB = data.positions[this.m_indexB].c.Clone();
|
|
var aB = data.positions[this.m_indexB].a;
|
|
var vB = data.velocities[this.m_indexB].v.Clone();
|
|
var wB = data.velocities[this.m_indexB].w;
|
|
var qA = new b2Rot(aA),
|
|
qB = new b2Rot(aB);
|
|
this.m_rA.Assign(b2Mul_r_v2(qA, b2Vec2.Subtract(this.m_localAnchorA, this.m_localCenterA)));
|
|
this.m_rB.Assign(b2Mul_r_v2(qB, b2Vec2.Subtract(this.m_localAnchorB, this.m_localCenterB)));
|
|
this.m_u.Assign(b2Vec2.Subtract(b2Vec2.Subtract(b2Vec2.Add(cB, this.m_rB), cA), this.m_rA));
|
|
this.m_length = this.m_u.Length();
|
|
var C = this.m_length - this.m_maxLength;
|
|
if (C > 0) {
|
|
this.m_state = b2Joint.e_atUpperLimit
|
|
} else {
|
|
this.m_state = b2Joint.e_inactiveLimit
|
|
}
|
|
if (this.m_length > b2_linearSlop) {
|
|
this.m_u.Multiply(1 / this.m_length)
|
|
} else {
|
|
this.m_u.SetZero();
|
|
this.m_mass = 0;
|
|
this.m_impulse = 0;
|
|
return
|
|
}
|
|
var crA = b2Cross_v2_v2(this.m_rA, this.m_u);
|
|
var crB = b2Cross_v2_v2(this.m_rB, this.m_u);
|
|
var invMass = this.m_invMassA + this.m_invIA * crA * crA + this.m_invMassB + this.m_invIB * crB * crB;
|
|
this.m_mass = invMass != 0 ? 1 / invMass : 0;
|
|
if (data.step.warmStarting) {
|
|
this.m_impulse *= data.step.dtRatio;
|
|
var P = b2Vec2.Multiply(this.m_impulse, this.m_u);
|
|
vA.Subtract(b2Vec2.Multiply(this.m_invMassA, P));
|
|
wA -= this.m_invIA * b2Cross_v2_v2(this.m_rA, P);
|
|
vB.Add(b2Vec2.Multiply(this.m_invMassB, P));
|
|
wB += this.m_invIB * b2Cross_v2_v2(this.m_rB, P)
|
|
} else {
|
|
this.m_impulse = 0
|
|
}
|
|
data.velocities[this.m_indexA].v.Assign(vA);
|
|
data.velocities[this.m_indexA].w = wA;
|
|
data.velocities[this.m_indexB].v.Assign(vB);
|
|
data.velocities[this.m_indexB].w = wB
|
|
},
|
|
SolveVelocityConstraints: function (data) {
|
|
var vA = data.velocities[this.m_indexA].v.Clone();
|
|
var wA = data.velocities[this.m_indexA].w;
|
|
var vB = data.velocities[this.m_indexB].v.Clone();
|
|
var wB = data.velocities[this.m_indexB].w;
|
|
var vpA = b2Vec2.Add(vA, b2Cross_f_v2(wA, this.m_rA));
|
|
var vpB = b2Vec2.Add(vB, b2Cross_f_v2(wB, this.m_rB));
|
|
var C = this.m_length - this.m_maxLength;
|
|
var Cdot = b2Dot_v2_v2(this.m_u, b2Vec2.Subtract(vpB, vpA));
|
|
if (C < 0) {
|
|
Cdot += data.step.inv_dt * C
|
|
}
|
|
var impulse = -this.m_mass * Cdot;
|
|
var oldImpulse = this.m_impulse;
|
|
this.m_impulse = b2Min(0, this.m_impulse + impulse);
|
|
impulse = this.m_impulse - oldImpulse;
|
|
var P = b2Vec2.Multiply(impulse, this.m_u);
|
|
vA.Subtract(b2Vec2.Multiply(this.m_invMassA, P));
|
|
wA -= this.m_invIA * b2Cross_v2_v2(this.m_rA, P);
|
|
vB.Add(b2Vec2.Multiply(this.m_invMassB, P));
|
|
wB += this.m_invIB * b2Cross_v2_v2(this.m_rB, P);
|
|
data.velocities[this.m_indexA].v.Assign(vA);
|
|
data.velocities[this.m_indexA].w = wA;
|
|
data.velocities[this.m_indexB].v.Assign(vB);
|
|
data.velocities[this.m_indexB].w = wB
|
|
},
|
|
SolvePositionConstraints: function (data) {
|
|
var cA = data.positions[this.m_indexA].c.Clone();
|
|
var aA = data.positions[this.m_indexA].a;
|
|
var cB = data.positions[this.m_indexB].c.Clone();
|
|
var aB = data.positions[this.m_indexB].a;
|
|
var qA = new b2Rot(aA),
|
|
qB = new b2Rot(aB);
|
|
var rA = b2Mul_r_v2(qA, b2Vec2.Subtract(this.m_localAnchorA, this.m_localCenterA));
|
|
var rB = b2Mul_r_v2(qB, b2Vec2.Subtract(this.m_localAnchorB, this.m_localCenterB));
|
|
var u = b2Vec2.Subtract(b2Vec2.Subtract(b2Vec2.Add(cB, rB), cA), rA);
|
|
var length = u.Normalize();
|
|
var C = length - this.m_maxLength;
|
|
C = b2Clamp(C, 0, b2_maxLinearCorrection);
|
|
var impulse = -this.m_mass * C;
|
|
var P = b2Vec2.Multiply(impulse, u);
|
|
cA.Subtract(b2Vec2.Multiply(this.m_invMassA, P));
|
|
aA -= this.m_invIA * b2Cross_v2_v2(rA, P);
|
|
cB.Add(b2Vec2.Multiply(this.m_invMassB, P));
|
|
aB += this.m_invIB * b2Cross_v2_v2(rB, P);
|
|
data.positions[this.m_indexA].c.Assign(cA);
|
|
data.positions[this.m_indexA].a = aA;
|
|
data.positions[this.m_indexB].c.Assign(cB);
|
|
data.positions[this.m_indexB].a = aB;
|
|
return length - this.m_maxLength < b2_linearSlop
|
|
},
|
|
_serialize: function (out) {
|
|
var obj = out || {};
|
|
this.parent.prototype._serialize.call(this, obj);
|
|
obj.localAnchorA = this.m_localAnchorA._serialize();
|
|
obj.localAnchorB = this.m_localAnchorB._serialize();
|
|
obj.maxLength = this.m_maxLength;
|
|
return obj
|
|
}
|
|
};
|
|
b2RopeJoint._extend(b2Joint);
|
|
var expf = Math.exp;
|
|
|
|
function b2RopeDef() {
|
|
this.vertices = null;
|
|
this.count = 0;
|
|
this.masses = null;
|
|
this.gravity = new b2Vec2();
|
|
this.damping = 0.1;
|
|
this.k2 = 0.9;
|
|
this.k3 = 0.1
|
|
}
|
|
|
|
function b2Rope() {
|
|
this.m_count = 0;
|
|
this.m_ps = null;
|
|
this.m_p0s = null;
|
|
this.m_vs = null;
|
|
this.m_ims = null;
|
|
this.m_Ls = null;
|
|
this.m_as = null;
|
|
this.m_damping = 0;
|
|
this.m_gravity = new b2Vec2();
|
|
this.m_k2 = 1;
|
|
this.m_k3 = 0.1
|
|
}
|
|
b2Rope.prototype = {
|
|
Initialize: function (def) {
|
|
this.m_count = def.count;
|
|
this.m_ps = new Array(this.m_count);
|
|
this.m_p0s = new Array(this.m_count);
|
|
this.m_vs = new Array(this.m_count);
|
|
this.m_ims = new Array(this.m_count);
|
|
for (var i = 0; i < this.m_count; ++i) {
|
|
this.m_ps[i] = def.vertices[i].Clone();
|
|
this.m_p0s[i] = def.vertices[i].Clone();
|
|
this.m_vs[i] = new b2Vec2();
|
|
var m = def.masses[i];
|
|
if (m > 0) {
|
|
this.m_ims[i] = 1 / m
|
|
} else {
|
|
this.m_ims[i] = 0
|
|
}
|
|
}
|
|
var count2 = this.m_count - 1;
|
|
var count3 = this.m_count - 2;
|
|
this.m_Ls = new Array(count2);
|
|
this.m_as = new Array(count3);
|
|
for (var i = 0; i < count2; ++i) {
|
|
var p1 = this.m_ps[i];
|
|
var p2 = this.m_ps[i + 1];
|
|
this.m_Ls[i] = b2Distance(p1, p2)
|
|
}
|
|
for (var i = 0; i < count3; ++i) {
|
|
var p1 = this.m_ps[i];
|
|
var p2 = this.m_ps[i + 1];
|
|
var p3 = this.m_ps[i + 2];
|
|
var d1 = b2Vec2.Subtract(p2, p1);
|
|
var d2 = b2Vec2.Subtract(p3, p2);
|
|
var a = b2Cross_v2_v2(d1, d2);
|
|
var b = b2Dot_v2_v2(d1, d2);
|
|
this.m_as[i] = b2Atan2(a, b)
|
|
}
|
|
this.m_gravity = def.gravity.Clone();
|
|
this.m_damping = def.damping;
|
|
this.m_k2 = def.k2;
|
|
this.m_k3 = def.k3
|
|
},
|
|
Step: function (h, iterations) {
|
|
if (h == 0) {
|
|
return
|
|
}
|
|
var d = expf(-h * this.m_damping);
|
|
for (var i = 0; i < this.m_count; ++i) {
|
|
this.m_p0s[i].Assign(this.m_ps[i]);
|
|
if (this.m_ims[i] > 0) {
|
|
this.m_vs[i].Add(b2Vec2.Multiply(h, this.m_gravity))
|
|
}
|
|
this.m_vs[i].Multiply(d);
|
|
this.m_ps[i].Add(b2Vec2.Multiply(h, this.m_vs[i]))
|
|
}
|
|
for (var i = 0; i < iterations; ++i) {
|
|
this.SolveC2();
|
|
this.SolveC3();
|
|
this.SolveC2()
|
|
}
|
|
var inv_h = 1 / h;
|
|
for (var i = 0; i < this.m_count; ++i) {
|
|
this.m_vs[i] = b2Vec2.Multiply(inv_h, b2Vec2.Subtract(this.m_ps[i], this.m_p0s[i]))
|
|
}
|
|
},
|
|
GetVertexCount: function () {
|
|
return this.m_count
|
|
},
|
|
GetVertices: function () {
|
|
return this.m_ps
|
|
},
|
|
Draw: function (draw) {
|
|
var c = new b2Color(0.4, 0.5, 0.7);
|
|
for (var i = 0; i < this.m_count - 1; ++i) {
|
|
draw.DrawSegment(this.m_ps[i], this.m_ps[i + 1], c)
|
|
}
|
|
},
|
|
SetAngle: function (angle) {
|
|
var count3 = this.m_count - 2;
|
|
for (var i = 0; i < count3; ++i) {
|
|
this.m_as[i] = angle
|
|
}
|
|
},
|
|
SolveC2: function () {
|
|
var count2 = this.m_count - 1;
|
|
for (var i = 0; i < count2; ++i) {
|
|
var p1 = this.m_ps[i];
|
|
var p2 = this.m_ps[i + 1];
|
|
var d = b2Vec2.Subtract(p2, p1);
|
|
var L = d.Normalize();
|
|
var im1 = this.m_ims[i];
|
|
var im2 = this.m_ims[i + 1];
|
|
if (im1 + im2 == 0) {
|
|
continue
|
|
}
|
|
var s1 = im1 / (im1 + im2);
|
|
var s2 = im2 / (im1 + im2);
|
|
p1.Subtract(b2Vec2.Multiply(this.m_k2 * s1 * (this.m_Ls[i] - L), d));
|
|
p2.Add(b2Vec2.Multiply(this.m_k2 * s2 * (this.m_Ls[i] - L), d))
|
|
}
|
|
},
|
|
SolveC3: function () {
|
|
var count3 = this.m_count - 2;
|
|
for (var i = 0; i < count3; ++i) {
|
|
var p1 = this.m_ps[i];
|
|
var p2 = this.m_ps[i + 1];
|
|
var p3 = this.m_ps[i + 2];
|
|
var m1 = this.m_ims[i];
|
|
var m2 = this.m_ims[i + 1];
|
|
var m3 = this.m_ims[i + 2];
|
|
var d1 = b2Vec2.Subtract(p2, p1);
|
|
var d2 = b2Vec2.Subtract(p3, p2);
|
|
var L1sqr = d1.LengthSquared();
|
|
var L2sqr = d2.LengthSquared();
|
|
if (L1sqr * L2sqr == 0) {
|
|
continue
|
|
}
|
|
var a = b2Cross_v2_v2(d1, d2);
|
|
var b = b2Dot_v2_v2(d1, d2);
|
|
var angle = b2Atan2(a, b);
|
|
var Jd1 = b2Vec2.Multiply((-1 / L1sqr), d1.Skew());
|
|
var Jd2 = b2Vec2.Multiply((1 / L2sqr), d2.Skew());
|
|
var J1 = b2Vec2.Negate(Jd1);
|
|
var J2 = b2Vec2.Subtract(Jd1, Jd2);
|
|
var J3 = Jd2;
|
|
var mass = m1 * b2Dot_v2_v2(J1, J1) + m2 * b2Dot_v2_v2(J2, J2) + m3 * b2Dot_v2_v2(J3, J3);
|
|
if (mass == 0) {
|
|
continue
|
|
}
|
|
mass = 1 / mass;
|
|
var C = angle - this.m_as[i];
|
|
while (C > b2_pi) {
|
|
angle -= 2 * b2_pi;
|
|
C = angle - this.m_as[i]
|
|
}
|
|
while (C < -b2_pi) {
|
|
angle += 2 * b2_pi;
|
|
C = angle - this.m_as[i]
|
|
}
|
|
var impulse = -this.m_k3 * mass * C;
|
|
p1.Add(b2Vec2.Multiply((m1 * impulse), J1));
|
|
p2.Add(b2Vec2.Multiply((m2 * impulse), J2));
|
|
p3.Add(b2Vec2.Multiply((m3 * impulse), J3))
|
|
}
|
|
}
|
|
};
|
|
var b2JsonSerializer = {
|
|
serialize: function (world) {
|
|
var shapes = [];
|
|
var i;
|
|
var serialized;
|
|
var b;
|
|
var f;
|
|
var shape;
|
|
for (b = world.GetBodyList(); b; b = b.GetNext()) {
|
|
for (f = b.GetFixtureList(); f; f = f.GetNext()) {
|
|
shape = f.GetShape();
|
|
f.__temp_shape_id = shapes.length;
|
|
shapes.push(shape._serialize())
|
|
}
|
|
}
|
|
var fixtures = [];
|
|
for (b = world.GetBodyList(); b; b = b.GetNext()) {
|
|
b.__temp_fixture_ids = [];
|
|
for (f = b.GetFixtureList(); f; f = f.GetNext()) {
|
|
serialized = f._serialize();
|
|
serialized.shape = f.__temp_shape_id;
|
|
delete f.__temp_shape_id;
|
|
b.__temp_fixture_ids.push(fixtures.length);
|
|
fixtures.push(serialized)
|
|
}
|
|
}
|
|
var bodies = [];
|
|
for (b = world.GetBodyList(); b; b = b.GetNext()) {
|
|
serialized = b._serialize();
|
|
serialized.fixtures = [];
|
|
for (i = 0; i < b.__temp_fixture_ids.length; ++i) {
|
|
serialized.fixtures.push(b.__temp_fixture_ids[i])
|
|
}
|
|
delete b.__temp_fixture_ids;
|
|
b.__temp_body_id = bodies.length;
|
|
bodies.push(serialized)
|
|
}
|
|
var joints = [];
|
|
var j;
|
|
for (j = world.GetJointList(), i = 0; j; j = j.GetNext(), ++i) {
|
|
j.__temp_joint_id = i
|
|
}
|
|
for (j = world.GetJointList(); j; j = j.GetNext()) {
|
|
if (j.GetType() === b2Joint.e_mouseJoint) {
|
|
continue
|
|
}
|
|
serialized = j._serialize();
|
|
serialized.bodyA = j.GetBodyA().__temp_body_id;
|
|
serialized.bodyB = j.GetBodyB().__temp_body_id;
|
|
joints.push(serialized)
|
|
}
|
|
for (j = world.GetJointList(); j; j = j.GetNext()) {
|
|
delete j.__temp_joint_id
|
|
}
|
|
for (b = world.GetBodyList(); b; b = b.GetNext()) {
|
|
delete b.__temp_body_id
|
|
}
|
|
return {
|
|
shapes: shapes,
|
|
fixtures: fixtures,
|
|
bodies: bodies,
|
|
joints: joints
|
|
}
|
|
},
|
|
deserialize: function (serialized, world, clear) {
|
|
var deserialized = JSON.parse(serialized);
|
|
if (clear) {
|
|
for (var b = world.GetBodyList(); b;) {
|
|
var next = b.GetNext();
|
|
world.DestroyBody(b);
|
|
b = next
|
|
}
|
|
for (var j = world.GetJointList(); j;) {
|
|
var next = j.GetNext();
|
|
world.DestroyJoint(j);
|
|
j = next
|
|
}
|
|
}
|
|
var shapes = [];
|
|
for (var i = 0; i < deserialized.shapes.length; ++i) {
|
|
var shapeData = deserialized.shapes[i];
|
|
var shape;
|
|
switch (shapeData.m_type) {
|
|
case b2Shape.e_circle:
|
|
shape = new b2CircleShape();
|
|
break;
|
|
case b2Shape.e_edge:
|
|
shape = new b2EdgeShape();
|
|
break;
|
|
case b2Shape.e_chain:
|
|
shape = new b2ChainShape();
|
|
break;
|
|
case b2Shape.e_polygon:
|
|
shape = new b2PolygonShape();
|
|
break
|
|
}
|
|
shape._deserialize(shapeData);
|
|
shapes.push(shape)
|
|
}
|
|
var fixtures = [];
|
|
for (i = 0; i < deserialized.fixtures.length; ++i) {
|
|
var fixtureData = deserialized.fixtures[i];
|
|
var fixture = new b2FixtureDef();
|
|
fixture._deserialize(fixtureData);
|
|
fixture.shape = shapes[fixtureData.shape];
|
|
fixtures.push(fixture)
|
|
}
|
|
var bodies = [];
|
|
for (i = 0; i < deserialized.bodies.length; ++i) {
|
|
var bodyData = deserialized.bodies[i];
|
|
var def = new b2BodyDef();
|
|
def._deserialize(bodyData);
|
|
var body = world.CreateBody(def);
|
|
for (var x = 0; x < bodyData.fixtures.length; ++x) {
|
|
body.CreateFixture(fixtures[bodyData.fixtures[x]])
|
|
}
|
|
bodies.push(body)
|
|
}
|
|
var joints = [];
|
|
var gears = [];
|
|
for (i = 0; i < deserialized.joints.length; ++i) {
|
|
var jointData = deserialized.joints[i];
|
|
var jointDef;
|
|
switch (jointData.type) {
|
|
case b2Joint.e_revoluteJoint:
|
|
jointDef = new b2RevoluteJointDef();
|
|
break;
|
|
case b2Joint.e_prismaticJoint:
|
|
jointDef = new b2PrismaticJointDef();
|
|
break;
|
|
case b2Joint.e_distanceJoint:
|
|
jointDef = new b2DistanceJointDef();
|
|
break;
|
|
case b2Joint.e_pulleyJoint:
|
|
jointDef = new b2PulleyJointDef();
|
|
break;
|
|
case b2Joint.e_gearJoint:
|
|
jointDef = new b2GearJointDef();
|
|
break;
|
|
case b2Joint.e_wheelJoint:
|
|
jointDef = new b2WheelJointDef();
|
|
break;
|
|
case b2Joint.e_weldJoint:
|
|
jointDef = new b2WeldJointDef();
|
|
break;
|
|
case b2Joint.e_frictionJoint:
|
|
jointDef = new b2FrictionJointDef();
|
|
break;
|
|
case b2Joint.e_ropeJoint:
|
|
jointDef = new b2RopeJointDef();
|
|
break;
|
|
case b2Joint.e_motorJoint:
|
|
jointDef = new b2MotorJointDef();
|
|
break;
|
|
default:
|
|
throw new Error("unknown joint")
|
|
}
|
|
jointDef._deserialize(jointData, bodies);
|
|
if (jointData.type === b2Joint.e_gearJoint) {
|
|
gears.push([jointDef, joints.length]);
|
|
joints.push(null)
|
|
} else {
|
|
var joint = world.CreateJoint(jointDef);
|
|
joints.push(joint)
|
|
}
|
|
}
|
|
for (i = 0; i < gears.length; ++i) {
|
|
gears[i][0].joint1 = joints[gears[i][0].joint1];
|
|
gears[i][0].joint2 = joints[gears[i][0].joint2];
|
|
joint = world.CreateJoint(gears[i][0]);
|
|
joints[gears[i][1]] = joint
|
|
}
|
|
}
|
|
};
|
|
var b2RUBELoader = (function () {
|
|
function parseVector(obj) {
|
|
return new b2Vec2(obj ? (obj.x || 0) : 0, obj ? (obj.y || 0) : 0)
|
|
}
|
|
|
|
function parseVectorArray(obj) {
|
|
var vals = new Array(obj.x.length);
|
|
for (var i = 0; i < vals.length; ++i) {
|
|
vals[i] = new b2Vec2(obj.x[i], obj.y[i])
|
|
}
|
|
return vals
|
|
}
|
|
|
|
function parseProperty(obj, instance) {
|
|
var name = obj.name;
|
|
var val;
|
|
if (typeof (obj["int"]) !== "undefined") {
|
|
val = obj["int"]
|
|
} else {
|
|
if (typeof (obj["float"]) !== "undefined") {
|
|
val = obj["float"]
|
|
} else {
|
|
if (typeof (obj.string) !== "undefined") {
|
|
val = obj.string
|
|
} else {
|
|
if (typeof (obj.bool) !== "undefined") {
|
|
val = obj.bool
|
|
} else {
|
|
if (typeof (obj.vec2) !== "undefined") {
|
|
val = parseVector(obj.vec2)
|
|
} else {
|
|
throw new Error("unknown property type")
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if (instance.hasOwnProperty(name)) {
|
|
throw new Error("custom property possibly overwriting an existing one")
|
|
}
|
|
instance[name] = val
|
|
}
|
|
|
|
function parseFixture(obj, body) {
|
|
var def = new b2FixtureDef();
|
|
def.density = obj.density || 0;
|
|
def.filter.categoryBits = typeof (obj["filter-categoryBits"]) === "undefined" ? 1 : obj["filter-categoryBits"];
|
|
def.filter.maskBits = typeof (obj["filter-maskBits"]) === "undefined" ? 65535 : obj["filter-maskBits"];
|
|
def.filter.groupIndex = typeof (obj["filter-groupIndex"]) === "undefined" ? 0 : obj["filter-groupIndex"];
|
|
def.friction = obj.friction || 0;
|
|
def.restitution = obj.restitution || 0;
|
|
def.isSensor = obj.sensor || 0;
|
|
var shape;
|
|
if (typeof (obj.circle) !== "undefined") {
|
|
shape = new b2CircleShape();
|
|
shape.m_p = parseVector(obj.circle.center);
|
|
shape.m_radius = obj.circle.radius || 0
|
|
} else {
|
|
if (typeof (obj.polygon) !== "undefined") {
|
|
var vertices = parseVectorArray(obj.polygon.vertices);
|
|
shape = new b2PolygonShape();
|
|
shape.Set(vertices, vertices.length)
|
|
} else {
|
|
if (typeof (obj.chain) !== "undefined") {
|
|
var vertices = parseVectorArray(obj.chain.vertices);
|
|
shape = new b2ChainShape();
|
|
shape.m_count = vertices.length;
|
|
shape.m_vertices = vertices;
|
|
if (shape.m_hasNextVertex = obj.chain.hasNextVertex) {
|
|
shape.m_nextVertex = parseVector(obj.chain.nextVertex)
|
|
}
|
|
if (shape.m_hasPrevVertex = obj.chain.hasPrevVertex) {
|
|
shape.m_prevVertex = parseVector(obj.chain.prevVertex)
|
|
}
|
|
} else {
|
|
throw new Error("unknown shape type")
|
|
}
|
|
}
|
|
}
|
|
def.shape = shape;
|
|
var fixture = body.CreateFixture(def);
|
|
fixture.name = obj.name;
|
|
if (obj.customProperties) {
|
|
for (var i = 0; i < obj.customProperties.length; ++i) {
|
|
parseProperty(obj, fixture)
|
|
}
|
|
}
|
|
}
|
|
|
|
function parseBody(obj, world) {
|
|
var def = new b2BodyDef();
|
|
def.type = obj.type || b2Body.b2_staticBody;
|
|
def.angle = obj.angle || 0;
|
|
def.angularDamping = obj.angularDamping || 0;
|
|
def.angularVelocity = obj.angularVelocity || 0;
|
|
def.awake = obj.awake || false;
|
|
def.bullet = obj.bullet || false;
|
|
def.fixedRotation = obj.fixedRotation || false;
|
|
def.linearDamping = obj.linearDamping || false;
|
|
def.linearVelocity = parseVector(obj.linearVelocity);
|
|
def.gravityScale = typeof (obj.gravityScale) !== "undefined" ? obj.gravityScale : 1;
|
|
var md = new b2MassData();
|
|
md.mass = obj["massData-mass"] || 0;
|
|
md.center = parseVector(obj["massData-center"]);
|
|
md.I = obj["massData-I"] || 0;
|
|
def.position = parseVector(obj.position);
|
|
var body = world.CreateBody(def);
|
|
body.name = obj.name;
|
|
body.SetMassData(md);
|
|
if (obj.fixture) {
|
|
for (var i = 0; i < obj.fixture.length; ++i) {
|
|
parseFixture(obj.fixture[i], body)
|
|
}
|
|
}
|
|
if (obj.customProperties) {
|
|
for (i = 0; i < obj.customProperties.length; ++i) {
|
|
parseProperty(obj, body)
|
|
}
|
|
}
|
|
return body
|
|
}
|
|
var jointsList = {
|
|
revolute: b2RevoluteJointDef,
|
|
distance: b2DistanceJointDef,
|
|
prismatic: b2PrismaticJointDef,
|
|
wheel: b2WheelJointDef,
|
|
rope: b2RopeJointDef,
|
|
motor: b2MotorJointDef,
|
|
weld: b2WeldJointDef,
|
|
friction: b2FrictionJointDef
|
|
};
|
|
|
|
function parseJoint(obj, world, bodies) {
|
|
if (!jointsList[obj.type]) {
|
|
throw new Error("unknown joint type")
|
|
}
|
|
var jd = new jointsList[obj.type]();
|
|
switch (jd.type) {
|
|
case b2Joint.e_revoluteJoint:
|
|
jd.localAnchorA = parseVector(obj.anchorA);
|
|
jd.localAnchorB = parseVector(obj.anchorB);
|
|
jd.enableLimit = obj.enableLimit || false;
|
|
jd.enableMotor = obj.enableMotor || false;
|
|
jd.lowerAngle = obj.lowerLimit || 0;
|
|
jd.maxMotorTorque = obj.maxMotorTorque || 0;
|
|
jd.motorSpeed = obj.motorSpeed || 0;
|
|
jd.referenceAngle = obj.refAngle || 0;
|
|
jd.upperAngle = obj.upperLimit || 0;
|
|
break;
|
|
case b2Joint.e_distanceJoint:
|
|
jd.localAnchorA = parseVector(obj.anchorA);
|
|
jd.localAnchorB = parseVector(obj.anchorB);
|
|
jd.dampingRatio = obj.dampingRatio || 0;
|
|
jd.frequencyHz = obj.frequency || 0;
|
|
jd.length = obj.length || 0;
|
|
break;
|
|
case b2Joint.e_prismaticJoint:
|
|
jd.localAnchorA = parseVector(obj.anchorA);
|
|
jd.localAnchorB = parseVector(obj.anchorB);
|
|
jd.enableLimit = obj.enableLimit || false;
|
|
jd.enableMotor = obj.enableMotor || false;
|
|
jd.localAxisA = parseVector(obj.localAxisA);
|
|
jd.lowerTranslation = obj.lowerLimit || 0;
|
|
jd.maxMotorForce = obj.maxMotorForce || 0;
|
|
jd.motorSpeed = obj.motorSpeed || 0;
|
|
jd.referenceAngle = obj.refAngle || 0;
|
|
jd.upperTranslation = obj.upperLimit || 0;
|
|
break;
|
|
case b2Joint.e_wheelJoint:
|
|
jd.localAnchorA = parseVector(obj.anchorA);
|
|
jd.localAnchorB = parseVector(obj.anchorB);
|
|
jd.enableMotor = obj.enableMotor || false;
|
|
jd.localAxisA = parseVector(obj.localAxisA);
|
|
jd.maxMotorTorque = obj.maxMotorTorque || 0;
|
|
jd.motorSpeed = obj.motorSpeed || 0;
|
|
jd.dampingRatio = obj.springDampingRatio || 0;
|
|
jd.frequencyHz = obj.springFrequency || 0;
|
|
break;
|
|
case b2Joint.e_ropeJoint:
|
|
jd.localAnchorA = parseVector(obj.anchorA);
|
|
jd.localAnchorB = parseVector(obj.anchorB);
|
|
jd.maxLength = obj.maxLength || 0;
|
|
break;
|
|
case b2Joint.e_motorJoint:
|
|
jd.linearOffset = parseVector(obj.anchorA);
|
|
jd.angularOffset = obj.refAngle || 0;
|
|
jd.maxForce = obj.maxForce || 0;
|
|
jd.maxTorque = obj.maxTorque || 0;
|
|
jd.correctionFactor = obj.correctionFactor || 0;
|
|
break;
|
|
case b2Joint.e_weldJoint:
|
|
jd.localAnchorA = parseVector(obj.anchorA);
|
|
jd.localAnchorB = parseVector(obj.anchorB);
|
|
jd.referenceAngle = obj.refAngle || 0;
|
|
jd.dampingRatio = obj.dampingRatio || 0;
|
|
jd.frequencyHz = obj.frequencyHz || 0;
|
|
break;
|
|
case b2Joint.e_frictionJoint:
|
|
jd.localAnchorA = parseVector(obj.anchorA);
|
|
jd.localAnchorB = parseVector(obj.anchorB);
|
|
jd.maxForce = obj.maxForce || 0;
|
|
jd.maxTorque = obj.maxTorque || 0;
|
|
break;
|
|
default:
|
|
throw new Error("wat?")
|
|
}
|
|
jd.bodyA = bodies[obj.bodyA || 0];
|
|
jd.bodyB = bodies[obj.bodyB || 0];
|
|
jd.collideConnected = obj.collideConnected || false;
|
|
var joint = world.CreateJoint(jd);
|
|
joint.name = obj.name;
|
|
if (obj.customProperties) {
|
|
for (var i = 0; i < obj.customProperties.length; ++i) {
|
|
parseProperty(obj, joint)
|
|
}
|
|
}
|
|
return joint
|
|
}
|
|
|
|
function b2RubeParameters() {
|
|
this.world = null;
|
|
this.positionIterations = 0;
|
|
this.velocityIterations = 0;
|
|
this.stepsPerSecond = 0;
|
|
this.fixtures = {};
|
|
this.bodies = {};
|
|
this.joints = {};
|
|
Object.seal(this)
|
|
}
|
|
|
|
function parseWorld(obj, world) {
|
|
var params = new b2RubeParameters();
|
|
params.world = world = world || new b2World(new b2Vec2(0, 0));
|
|
params.positionIterations = obj.positionIterations || 0;
|
|
params.velocityIterations = obj.velocityIterations || 0;
|
|
params.stepsPerSecond = obj.stepsPerSecond || 0;
|
|
if (obj.gravity) {
|
|
world.SetGravity(parseVector(obj.gravity))
|
|
}
|
|
world.SetAllowSleeping(obj.allowSleep || false);
|
|
world.SetAutoClearForces(obj.autoClearForces || false);
|
|
world.SetWarmStarting(obj.warmStarting || false);
|
|
world.SetContinuousPhysics(obj.continuousPhysics || false);
|
|
world.SetSubStepping(obj.subStepping || false);
|
|
var bodies = [];
|
|
var bl = obj.body;
|
|
if (bl) {
|
|
for (var i = 0; i < bl.length; ++i) {
|
|
var body = parseBody(bl[i], world);
|
|
bodies.push(body);
|
|
for (var f = body.GetFixtureList(); f; f = f.GetNext()) {
|
|
if (!params.fixtures[f.name]) {
|
|
params.fixtures[f.name] = []
|
|
}
|
|
params.fixtures[f.name].push(f)
|
|
}
|
|
if (!params.bodies[body.name]) {
|
|
params.bodies[body.name] = []
|
|
}
|
|
params.bodies[body.name].push(body)
|
|
}
|
|
}
|
|
var joints = [];
|
|
var jl = obj.joint;
|
|
if (jl) {
|
|
for (i = 0; i < jl.length; ++i) {
|
|
var joint = parseJoint(jl[i], world, bodies);
|
|
joints.push(joint);
|
|
if (!params.joints[joint.name]) {
|
|
params.joints[joint.name] = []
|
|
}
|
|
params.joints[joint.name].push(joint)
|
|
}
|
|
}
|
|
return params
|
|
}
|
|
return {
|
|
parseWorld: parseWorld
|
|
}
|
|
})();
|
|
var mappings = [{
|
|
trimmed: "version",
|
|
name: "b2_version",
|
|
def: b2_version
|
|
}, {
|
|
trimmed: "Vec2",
|
|
name: "b2Vec2",
|
|
def: b2Vec2
|
|
}, {
|
|
trimmed: "Vec3",
|
|
name: "b2Vec3",
|
|
def: b2Vec3
|
|
}, {
|
|
trimmed: "Mat22",
|
|
name: "b2Mat22",
|
|
def: b2Mat22
|
|
}, {
|
|
trimmed: "Mat33",
|
|
name: "b2Mat33",
|
|
def: b2Mat33
|
|
}, {
|
|
trimmed: "Rot",
|
|
name: "b2Rot",
|
|
def: b2Rot
|
|
}, {
|
|
trimmed: "Transform",
|
|
name: "b2Transform",
|
|
def: b2Transform
|
|
}, {
|
|
trimmed: "Sweep",
|
|
name: "b2Sweep",
|
|
def: b2Sweep
|
|
}, {
|
|
trimmed: "Dot_v2_v2",
|
|
name: "b2Dot_v2_v2",
|
|
def: b2Dot_v2_v2
|
|
}, {
|
|
trimmed: "Cross_v2_v2",
|
|
name: "b2Cross_v2_v2",
|
|
def: b2Cross_v2_v2
|
|
}, {
|
|
trimmed: "Cross_v2_f",
|
|
name: "b2Cross_v2_f",
|
|
def: b2Cross_v2_f
|
|
}, {
|
|
trimmed: "Cross_f_v2",
|
|
name: "b2Cross_f_v2",
|
|
def: b2Cross_f_v2
|
|
}, {
|
|
trimmed: "Mul_m22_v2",
|
|
name: "b2Mul_m22_v2",
|
|
def: b2Mul_m22_v2
|
|
}, {
|
|
trimmed: "MulT_m22_v2",
|
|
name: "b2MulT_m22_v2",
|
|
def: b2MulT_m22_v2
|
|
}, {
|
|
trimmed: "Distance",
|
|
name: "b2Distance",
|
|
def: b2Distance
|
|
}, {
|
|
trimmed: "DistanceSquared",
|
|
name: "b2DistanceSquared",
|
|
def: b2DistanceSquared
|
|
}, {
|
|
trimmed: "Dot_v3_v3",
|
|
name: "b2Dot_v3_v3",
|
|
def: b2Dot_v3_v3
|
|
}, {
|
|
trimmed: "Cross_v3_v3",
|
|
name: "b2Cross_v3_v3",
|
|
def: b2Cross_v3_v3
|
|
}, {
|
|
trimmed: "Mul_m22_m22",
|
|
name: "b2Mul_m22_m22",
|
|
def: b2Mul_m22_m22
|
|
}, {
|
|
trimmed: "MulT_m22_m22",
|
|
name: "b2MulT_m22_m22",
|
|
def: b2MulT_m22_m22
|
|
}, {
|
|
trimmed: "Mul_m33_v3",
|
|
name: "b2Mul_m33_v3",
|
|
def: b2Mul_m33_v3
|
|
}, {
|
|
trimmed: "Mul22_m33_v2",
|
|
name: "b2Mul22_m33_v2",
|
|
def: b2Mul22_m33_v2
|
|
}, {
|
|
trimmed: "Mul_r_r",
|
|
name: "b2Mul_r_r",
|
|
def: b2Mul_r_r
|
|
}, {
|
|
trimmed: "MulT_r_r",
|
|
name: "b2MulT_r_r",
|
|
def: b2MulT_r_r
|
|
}, {
|
|
trimmed: "Mul_r_v2",
|
|
name: "b2Mul_r_v2",
|
|
def: b2Mul_r_v2
|
|
}, {
|
|
trimmed: "MulT_r_v2",
|
|
name: "b2MulT_r_v2",
|
|
def: b2MulT_r_v2
|
|
}, {
|
|
trimmed: "Mul_t_v2",
|
|
name: "b2Mul_t_v2",
|
|
def: b2Mul_t_v2
|
|
}, {
|
|
trimmed: "Min_v2",
|
|
name: "b2Min_v2",
|
|
def: b2Min_v2
|
|
}, {
|
|
trimmed: "Max_v2",
|
|
name: "b2Max_v2",
|
|
def: b2Max_v2
|
|
}, {
|
|
trimmed: "Clamp",
|
|
name: "b2Clamp",
|
|
def: b2Clamp
|
|
}, {
|
|
trimmed: "MulT_t_v2",
|
|
name: "b2MulT_t_v2",
|
|
def: b2MulT_t_v2
|
|
}, {
|
|
trimmed: "Mul_t_t",
|
|
name: "b2Mul_t_t",
|
|
def: b2Mul_t_t
|
|
}, {
|
|
trimmed: "MulT_t_t",
|
|
name: "b2MulT_t_t",
|
|
def: b2MulT_t_t
|
|
}, {
|
|
trimmed: "Clamp_v2",
|
|
name: "b2Clamp_v2",
|
|
def: b2Clamp_v2
|
|
}, {
|
|
trimmed: "NextPowerOfTwo",
|
|
name: "b2NextPowerOfTwo",
|
|
def: b2NextPowerOfTwo
|
|
}, {
|
|
trimmed: "Abs_v2",
|
|
name: "b2Abs_v2",
|
|
def: b2Abs_v2
|
|
}, {
|
|
trimmed: "Abs_m22",
|
|
name: "b2Abs_m22",
|
|
def: b2Abs_m22
|
|
}, {
|
|
trimmed: "IsPowerOfTwo",
|
|
name: "b2IsPowerOfTwo",
|
|
def: b2IsPowerOfTwo
|
|
}, {
|
|
trimmed: "RandomFloat",
|
|
name: "b2RandomFloat",
|
|
def: b2RandomFloat
|
|
}, {
|
|
trimmed: "Timer",
|
|
name: "b2Timer",
|
|
def: b2Timer
|
|
}, {
|
|
trimmed: "Color",
|
|
name: "b2Color",
|
|
def: b2Color
|
|
}, {
|
|
trimmed: "Draw",
|
|
name: "b2Draw",
|
|
def: b2Draw
|
|
}, {
|
|
trimmed: "ContactID",
|
|
name: "b2ContactID",
|
|
def: b2ContactID
|
|
}, {
|
|
trimmed: "ManifoldPoint",
|
|
name: "b2ManifoldPoint",
|
|
def: b2ManifoldPoint
|
|
}, {
|
|
trimmed: "Manifold",
|
|
name: "b2Manifold",
|
|
def: b2Manifold
|
|
}, {
|
|
trimmed: "WorldManifold",
|
|
name: "b2WorldManifold",
|
|
def: b2WorldManifold
|
|
}, {
|
|
trimmed: "GetPointStates",
|
|
name: "b2GetPointStates",
|
|
def: b2GetPointStates
|
|
}, {
|
|
trimmed: "ClipVertex",
|
|
name: "b2ClipVertex",
|
|
def: b2ClipVertex
|
|
}, {
|
|
trimmed: "RayCastInput",
|
|
name: "b2RayCastInput",
|
|
def: b2RayCastInput
|
|
}, {
|
|
trimmed: "RayCastOutput",
|
|
name: "b2RayCastOutput",
|
|
def: b2RayCastOutput
|
|
}, {
|
|
trimmed: "AABB",
|
|
name: "b2AABB",
|
|
def: b2AABB
|
|
}, {
|
|
trimmed: "CollideCircles",
|
|
name: "b2CollideCircles",
|
|
def: b2CollideCircles
|
|
}, {
|
|
trimmed: "CollidePolygonAndCircle",
|
|
name: "b2CollidePolygonAndCircle",
|
|
def: b2CollidePolygonAndCircle
|
|
}, {
|
|
trimmed: "FindMaxSeparation",
|
|
name: "b2FindMaxSeparation",
|
|
def: b2FindMaxSeparation
|
|
}, {
|
|
trimmed: "FindIncidentEdge",
|
|
name: "b2FindIncidentEdge",
|
|
def: b2FindIncidentEdge
|
|
}, {
|
|
trimmed: "CollidePolygons",
|
|
name: "b2CollidePolygons",
|
|
def: b2CollidePolygons
|
|
}, {
|
|
trimmed: "CollideEdgeAndCircle",
|
|
name: "b2CollideEdgeAndCircle",
|
|
def: b2CollideEdgeAndCircle
|
|
}, {
|
|
trimmed: "EPAxis",
|
|
name: "b2EPAxis",
|
|
def: b2EPAxis
|
|
}, {
|
|
trimmed: "TempPolygon",
|
|
name: "b2TempPolygon",
|
|
def: b2TempPolygon
|
|
}, {
|
|
trimmed: "ReferenceFace",
|
|
name: "b2ReferenceFace",
|
|
def: b2ReferenceFace
|
|
}, {
|
|
trimmed: "EPCollider",
|
|
name: "b2EPCollider",
|
|
def: b2EPCollider
|
|
}, {
|
|
trimmed: "CollideEdgeAndPolygon",
|
|
name: "b2CollideEdgeAndPolygon",
|
|
def: b2CollideEdgeAndPolygon
|
|
}, {
|
|
trimmed: "ClipSegmentToLine",
|
|
name: "b2ClipSegmentToLine",
|
|
def: b2ClipSegmentToLine
|
|
}, {
|
|
trimmed: "TestShapeOverlap",
|
|
name: "b2TestShapeOverlap",
|
|
def: b2TestShapeOverlap
|
|
}, {
|
|
trimmed: "TestOverlap",
|
|
name: "b2TestOverlap",
|
|
def: b2TestOverlap
|
|
}, {
|
|
trimmed: "Shape",
|
|
name: "b2Shape",
|
|
def: b2Shape
|
|
}, {
|
|
trimmed: "CircleShape",
|
|
name: "b2CircleShape",
|
|
def: b2CircleShape
|
|
}, {
|
|
trimmed: "EdgeShape",
|
|
name: "b2EdgeShape",
|
|
def: b2EdgeShape
|
|
}, {
|
|
trimmed: "ChainShape",
|
|
name: "b2ChainShape",
|
|
def: b2ChainShape
|
|
}, {
|
|
trimmed: "PolygonShape",
|
|
name: "b2PolygonShape",
|
|
def: b2PolygonShape
|
|
}, {
|
|
trimmed: "Pair",
|
|
name: "b2Pair",
|
|
def: b2Pair
|
|
}, {
|
|
trimmed: "PairLessThan",
|
|
name: "b2PairLessThan",
|
|
def: b2PairLessThan
|
|
}, {
|
|
trimmed: "BroadPhase",
|
|
name: "b2BroadPhase",
|
|
def: b2BroadPhase
|
|
}, {
|
|
trimmed: "DistanceProxy",
|
|
name: "b2DistanceProxy",
|
|
def: b2DistanceProxy
|
|
}, {
|
|
trimmed: "SimplexCache",
|
|
name: "b2SimplexCache",
|
|
def: b2SimplexCache
|
|
}, {
|
|
trimmed: "DistanceInput",
|
|
name: "b2DistanceInput",
|
|
def: b2DistanceInput
|
|
}, {
|
|
trimmed: "DistanceOutput",
|
|
name: "b2DistanceOutput",
|
|
def: b2DistanceOutput
|
|
}, {
|
|
trimmed: "SimplexVertex",
|
|
name: "b2SimplexVertex",
|
|
def: b2SimplexVertex
|
|
}, {
|
|
trimmed: "Simplex",
|
|
name: "b2Simplex",
|
|
def: b2Simplex
|
|
}, {
|
|
trimmed: "DistanceFunc",
|
|
name: "b2DistanceFunc",
|
|
def: b2DistanceFunc
|
|
}, {
|
|
trimmed: "TreeNode",
|
|
name: "b2TreeNode",
|
|
def: b2TreeNode
|
|
}, {
|
|
trimmed: "DynamicTree",
|
|
name: "b2DynamicTree",
|
|
def: b2DynamicTree
|
|
}, {
|
|
trimmed: "TOIInput",
|
|
name: "b2TOIInput",
|
|
def: b2TOIInput
|
|
}, {
|
|
trimmed: "TOIOutput",
|
|
name: "b2TOIOutput",
|
|
def: b2TOIOutput
|
|
}, {
|
|
trimmed: "SeparationFunction",
|
|
name: "b2SeparationFunction",
|
|
def: b2SeparationFunction
|
|
}, {
|
|
trimmed: "TimeOfImpact",
|
|
name: "b2TimeOfImpact",
|
|
def: b2TimeOfImpact
|
|
}, {
|
|
trimmed: "BodyDef",
|
|
name: "b2BodyDef",
|
|
def: b2BodyDef
|
|
}, {
|
|
trimmed: "Body",
|
|
name: "b2Body",
|
|
def: b2Body
|
|
}, {
|
|
trimmed: "Filter",
|
|
name: "b2Filter",
|
|
def: b2Filter
|
|
}, {
|
|
trimmed: "FixtureDef",
|
|
name: "b2FixtureDef",
|
|
def: b2FixtureDef
|
|
}, {
|
|
trimmed: "Fixture",
|
|
name: "b2Fixture",
|
|
def: b2Fixture
|
|
}, {
|
|
trimmed: "DestructionListener",
|
|
name: "b2DestructionListener",
|
|
def: b2DestructionListener
|
|
}, {
|
|
trimmed: "ContactFilter",
|
|
name: "b2ContactFilter",
|
|
def: b2ContactFilter
|
|
}, {
|
|
trimmed: "ContactImpulse",
|
|
name: "b2ContactImpulse",
|
|
def: b2ContactImpulse
|
|
}, {
|
|
trimmed: "ContactListener",
|
|
name: "b2ContactListener",
|
|
def: b2ContactListener
|
|
}, {
|
|
trimmed: "QueryCallback",
|
|
name: "b2QueryCallback",
|
|
def: b2QueryCallback
|
|
}, {
|
|
trimmed: "RayCastCallback",
|
|
name: "b2RayCastCallback",
|
|
def: b2RayCastCallback
|
|
}, {
|
|
trimmed: "TimeStep",
|
|
name: "b2TimeStep",
|
|
def: b2TimeStep
|
|
}, {
|
|
trimmed: "Position",
|
|
name: "b2Position",
|
|
def: b2Position
|
|
}, {
|
|
trimmed: "Velocity",
|
|
name: "b2Velocity",
|
|
def: b2Velocity
|
|
}, {
|
|
trimmed: "SolverData",
|
|
name: "b2SolverData",
|
|
def: b2SolverData
|
|
}, {
|
|
trimmed: "World",
|
|
name: "b2World",
|
|
def: b2World
|
|
}, {
|
|
trimmed: "MixFriction",
|
|
name: "b2MixFriction",
|
|
def: b2MixFriction
|
|
}, {
|
|
trimmed: "MixRestitution",
|
|
name: "b2MixRestitution",
|
|
def: b2MixRestitution
|
|
}, {
|
|
trimmed: "ContactRegister",
|
|
name: "b2ContactRegister",
|
|
def: b2ContactRegister
|
|
}, {
|
|
trimmed: "ContactEdge",
|
|
name: "b2ContactEdge",
|
|
def: b2ContactEdge
|
|
}, {
|
|
trimmed: "Contact",
|
|
name: "b2Contact",
|
|
def: b2Contact
|
|
}, {
|
|
trimmed: "CircleContact",
|
|
name: "b2CircleContact",
|
|
def: b2CircleContact
|
|
}, {
|
|
trimmed: "PolygonContact",
|
|
name: "b2PolygonContact",
|
|
def: b2PolygonContact
|
|
}, {
|
|
trimmed: "ChainAndCircleContact",
|
|
name: "b2ChainAndCircleContact",
|
|
def: b2ChainAndCircleContact
|
|
}, {
|
|
trimmed: "ChainAndPolygonContact",
|
|
name: "b2ChainAndPolygonContact",
|
|
def: b2ChainAndPolygonContact
|
|
}, {
|
|
trimmed: "EdgeAndCircleContact",
|
|
name: "b2EdgeAndCircleContact",
|
|
def: b2EdgeAndCircleContact
|
|
}, {
|
|
trimmed: "EdgeAndPolygonContact",
|
|
name: "b2EdgeAndPolygonContact",
|
|
def: b2EdgeAndPolygonContact
|
|
}, {
|
|
trimmed: "PolygonAndCircleContact",
|
|
name: "b2PolygonAndCircleContact",
|
|
def: b2PolygonAndCircleContact
|
|
}, {
|
|
trimmed: "defaultFilter",
|
|
name: "b2_defaultFilter",
|
|
def: b2_defaultFilter
|
|
}, {
|
|
trimmed: "defaultListener",
|
|
name: "b2_defaultListener",
|
|
def: b2_defaultListener
|
|
}, {
|
|
trimmed: "ContactManager",
|
|
name: "b2ContactManager",
|
|
def: b2ContactManager
|
|
}, {
|
|
trimmed: "VelocityConstraintPoint",
|
|
name: "b2VelocityConstraintPoint",
|
|
def: b2VelocityConstraintPoint
|
|
}, {
|
|
trimmed: "ContactPositionConstraint",
|
|
name: "b2ContactPositionConstraint",
|
|
def: b2ContactPositionConstraint
|
|
}, {
|
|
trimmed: "ContactVelocityConstraint",
|
|
name: "b2ContactVelocityConstraint",
|
|
def: b2ContactVelocityConstraint
|
|
}, {
|
|
trimmed: "PositionSolverManifold",
|
|
name: "b2PositionSolverManifold",
|
|
def: b2PositionSolverManifold
|
|
}, {
|
|
trimmed: "ContactSolverDef",
|
|
name: "b2ContactSolverDef",
|
|
def: b2ContactSolverDef
|
|
}, {
|
|
trimmed: "ContactSolver",
|
|
name: "b2ContactSolver",
|
|
def: b2ContactSolver
|
|
}, {
|
|
trimmed: "Island",
|
|
name: "b2Island",
|
|
def: b2Island
|
|
}, {
|
|
trimmed: "Jacobian",
|
|
name: "b2Jacobian",
|
|
def: b2Jacobian
|
|
}, {
|
|
trimmed: "JointEdge",
|
|
name: "b2JointEdge",
|
|
def: b2JointEdge
|
|
}, {
|
|
trimmed: "JointDef",
|
|
name: "b2JointDef",
|
|
def: b2JointDef
|
|
}, {
|
|
trimmed: "Joint",
|
|
name: "b2Joint",
|
|
def: b2Joint
|
|
}, {
|
|
trimmed: "RevoluteJointDef",
|
|
name: "b2RevoluteJointDef",
|
|
def: b2RevoluteJointDef
|
|
}, {
|
|
trimmed: "RevoluteJoint",
|
|
name: "b2RevoluteJoint",
|
|
def: b2RevoluteJoint
|
|
}, {
|
|
trimmed: "MouseJointDef",
|
|
name: "b2MouseJointDef",
|
|
def: b2MouseJointDef
|
|
}, {
|
|
trimmed: "MouseJoint",
|
|
name: "b2MouseJoint",
|
|
def: b2MouseJoint
|
|
}, {
|
|
trimmed: "DistanceJointDef",
|
|
name: "b2DistanceJointDef",
|
|
def: b2DistanceJointDef
|
|
}, {
|
|
trimmed: "DistanceJoint",
|
|
name: "b2DistanceJoint",
|
|
def: b2DistanceJoint
|
|
}, {
|
|
trimmed: "PrismaticJointDef",
|
|
name: "b2PrismaticJointDef",
|
|
def: b2PrismaticJointDef
|
|
}, {
|
|
trimmed: "PrismaticJoint",
|
|
name: "b2PrismaticJoint",
|
|
def: b2PrismaticJoint
|
|
}, {
|
|
trimmed: "FrictionJointDef",
|
|
name: "b2FrictionJointDef",
|
|
def: b2FrictionJointDef
|
|
}, {
|
|
trimmed: "FrictionJoint",
|
|
name: "b2FrictionJoint",
|
|
def: b2FrictionJoint
|
|
}, {
|
|
trimmed: "WeldJointDef",
|
|
name: "b2WeldJointDef",
|
|
def: b2WeldJointDef
|
|
}, {
|
|
trimmed: "WeldJoint",
|
|
name: "b2WeldJoint",
|
|
def: b2WeldJoint
|
|
}, {
|
|
trimmed: "WheelJointDef",
|
|
name: "b2WheelJointDef",
|
|
def: b2WheelJointDef
|
|
}, {
|
|
trimmed: "WheelJoint",
|
|
name: "b2WheelJoint",
|
|
def: b2WheelJoint
|
|
}, {
|
|
trimmed: "GearJointDef",
|
|
name: "b2GearJointDef",
|
|
def: b2GearJointDef
|
|
}, {
|
|
trimmed: "GearJoint",
|
|
name: "b2GearJoint",
|
|
def: b2GearJoint
|
|
}, {
|
|
trimmed: "MotorJointDef",
|
|
name: "b2MotorJointDef",
|
|
def: b2MotorJointDef
|
|
}, {
|
|
trimmed: "MotorJoint",
|
|
name: "b2MotorJoint",
|
|
def: b2MotorJoint
|
|
}, {
|
|
trimmed: "PulleyJointDef",
|
|
name: "b2PulleyJointDef",
|
|
def: b2PulleyJointDef
|
|
}, {
|
|
trimmed: "PulleyJoint",
|
|
name: "b2PulleyJoint",
|
|
def: b2PulleyJoint
|
|
}, {
|
|
trimmed: "RopeJointDef",
|
|
name: "b2RopeJointDef",
|
|
def: b2RopeJointDef
|
|
}, {
|
|
trimmed: "RopeJoint",
|
|
name: "b2RopeJoint",
|
|
def: b2RopeJoint
|
|
}, {
|
|
trimmed: "RopeDef",
|
|
name: "b2RopeDef",
|
|
def: b2RopeDef
|
|
}, {
|
|
trimmed: "Rope",
|
|
name: "b2Rope",
|
|
def: b2Rope
|
|
}, {
|
|
trimmed: "maxManifoldPoints",
|
|
name: "b2_maxManifoldPoints",
|
|
def: b2_maxManifoldPoints
|
|
}, {
|
|
trimmed: "maxPolygonVertices",
|
|
name: "b2_maxPolygonVertices",
|
|
def: b2_maxPolygonVertices
|
|
}, {
|
|
trimmed: "aabbExtension",
|
|
name: "b2_aabbExtension",
|
|
def: b2_aabbExtension
|
|
}, {
|
|
trimmed: "aabbMultiplier",
|
|
name: "b2_aabbMultiplier",
|
|
def: b2_aabbMultiplier
|
|
}, {
|
|
trimmed: "linearSlop",
|
|
name: "b2_linearSlop",
|
|
def: b2_linearSlop
|
|
}, {
|
|
trimmed: "angularSlop",
|
|
name: "b2_angularSlop",
|
|
def: b2_angularSlop
|
|
}, {
|
|
trimmed: "polygonRadius",
|
|
name: "b2_polygonRadius",
|
|
def: b2_polygonRadius
|
|
}, {
|
|
trimmed: "maxSubSteps",
|
|
name: "b2_maxSubSteps",
|
|
def: b2_maxSubSteps
|
|
}, {
|
|
trimmed: "maxTOIContacts",
|
|
name: "b2_maxTOIContacts",
|
|
def: b2_maxTOIContacts
|
|
}, {
|
|
trimmed: "velocityThreshold",
|
|
name: "b2_velocityThreshold",
|
|
def: b2_velocityThreshold
|
|
}, {
|
|
trimmed: "maxLinearCorrection",
|
|
name: "b2_maxLinearCorrection",
|
|
def: b2_maxLinearCorrection
|
|
}, {
|
|
trimmed: "maxAngularCorrection",
|
|
name: "b2_maxAngularCorrection",
|
|
def: b2_maxAngularCorrection
|
|
}, {
|
|
trimmed: "maxTranslation",
|
|
name: "b2_maxTranslation",
|
|
def: b2_maxTranslation
|
|
}, {
|
|
trimmed: "maxTranslationSquared",
|
|
name: "b2_maxTranslationSquared",
|
|
def: b2_maxTranslationSquared
|
|
}, {
|
|
trimmed: "maxRotation",
|
|
name: "b2_maxRotation",
|
|
def: b2_maxRotation
|
|
}, {
|
|
trimmed: "maxRotationSquared",
|
|
name: "b2_maxRotationSquared",
|
|
def: b2_maxRotationSquared
|
|
}, {
|
|
trimmed: "baumgarte",
|
|
name: "b2_baumgarte",
|
|
def: b2_baumgarte
|
|
}, {
|
|
trimmed: "toiBaugarte",
|
|
name: "b2_toiBaugarte",
|
|
def: b2_toiBaugarte
|
|
}, {
|
|
trimmed: "timeToSleep",
|
|
name: "b2_timeToSleep",
|
|
def: b2_timeToSleep
|
|
}, {
|
|
trimmed: "linearSleepTolerance",
|
|
name: "b2_linearSleepTolerance",
|
|
def: b2_linearSleepTolerance
|
|
}, {
|
|
trimmed: "angularSleepTolerance",
|
|
name: "b2_angularSleepTolerance",
|
|
def: b2_angularSleepTolerance
|
|
}, {
|
|
trimmed: "epsilon",
|
|
name: "b2_epsilon",
|
|
def: b2_epsilon
|
|
}, {
|
|
trimmed: "JsonSerializer",
|
|
name: "b2JsonSerializer",
|
|
def: b2JsonSerializer
|
|
}, {
|
|
trimmed: "RUBELoader",
|
|
name: "b2RUBELoader",
|
|
def: b2RUBELoader
|
|
}, {
|
|
trimmed: "Profiler",
|
|
name: "b2Profiler",
|
|
def: b2Profiler
|
|
}];
|
|
|
|
|
|
if (typeof (b2_compatibility) !== "undefined" && typeof (window) !== "undefined") {
|
|
for (var i = 0; i < mappings.length; ++i) {
|
|
window[mappings[i].name] = mappings[i].def
|
|
}
|
|
} else {
|
|
var b2 = {};
|
|
for (var i = 0; i < mappings.length; ++i) {
|
|
b2[mappings[i].trimmed] = mappings[i].def
|
|
}
|
|
if (typeof (module) !== "undefined") {
|
|
module.exports = b2
|
|
} else {
|
|
window.b2 = b2
|
|
}
|
|
}
|
|
})();
|