/** https://github.com/kripken/box2d.js v2.3.1 */ 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 } }