UNPKG

the-world-engine

Version:

three.js based, unity like game engine for browser

280 lines (264 loc) 10.2 kB
import { b2_maxFloat, b2_timeToSleep } from "../common/b2_settings.js"; import { b2_maxTranslation, b2_maxTranslationSquared } from "../common/b2_settings.js"; import { b2_maxRotation, b2_maxRotationSquared } from "../common/b2_settings.js"; import { b2_linearSleepTolerance, b2_angularSleepTolerance } from "../common/b2_settings.js"; import { b2Abs, b2Min, b2Max, b2Vec2 } from "../common/b2_math.js"; import { b2Timer } from "../common/b2_timer.js"; import { b2ContactSolver, b2ContactSolverDef } from "./b2_contact_solver.js"; import { b2BodyType } from "./b2_body.js"; import { b2SolverData, b2Position, b2Velocity } from "./b2_time_step.js"; import { b2ContactImpulse } from "./b2_world_callbacks.js"; export class b2Island { constructor() { this.m_bodies = []; this.m_contacts = []; this.m_joints = []; this.m_positions = b2Position.MakeArray(1024); this.m_velocities = b2Velocity.MakeArray(1024); this.m_bodyCount = 0; this.m_jointCount = 0; this.m_contactCount = 0; this.m_bodyCapacity = 0; this.m_contactCapacity = 0; this.m_jointCapacity = 0; } Initialize(t, s, i, o) { this.m_bodyCapacity = t; this.m_contactCapacity = s; this.m_jointCapacity = i; this.m_bodyCount = 0; this.m_contactCount = 0; this.m_jointCount = 0; this.m_listener = o; if (this.m_positions.length < t) { const s = b2Max(this.m_positions.length * 2, t); while (this.m_positions.length < s) { this.m_positions[this.m_positions.length] = new b2Position; } } if (this.m_velocities.length < t) { const s = b2Max(this.m_velocities.length * 2, t); while (this.m_velocities.length < s) { this.m_velocities[this.m_velocities.length] = new b2Velocity; } } } Clear() { this.m_bodyCount = 0; this.m_contactCount = 0; this.m_jointCount = 0; } AddBody(t) { t.m_islandIndex = this.m_bodyCount; this.m_bodies[this.m_bodyCount++] = t; } AddContact(t) { this.m_contacts[this.m_contactCount++] = t; } AddJoint(t) { this.m_joints[this.m_jointCount++] = t; } Solve(t, s, i, o) { const n = b2Island.s_timer.Reset(); const e = s.dt; for (let t = 0; t < this.m_bodyCount; ++t) { const s = this.m_bodies[t]; this.m_positions[t].c.Copy(s.m_sweep.c); const o = s.m_sweep.a; const n = this.m_velocities[t].v.Copy(s.m_linearVelocity); let h = s.m_angularVelocity; s.m_sweep.c0.Copy(s.m_sweep.c); s.m_sweep.a0 = s.m_sweep.a; if (s.m_type === b2BodyType.b2_dynamicBody) { n.x += e * s.m_invMass * (s.m_gravityScale * s.m_mass * i.x + s.m_force.x); n.y += e * s.m_invMass * (s.m_gravityScale * s.m_mass * i.y + s.m_force.y); h += e * s.m_invI * s.m_torque; n.SelfMul(1 / (1 + e * s.m_linearDamping)); h *= 1 / (1 + e * s.m_angularDamping); } this.m_positions[t].a = o; this.m_velocities[t].w = h; } n.Reset(); const h = b2Island.s_solverData; h.step.Copy(s); h.positions = this.m_positions; h.velocities = this.m_velocities; const a = b2Island.s_contactSolverDef; a.step.Copy(s); a.contacts = this.m_contacts; a.count = this.m_contactCount; a.positions = this.m_positions; a.velocities = this.m_velocities; const l = b2Island.s_contactSolver.Initialize(a); l.InitializeVelocityConstraints(); if (s.warmStarting) { l.WarmStart(); } for (let t = 0; t < this.m_jointCount; ++t) { this.m_joints[t].InitVelocityConstraints(h); } t.solveInit = n.GetMilliseconds(); n.Reset(); for (let t = 0; t < s.velocityIterations; ++t) { for (let t = 0; t < this.m_jointCount; ++t) { this.m_joints[t].SolveVelocityConstraints(h); } l.SolveVelocityConstraints(); } l.StoreImpulses(); t.solveVelocity = n.GetMilliseconds(); for (let t = 0; t < this.m_bodyCount; ++t) { const s = this.m_positions[t].c; let i = this.m_positions[t].a; const o = this.m_velocities[t].v; let n = this.m_velocities[t].w; const h = b2Vec2.MulSV(e, o, b2Island.s_translation); if (b2Vec2.DotVV(h, h) > b2_maxTranslationSquared) { const t = b2_maxTranslation / h.Length(); o.SelfMul(t); } const a = e * n; if (a * a > b2_maxRotationSquared) { const t = b2_maxRotation / b2Abs(a); n *= t; } s.x += e * o.x; s.y += e * o.y; i += e * n; this.m_positions[t].a = i; this.m_velocities[t].w = n; } n.Reset(); let b = false; for (let t = 0; t < s.positionIterations; ++t) { const t = l.SolvePositionConstraints(); let s = true; for (let t = 0; t < this.m_jointCount; ++t) { const i = this.m_joints[t].SolvePositionConstraints(h); s = s && i; } if (t && s) { b = true; break; } } for (let t = 0; t < this.m_bodyCount; ++t) { const s = this.m_bodies[t]; s.m_sweep.c.Copy(this.m_positions[t].c); s.m_sweep.a = this.m_positions[t].a; s.m_linearVelocity.Copy(this.m_velocities[t].v); s.m_angularVelocity = this.m_velocities[t].w; s.SynchronizeTransform(); } t.solvePosition = n.GetMilliseconds(); this.Report(l.m_velocityConstraints); if (o) { let t = b2_maxFloat; const s = b2_linearSleepTolerance * b2_linearSleepTolerance; const i = b2_angularSleepTolerance * b2_angularSleepTolerance; for (let o = 0; o < this.m_bodyCount; ++o) { const n = this.m_bodies[o]; if (n.GetType() === b2BodyType.b2_staticBody) { continue; } if (!n.m_autoSleepFlag || n.m_angularVelocity * n.m_angularVelocity > i || b2Vec2.DotVV(n.m_linearVelocity, n.m_linearVelocity) > s) { n.m_sleepTime = 0; t = 0; } else { n.m_sleepTime += e; t = b2Min(t, n.m_sleepTime); } } if (t >= b2_timeToSleep && b) { for (let t = 0; t < this.m_bodyCount; ++t) { const s = this.m_bodies[t]; s.SetAwake(false); } } } } SolveTOI(t, s, i) { for (let t = 0; t < this.m_bodyCount; ++t) { const s = this.m_bodies[t]; this.m_positions[t].c.Copy(s.m_sweep.c); this.m_positions[t].a = s.m_sweep.a; this.m_velocities[t].v.Copy(s.m_linearVelocity); this.m_velocities[t].w = s.m_angularVelocity; } const o = b2Island.s_contactSolverDef; o.contacts = this.m_contacts; o.count = this.m_contactCount; o.step.Copy(t); o.positions = this.m_positions; o.velocities = this.m_velocities; const n = b2Island.s_contactSolver.Initialize(o); for (let o = 0; o < t.positionIterations; ++o) { const t = n.SolveTOIPositionConstraints(s, i); if (t) { break; } } this.m_bodies[s].m_sweep.c0.Copy(this.m_positions[s].c); this.m_bodies[s].m_sweep.a0 = this.m_positions[s].a; this.m_bodies[i].m_sweep.c0.Copy(this.m_positions[i].c); this.m_bodies[i].m_sweep.a0 = this.m_positions[i].a; n.InitializeVelocityConstraints(); for (let s = 0; s < t.velocityIterations; ++s) { n.SolveVelocityConstraints(); } const e = t.dt; for (let t = 0; t < this.m_bodyCount; ++t) { const s = this.m_positions[t].c; let i = this.m_positions[t].a; const o = this.m_velocities[t].v; let n = this.m_velocities[t].w; const h = b2Vec2.MulSV(e, o, b2Island.s_translation); if (b2Vec2.DotVV(h, h) > b2_maxTranslationSquared) { const t = b2_maxTranslation / h.Length(); o.SelfMul(t); } const a = e * n; if (a * a > b2_maxRotationSquared) { const t = b2_maxRotation / b2Abs(a); n *= t; } s.SelfMulAdd(e, o); i += e * n; this.m_positions[t].a = i; this.m_velocities[t].w = n; const l = this.m_bodies[t]; l.m_sweep.c.Copy(s); l.m_sweep.a = i; l.m_linearVelocity.Copy(o); l.m_angularVelocity = n; l.SynchronizeTransform(); } this.Report(n.m_velocityConstraints); } Report(t) { if (this.m_listener === null) { return; } for (let s = 0; s < this.m_contactCount; ++s) { const i = this.m_contacts[s]; if (!i) { continue; } const o = t[s]; const n = b2Island.s_impulse; n.count = o.pointCount; for (let t = 0; t < o.pointCount; ++t) { n.normalImpulses[t] = o.points[t].normalImpulse; n.tangentImpulses[t] = o.points[t].tangentImpulse; } this.m_listener.PostSolve(i, n); } } } b2Island.s_timer = new b2Timer; b2Island.s_solverData = new b2SolverData; b2Island.s_contactSolverDef = new b2ContactSolverDef; b2Island.s_contactSolver = new b2ContactSolver; b2Island.s_translation = new b2Vec2; b2Island.s_impulse = new b2ContactImpulse;