the-world-engine
Version:
three.js based, unity like game engine for browser
280 lines (264 loc) • 10.2 kB
JavaScript
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;