the-world-engine
Version:
three.js based, unity like game engine for browser
1,239 lines (1,182 loc) • 39.9 kB
JavaScript
import { b2_epsilon, b2_maxSubSteps, b2_maxTOIContacts } from "../common/b2_settings.js";
import { b2Min, b2Vec2, b2Transform, b2Sweep } from "../common/b2_math.js";
import { b2Timer } from "../common/b2_timer.js";
import { b2Color, b2DrawFlags } from "../common/b2_draw.js";
import { b2AABB, b2RayCastInput, b2RayCastOutput, b2TestOverlapShape } from "../collision/b2_collision.js";
import { b2TimeOfImpact, b2TOIInput, b2TOIOutput, b2TOIOutputState } from "../collision/b2_time_of_impact.js";
import { b2ShapeType } from "../collision/b2_shape.js";
import { b2JointType } from "./b2_joint.js";
import { b2AreaJoint } from "./b2_area_joint.js";
import { b2DistanceJoint } from "./b2_distance_joint.js";
import { b2FrictionJoint } from "./b2_friction_joint.js";
import { b2GearJoint } from "./b2_gear_joint.js";
import { b2MotorJoint } from "./b2_motor_joint.js";
import { b2MouseJoint } from "./b2_mouse_joint.js";
import { b2PrismaticJoint } from "./b2_prismatic_joint.js";
import { b2PulleyJoint } from "./b2_pulley_joint.js";
import { b2RevoluteJoint } from "./b2_revolute_joint.js";
import { b2WeldJoint } from "./b2_weld_joint.js";
import { b2WheelJoint } from "./b2_wheel_joint.js";
import { b2Body, b2BodyType } from "./b2_body.js";
import { b2ContactManager } from "./b2_contact_manager.js";
import { b2Island } from "./b2_island.js";
import { b2Profile, b2TimeStep } from "./b2_time_step.js";
import { b2QueryCallback } from "./b2_world_callbacks.js";
import { b2RayCastCallback } from "./b2_world_callbacks.js";
import { b2_maxFloat } from "../common/b2_settings.js";
import { b2CalculateParticleIterations } from "../particle/b2_particle.js";
import { b2ParticleSystem } from "../particle/b2_particle_system.js";
export class b2World {
constructor(t) {
this.m_contactManager = new b2ContactManager;
this.m_bodyList = null;
this.m_jointList = null;
this.m_particleSystemList = null;
this.m_bodyCount = 0;
this.m_jointCount = 0;
this.m_gravity = new b2Vec2;
this.m_allowSleep = true;
this.m_destructionListener = null;
this.m_debugDraw = null;
this.m_inv_dt0 = 0;
this.m_newContacts = false;
this.m_locked = false;
this.m_clearForces = true;
this.m_warmStarting = true;
this.m_continuousPhysics = true;
this.m_subStepping = false;
this.m_stepComplete = true;
this.m_profile = new b2Profile;
this.m_island = new b2Island;
this.s_stack = [];
this.m_controllerList = null;
this.m_controllerCount = 0;
this.m_gravity.Copy(t);
}
SetDestructionListener(t) {
this.m_destructionListener = t;
}
SetContactFilter(t) {
this.m_contactManager.m_contactFilter = t;
}
SetContactListener(t) {
this.m_contactManager.m_contactListener = t;
}
SetDebugDraw(t) {
this.m_debugDraw = t;
}
CreateBody(t = {}) {
if (this.IsLocked()) {
throw new Error;
}
const i = new b2Body(t, this);
i.m_prev = null;
i.m_next = this.m_bodyList;
if (this.m_bodyList) {
this.m_bodyList.m_prev = i;
}
this.m_bodyList = i;
++this.m_bodyCount;
return i;
}
DestroyBody(t) {
if (this.IsLocked()) {
throw new Error;
}
let i = t.m_jointList;
while (i) {
const e = i;
i = i.next;
if (this.m_destructionListener) {
this.m_destructionListener.SayGoodbyeJoint(e.joint);
}
this.DestroyJoint(e.joint);
t.m_jointList = i;
}
t.m_jointList = null;
let e = t.m_controllerList;
while (e) {
const i = e;
e = e.nextController;
i.controller.RemoveBody(t);
}
let s = t.m_contactList;
while (s) {
const t = s;
s = s.next;
this.m_contactManager.Destroy(t.contact);
}
t.m_contactList = null;
let r = t.m_fixtureList;
while (r) {
const i = r;
r = r.m_next;
if (this.m_destructionListener) {
this.m_destructionListener.SayGoodbyeFixture(i);
}
i.DestroyProxies();
i.Reset();
t.m_fixtureList = r;
t.m_fixtureCount -= 1;
}
t.m_fixtureList = null;
t.m_fixtureCount = 0;
if (t.m_prev) {
t.m_prev.m_next = t.m_next;
}
if (t.m_next) {
t.m_next.m_prev = t.m_prev;
}
if (t === this.m_bodyList) {
this.m_bodyList = t.m_next;
}
--this.m_bodyCount;
}
static _Joint_Create(t) {
switch (t.type) {
case b2JointType.e_distanceJoint:
return new b2DistanceJoint(t);
case b2JointType.e_mouseJoint:
return new b2MouseJoint(t);
case b2JointType.e_prismaticJoint:
return new b2PrismaticJoint(t);
case b2JointType.e_revoluteJoint:
return new b2RevoluteJoint(t);
case b2JointType.e_pulleyJoint:
return new b2PulleyJoint(t);
case b2JointType.e_gearJoint:
return new b2GearJoint(t);
case b2JointType.e_wheelJoint:
return new b2WheelJoint(t);
case b2JointType.e_weldJoint:
return new b2WeldJoint(t);
case b2JointType.e_frictionJoint:
return new b2FrictionJoint(t);
case b2JointType.e_motorJoint:
return new b2MotorJoint(t);
case b2JointType.e_areaJoint:
return new b2AreaJoint(t);
}
throw new Error;
}
static _Joint_Destroy(t) {}
CreateJoint(t) {
if (this.IsLocked()) {
throw new Error;
}
const i = b2World._Joint_Create(t);
i.m_prev = null;
i.m_next = this.m_jointList;
if (this.m_jointList) {
this.m_jointList.m_prev = i;
}
this.m_jointList = i;
++this.m_jointCount;
i.m_edgeA.prev = null;
i.m_edgeA.next = i.m_bodyA.m_jointList;
if (i.m_bodyA.m_jointList) {
i.m_bodyA.m_jointList.prev = i.m_edgeA;
}
i.m_bodyA.m_jointList = i.m_edgeA;
i.m_edgeB.prev = null;
i.m_edgeB.next = i.m_bodyB.m_jointList;
if (i.m_bodyB.m_jointList) {
i.m_bodyB.m_jointList.prev = i.m_edgeB;
}
i.m_bodyB.m_jointList = i.m_edgeB;
const e = i.m_bodyA;
const s = i.m_bodyB;
const r = i.m_collideConnected;
if (!r) {
let t = s.GetContactList();
while (t) {
if (t.other === e) {
t.contact.FlagForFiltering();
}
t = t.next;
}
}
return i;
}
DestroyJoint(t) {
if (this.IsLocked()) {
throw new Error;
}
if (t.m_prev) {
t.m_prev.m_next = t.m_next;
}
if (t.m_next) {
t.m_next.m_prev = t.m_prev;
}
if (t === this.m_jointList) {
this.m_jointList = t.m_next;
}
const i = t.m_bodyA;
const e = t.m_bodyB;
const s = t.m_collideConnected;
i.SetAwake(true);
e.SetAwake(true);
if (t.m_edgeA.prev) {
t.m_edgeA.prev.next = t.m_edgeA.next;
}
if (t.m_edgeA.next) {
t.m_edgeA.next.prev = t.m_edgeA.prev;
}
if (t.m_edgeA === i.m_jointList) {
i.m_jointList = t.m_edgeA.next;
}
t.m_edgeA.Reset();
if (t.m_edgeB.prev) {
t.m_edgeB.prev.next = t.m_edgeB.next;
}
if (t.m_edgeB.next) {
t.m_edgeB.next.prev = t.m_edgeB.prev;
}
if (t.m_edgeB === e.m_jointList) {
e.m_jointList = t.m_edgeB.next;
}
t.m_edgeB.Reset();
b2World._Joint_Destroy(t);
--this.m_jointCount;
if (!s) {
let t = e.GetContactList();
while (t) {
if (t.other === i) {
t.contact.FlagForFiltering();
}
t = t.next;
}
}
}
CreateParticleSystem(t) {
if (this.IsLocked()) {
throw new Error;
}
const i = new b2ParticleSystem(t, this);
i.m_prev = null;
i.m_next = this.m_particleSystemList;
if (this.m_particleSystemList) {
this.m_particleSystemList.m_prev = i;
}
this.m_particleSystemList = i;
return i;
}
DestroyParticleSystem(t) {
if (this.IsLocked()) {
throw new Error;
}
if (t.m_prev) {
t.m_prev.m_next = t.m_next;
}
if (t.m_next) {
t.m_next.m_prev = t.m_prev;
}
if (t === this.m_particleSystemList) {
this.m_particleSystemList = t.m_next;
}
}
CalculateReasonableParticleIterations(t) {
if (this.m_particleSystemList === null) {
return 1;
}
function GetSmallestRadius(t) {
let i = b2_maxFloat;
for (let e = t.GetParticleSystemList(); e !== null; e = e.m_next) {
i = b2Min(i, e.GetRadius());
}
return i;
}
return b2CalculateParticleIterations(this.m_gravity.Length(), GetSmallestRadius(this), t);
}
Step(t, i, e, s = this.CalculateReasonableParticleIterations(t)) {
const r = b2World.Step_s_stepTimer.Reset();
if (this.m_newContacts) {
this.m_contactManager.FindNewContacts();
this.m_newContacts = false;
}
this.m_locked = true;
const o = b2World.Step_s_step;
o.dt = t;
o.velocityIterations = i;
o.positionIterations = e;
o.particleIterations = s;
if (t > 0) {
o.inv_dt = 1 / t;
} else {
o.inv_dt = 0;
}
o.dtRatio = this.m_inv_dt0 * t;
o.warmStarting = this.m_warmStarting;
const n = b2World.Step_s_timer.Reset();
this.m_contactManager.Collide();
this.m_profile.collide = n.GetMilliseconds();
if (this.m_stepComplete && o.dt > 0) {
const t = b2World.Step_s_timer.Reset();
for (let t = this.m_particleSystemList; t; t = t.m_next) {
t.Solve(o);
}
this.Solve(o);
this.m_profile.solve = t.GetMilliseconds();
}
if (this.m_continuousPhysics && o.dt > 0) {
const t = b2World.Step_s_timer.Reset();
this.SolveTOI(o);
this.m_profile.solveTOI = t.GetMilliseconds();
}
if (o.dt > 0) {
this.m_inv_dt0 = o.inv_dt;
}
if (this.m_clearForces) {
this.ClearForces();
}
this.m_locked = false;
this.m_profile.step = r.GetMilliseconds();
}
ClearForces() {
for (let t = this.m_bodyList; t; t = t.m_next) {
t.m_force.SetZero();
t.m_torque = 0;
}
}
DrawParticleSystem(t) {
if (this.m_debugDraw === null) {
return;
}
const i = t.GetParticleCount();
if (i) {
const e = t.GetRadius();
const s = t.GetPositionBuffer();
if (t.m_colorBuffer.data) {
const r = t.GetColorBuffer();
this.m_debugDraw.DrawParticles(s, e, r, i);
} else {
this.m_debugDraw.DrawParticles(s, e, null, i);
}
}
}
DebugDraw() {
if (this.m_debugDraw === null) {
return;
}
const t = this.m_debugDraw.GetFlags();
const i = b2World.DebugDraw_s_color.SetRGB(0, 0, 0);
if (t & b2DrawFlags.e_shapeBit) {
for (let t = this.m_bodyList; t; t = t.m_next) {
const e = t.m_xf;
this.m_debugDraw.PushTransform(e);
for (let e = t.GetFixtureList(); e; e = e.m_next) {
if (t.GetType() === b2BodyType.b2_dynamicBody && t.m_mass === 0) {
this.DrawShape(e, new b2Color(1, 0, 0));
} else if (!t.IsEnabled()) {
i.SetRGB(.5, .5, .3);
this.DrawShape(e, i);
} else if (t.GetType() === b2BodyType.b2_staticBody) {
i.SetRGB(.5, .9, .5);
this.DrawShape(e, i);
} else if (t.GetType() === b2BodyType.b2_kinematicBody) {
i.SetRGB(.5, .5, .9);
this.DrawShape(e, i);
} else if (!t.IsAwake()) {
i.SetRGB(.6, .6, .6);
this.DrawShape(e, i);
} else {
i.SetRGB(.9, .7, .7);
this.DrawShape(e, i);
}
}
this.m_debugDraw.PopTransform(e);
}
}
if (t & b2DrawFlags.e_particleBit) {
for (let t = this.m_particleSystemList; t; t = t.m_next) {
this.DrawParticleSystem(t);
}
}
if (t & b2DrawFlags.e_jointBit) {
for (let t = this.m_jointList; t; t = t.m_next) {
t.Draw(this.m_debugDraw);
}
}
if (t & b2DrawFlags.e_pairBit) {
i.SetRGB(.3, .9, .9);
for (let t = this.m_contactManager.m_contactList; t; t = t.m_next) {
const e = t.GetFixtureA();
const s = t.GetFixtureB();
const r = t.GetChildIndexA();
const o = t.GetChildIndexB();
const n = e.GetAABB(r).GetCenter();
const l = s.GetAABB(o).GetCenter();
this.m_debugDraw.DrawSegment(n, l, i);
}
}
if (t & b2DrawFlags.e_aabbBit) {
i.SetRGB(.9, .3, .9);
const t = b2World.DebugDraw_s_vs;
for (let e = this.m_bodyList; e; e = e.m_next) {
if (!e.IsEnabled()) {
continue;
}
for (let s = e.GetFixtureList(); s; s = s.m_next) {
for (let e = 0; e < s.m_proxyCount; ++e) {
const r = s.m_proxies[e];
const o = r.treeNode.aabb;
t[0].Set(o.lowerBound.x, o.lowerBound.y);
t[1].Set(o.upperBound.x, o.lowerBound.y);
t[2].Set(o.upperBound.x, o.upperBound.y);
t[3].Set(o.lowerBound.x, o.upperBound.y);
this.m_debugDraw.DrawPolygon(t, 4, i);
}
}
}
}
if (t & b2DrawFlags.e_centerOfMassBit) {
for (let t = this.m_bodyList; t; t = t.m_next) {
const i = b2World.DebugDraw_s_xf;
i.q.Copy(t.m_xf.q);
i.p.Copy(t.GetWorldCenter());
this.m_debugDraw.DrawTransform(i);
}
}
if (t & b2DrawFlags.e_controllerBit) {
for (let t = this.m_controllerList; t; t = t.m_next) {
t.Draw(this.m_debugDraw);
}
}
}
QueryAABB(...t) {
if (t[0] instanceof b2QueryCallback) {
this._QueryAABB(t[0], t[1]);
} else {
this._QueryAABB(null, t[0], t[1]);
}
}
_QueryAABB(t, i, e) {
this.m_contactManager.m_broadPhase.Query(i, (i => {
const s = i.userData;
const r = s.fixture;
if (t) {
return t.ReportFixture(r);
} else if (e) {
return e(r);
}
return true;
}));
if (t instanceof b2QueryCallback) {
for (let e = this.m_particleSystemList; e; e = e.m_next) {
if (t.ShouldQueryParticleSystem(e)) {
e.QueryAABB(t, i);
}
}
}
}
QueryAllAABB(t, i = []) {
this.QueryAABB(t, (t => {
i.push(t);
return true;
}));
return i;
}
QueryPointAABB(...t) {
if (t[0] instanceof b2QueryCallback) {
this._QueryPointAABB(t[0], t[1]);
} else {
this._QueryPointAABB(null, t[0], t[1]);
}
}
_QueryPointAABB(t, i, e) {
this.m_contactManager.m_broadPhase.QueryPoint(i, (i => {
const s = i.userData;
const r = s.fixture;
if (t) {
return t.ReportFixture(r);
} else if (e) {
return e(r);
}
return true;
}));
if (t instanceof b2QueryCallback) {
for (let e = this.m_particleSystemList; e; e = e.m_next) {
if (t.ShouldQueryParticleSystem(e)) {
e.QueryPointAABB(t, i);
}
}
}
}
QueryAllPointAABB(t, i = []) {
this.QueryPointAABB(t, (t => {
i.push(t);
return true;
}));
return i;
}
QueryFixtureShape(...t) {
if (t[0] instanceof b2QueryCallback) {
this._QueryFixtureShape(t[0], t[1], t[2], t[3]);
} else {
this._QueryFixtureShape(null, t[0], t[1], t[2], t[3]);
}
}
_QueryFixtureShape(t, i, e, s, r) {
const o = b2World.QueryFixtureShape_s_aabb;
i.ComputeAABB(o, s, e);
this.m_contactManager.m_broadPhase.Query(o, (o => {
const n = o.userData;
const l = n.fixture;
if (b2TestOverlapShape(i, e, l.GetShape(), n.childIndex, s, l.GetBody().GetTransform())) {
if (t) {
return t.ReportFixture(l);
} else if (r) {
return r(l);
}
}
return true;
}));
if (t instanceof b2QueryCallback) {
for (let i = this.m_particleSystemList; i; i = i.m_next) {
if (t.ShouldQueryParticleSystem(i)) {
i.QueryAABB(t, o);
}
}
}
}
QueryAllFixtureShape(t, i, e, s = []) {
this.QueryFixtureShape(t, i, e, (t => {
s.push(t);
return true;
}));
return s;
}
QueryFixturePoint(...t) {
if (t[0] instanceof b2QueryCallback) {
this._QueryFixturePoint(t[0], t[1]);
} else {
this._QueryFixturePoint(null, t[0], t[1]);
}
}
_QueryFixturePoint(t, i, e) {
this.m_contactManager.m_broadPhase.QueryPoint(i, (s => {
const r = s.userData;
const o = r.fixture;
if (o.TestPoint(i)) {
if (t) {
return t.ReportFixture(o);
} else if (e) {
return e(o);
}
}
return true;
}));
if (t) {
for (let e = this.m_particleSystemList; e; e = e.m_next) {
if (t.ShouldQueryParticleSystem(e)) {
e.QueryPointAABB(t, i);
}
}
}
}
QueryAllFixturePoint(t, i = []) {
this.QueryFixturePoint(t, (t => {
i.push(t);
return true;
}));
return i;
}
RayCast(...t) {
if (t[0] instanceof b2RayCastCallback) {
this._RayCast(t[0], t[1], t[2]);
} else {
this._RayCast(null, t[0], t[1], t[2]);
}
}
_RayCast(t, i, e, s) {
const r = b2World.RayCast_s_input;
r.maxFraction = 1;
r.p1.Copy(i);
r.p2.Copy(e);
this.m_contactManager.m_broadPhase.RayCast(r, ((r, o) => {
const n = o.userData;
const l = n.fixture;
const h = n.childIndex;
const f = b2World.RayCast_s_output;
const c = l.RayCast(f, r, h);
if (c) {
const r = f.fraction;
const o = b2World.RayCast_s_point;
o.Set((1 - r) * i.x + r * e.x, (1 - r) * i.y + r * e.y);
if (t) {
return t.ReportFixture(l, o, f.normal, r);
} else if (s) {
return s(l, o, f.normal, r);
}
}
return r.maxFraction;
}));
if (t) {
for (let s = this.m_particleSystemList; s; s = s.m_next) {
if (t.ShouldQueryParticleSystem(s)) {
s.RayCast(t, i, e);
}
}
}
}
RayCastOne(t, i) {
let e = null;
let s = 1;
this.RayCast(t, i, ((t, i, r, o) => {
if (o < s) {
s = o;
e = t;
}
return s;
}));
return e;
}
RayCastAll(t, i, e = []) {
this.RayCast(t, i, ((t, i, s, r) => {
e.push(t);
return 1;
}));
return e;
}
GetBodyList() {
return this.m_bodyList;
}
GetJointList() {
return this.m_jointList;
}
GetParticleSystemList() {
return this.m_particleSystemList;
}
GetContactList() {
return this.m_contactManager.m_contactList;
}
SetAllowSleeping(t) {
if (t === this.m_allowSleep) {
return;
}
this.m_allowSleep = t;
if (!this.m_allowSleep) {
for (let t = this.m_bodyList; t; t = t.m_next) {
t.SetAwake(true);
}
}
}
GetAllowSleeping() {
return this.m_allowSleep;
}
SetWarmStarting(t) {
this.m_warmStarting = t;
}
GetWarmStarting() {
return this.m_warmStarting;
}
SetContinuousPhysics(t) {
this.m_continuousPhysics = t;
}
GetContinuousPhysics() {
return this.m_continuousPhysics;
}
SetSubStepping(t) {
this.m_subStepping = t;
}
GetSubStepping() {
return this.m_subStepping;
}
GetProxyCount() {
return this.m_contactManager.m_broadPhase.GetProxyCount();
}
GetBodyCount() {
return this.m_bodyCount;
}
GetJointCount() {
return this.m_jointCount;
}
GetContactCount() {
return this.m_contactManager.m_contactCount;
}
GetTreeHeight() {
return this.m_contactManager.m_broadPhase.GetTreeHeight();
}
GetTreeBalance() {
return this.m_contactManager.m_broadPhase.GetTreeBalance();
}
GetTreeQuality() {
return this.m_contactManager.m_broadPhase.GetTreeQuality();
}
SetGravity(t, i = true) {
if (!b2Vec2.IsEqualToV(this.m_gravity, t)) {
this.m_gravity.Copy(t);
if (i) {
for (let t = this.m_bodyList; t; t = t.m_next) {
t.SetAwake(true);
}
}
}
}
GetGravity() {
return this.m_gravity;
}
IsLocked() {
return this.m_locked;
}
SetAutoClearForces(t) {
this.m_clearForces = t;
}
GetAutoClearForces() {
return this.m_clearForces;
}
ShiftOrigin(t) {
if (this.IsLocked()) {
throw new Error;
}
for (let i = this.m_bodyList; i; i = i.m_next) {
i.m_xf.p.SelfSub(t);
i.m_sweep.c0.SelfSub(t);
i.m_sweep.c.SelfSub(t);
}
for (let i = this.m_jointList; i; i = i.m_next) {
i.ShiftOrigin(t);
}
this.m_contactManager.m_broadPhase.ShiftOrigin(t);
}
GetContactManager() {
return this.m_contactManager;
}
GetProfile() {
return this.m_profile;
}
Dump(t) {
if (this.m_locked) {
return;
}
t("const g: b2Vec2 = new b2Vec2(%.15f, %.15f);\n", this.m_gravity.x, this.m_gravity.y);
t("this.m_world.SetGravity(g);\n");
t("const bodies: b2Body[] = [];\n");
t("const joints: b2Joint[] = [];\n");
let i = 0;
for (let e = this.m_bodyList; e; e = e.m_next) {
e.m_islandIndex = i;
e.Dump(t);
++i;
}
i = 0;
for (let t = this.m_jointList; t; t = t.m_next) {
t.m_index = i;
++i;
}
for (let i = this.m_jointList; i; i = i.m_next) {
if (i.m_type === b2JointType.e_gearJoint) {
continue;
}
t("{\n");
i.Dump(t);
t("}\n");
}
for (let i = this.m_jointList; i; i = i.m_next) {
if (i.m_type !== b2JointType.e_gearJoint) {
continue;
}
t("{\n");
i.Dump(t);
t("}\n");
}
}
DrawShape(t, i) {
if (this.m_debugDraw === null) {
return;
}
const e = t.GetShape();
switch (e.m_type) {
case b2ShapeType.e_circleShape:
{
const t = e;
const s = t.m_p;
const r = t.m_radius;
const o = b2Vec2.UNITX;
this.m_debugDraw.DrawSolidCircle(s, r, o, i);
break;
}
case b2ShapeType.e_edgeShape:
{
const t = e;
const s = t.m_vertex1;
const r = t.m_vertex2;
this.m_debugDraw.DrawSegment(s, r, i);
if (t.m_oneSided === false) {
this.m_debugDraw.DrawPoint(s, 4, i);
this.m_debugDraw.DrawPoint(r, 4, i);
}
break;
}
case b2ShapeType.e_chainShape:
{
const t = e;
const s = t.m_count;
const r = t.m_vertices;
let o = r[0];
for (let t = 1; t < s; ++t) {
const e = r[t];
this.m_debugDraw.DrawSegment(o, e, i);
o = e;
}
break;
}
case b2ShapeType.e_polygonShape:
{
const t = e;
const s = t.m_count;
const r = t.m_vertices;
this.m_debugDraw.DrawSolidPolygon(r, s, i);
break;
}
}
}
Solve(t) {
for (let t = this.m_bodyList; t; t = t.m_next) {
t.m_xf0.Copy(t.m_xf);
}
for (let i = this.m_controllerList; i; i = i.m_next) {
i.Step(t);
}
this.m_profile.solveInit = 0;
this.m_profile.solveVelocity = 0;
this.m_profile.solvePosition = 0;
const i = this.m_island;
i.Initialize(this.m_bodyCount, this.m_contactManager.m_contactCount, this.m_jointCount, this.m_contactManager.m_contactListener);
for (let t = this.m_bodyList; t; t = t.m_next) {
t.m_islandFlag = false;
}
for (let t = this.m_contactManager.m_contactList; t; t = t.m_next) {
t.m_islandFlag = false;
}
for (let t = this.m_jointList; t; t = t.m_next) {
t.m_islandFlag = false;
}
const e = this.s_stack;
for (let s = this.m_bodyList; s; s = s.m_next) {
if (s.m_islandFlag) {
continue;
}
if (!s.IsAwake() || !s.IsEnabled()) {
continue;
}
if (s.GetType() === b2BodyType.b2_staticBody) {
continue;
}
i.Clear();
let r = 0;
e[r++] = s;
s.m_islandFlag = true;
while (r > 0) {
const t = e[--r];
if (!t) {
throw new Error;
}
i.AddBody(t);
if (t.GetType() === b2BodyType.b2_staticBody) {
continue;
}
t.m_awakeFlag = true;
for (let s = t.m_contactList; s; s = s.next) {
const t = s.contact;
if (t.m_islandFlag) {
continue;
}
if (!t.IsEnabled() || !t.IsTouching()) {
continue;
}
const o = t.m_fixtureA.m_isSensor;
const n = t.m_fixtureB.m_isSensor;
if (o || n) {
continue;
}
i.AddContact(t);
t.m_islandFlag = true;
const l = s.other;
if (l.m_islandFlag) {
continue;
}
e[r++] = l;
l.m_islandFlag = true;
}
for (let s = t.m_jointList; s; s = s.next) {
if (s.joint.m_islandFlag) {
continue;
}
const t = s.other;
if (!t.IsEnabled()) {
continue;
}
i.AddJoint(s.joint);
s.joint.m_islandFlag = true;
if (t.m_islandFlag) {
continue;
}
e[r++] = t;
t.m_islandFlag = true;
}
}
const o = new b2Profile;
i.Solve(o, t, this.m_gravity, this.m_allowSleep);
this.m_profile.solveInit += o.solveInit;
this.m_profile.solveVelocity += o.solveVelocity;
this.m_profile.solvePosition += o.solvePosition;
for (let t = 0; t < i.m_bodyCount; ++t) {
const e = i.m_bodies[t];
if (e.GetType() === b2BodyType.b2_staticBody) {
e.m_islandFlag = false;
}
}
}
for (let t = 0; t < e.length; ++t) {
if (!e[t]) {
break;
}
e[t] = null;
}
const s = new b2Timer;
for (let t = this.m_bodyList; t; t = t.m_next) {
if (!t.m_islandFlag) {
continue;
}
if (t.GetType() === b2BodyType.b2_staticBody) {
continue;
}
t.SynchronizeFixtures();
}
this.m_contactManager.FindNewContacts();
this.m_profile.broadphase = s.GetMilliseconds();
}
SolveTOI(t) {
const i = this.m_island;
i.Initialize(2 * b2_maxTOIContacts, b2_maxTOIContacts, 0, this.m_contactManager.m_contactListener);
if (this.m_stepComplete) {
for (let t = this.m_bodyList; t; t = t.m_next) {
t.m_islandFlag = false;
t.m_sweep.alpha0 = 0;
}
for (let t = this.m_contactManager.m_contactList; t; t = t.m_next) {
t.m_toiFlag = false;
t.m_islandFlag = false;
t.m_toiCount = 0;
t.m_toi = 1;
}
}
for (;;) {
let e = null;
let s = 1;
for (let t = this.m_contactManager.m_contactList; t; t = t.m_next) {
if (!t.IsEnabled()) {
continue;
}
if (t.m_toiCount > b2_maxSubSteps) {
continue;
}
let i = 1;
if (t.m_toiFlag) {
i = t.m_toi;
} else {
const e = t.GetFixtureA();
const s = t.GetFixtureB();
if (e.IsSensor() || s.IsSensor()) {
continue;
}
const r = e.GetBody();
const o = s.GetBody();
const n = r.m_type;
const l = o.m_type;
const h = r.IsAwake() && n !== b2BodyType.b2_staticBody;
const f = o.IsAwake() && l !== b2BodyType.b2_staticBody;
if (!h && !f) {
continue;
}
const c = r.IsBullet() || n !== b2BodyType.b2_dynamicBody;
const u = o.IsBullet() || l !== b2BodyType.b2_dynamicBody;
if (!c && !u) {
continue;
}
let b = r.m_sweep.alpha0;
if (r.m_sweep.alpha0 < o.m_sweep.alpha0) {
b = o.m_sweep.alpha0;
r.m_sweep.Advance(b);
} else if (o.m_sweep.alpha0 < r.m_sweep.alpha0) {
b = r.m_sweep.alpha0;
o.m_sweep.Advance(b);
}
const a = t.GetChildIndexA();
const p = t.GetChildIndexB();
const m = b2World.SolveTOI_s_toi_input;
m.proxyA.SetShape(e.GetShape(), a);
m.proxyB.SetShape(s.GetShape(), p);
m.sweepA.Copy(r.m_sweep);
m.sweepB.Copy(o.m_sweep);
m.tMax = 1;
const y = b2World.SolveTOI_s_toi_output;
b2TimeOfImpact(y, m);
const w = y.t;
if (y.state === b2TOIOutputState.e_touching) {
i = b2Min(b + (1 - b) * w, 1);
} else {
i = 1;
}
t.m_toi = i;
t.m_toiFlag = true;
}
if (i < s) {
e = t;
s = i;
}
}
if (e === null || 1 - 10 * b2_epsilon < s) {
this.m_stepComplete = true;
break;
}
const r = e.GetFixtureA();
const o = e.GetFixtureB();
const n = r.GetBody();
const l = o.GetBody();
const h = b2World.SolveTOI_s_backup1.Copy(n.m_sweep);
const f = b2World.SolveTOI_s_backup2.Copy(l.m_sweep);
n.Advance(s);
l.Advance(s);
e.Update(this.m_contactManager.m_contactListener);
e.m_toiFlag = false;
++e.m_toiCount;
if (!e.IsEnabled() || !e.IsTouching()) {
e.SetEnabled(false);
n.m_sweep.Copy(h);
l.m_sweep.Copy(f);
n.SynchronizeTransform();
l.SynchronizeTransform();
continue;
}
n.SetAwake(true);
l.SetAwake(true);
i.Clear();
i.AddBody(n);
i.AddBody(l);
i.AddContact(e);
n.m_islandFlag = true;
l.m_islandFlag = true;
e.m_islandFlag = true;
for (let t = 0; t < 2; ++t) {
const e = t === 0 ? n : l;
if (e.m_type === b2BodyType.b2_dynamicBody) {
for (let t = e.m_contactList; t; t = t.next) {
if (i.m_bodyCount === i.m_bodyCapacity) {
break;
}
if (i.m_contactCount === i.m_contactCapacity) {
break;
}
const r = t.contact;
if (r.m_islandFlag) {
continue;
}
const o = t.other;
if (o.m_type === b2BodyType.b2_dynamicBody && !e.IsBullet() && !o.IsBullet()) {
continue;
}
const n = r.m_fixtureA.m_isSensor;
const l = r.m_fixtureB.m_isSensor;
if (n || l) {
continue;
}
const h = b2World.SolveTOI_s_backup.Copy(o.m_sweep);
if (!o.m_islandFlag) {
o.Advance(s);
}
r.Update(this.m_contactManager.m_contactListener);
if (!r.IsEnabled()) {
o.m_sweep.Copy(h);
o.SynchronizeTransform();
continue;
}
if (!r.IsTouching()) {
o.m_sweep.Copy(h);
o.SynchronizeTransform();
continue;
}
r.m_islandFlag = true;
i.AddContact(r);
if (o.m_islandFlag) {
continue;
}
o.m_islandFlag = true;
if (o.m_type !== b2BodyType.b2_staticBody) {
o.SetAwake(true);
}
i.AddBody(o);
}
}
}
const c = b2World.SolveTOI_s_subStep;
c.dt = (1 - s) * t.dt;
c.inv_dt = 1 / c.dt;
c.dtRatio = 1;
c.positionIterations = 20;
c.velocityIterations = t.velocityIterations;
c.particleIterations = t.particleIterations;
c.warmStarting = false;
i.SolveTOI(c, n.m_islandIndex, l.m_islandIndex);
for (let t = 0; t < i.m_bodyCount; ++t) {
const e = i.m_bodies[t];
e.m_islandFlag = false;
if (e.m_type !== b2BodyType.b2_dynamicBody) {
continue;
}
e.SynchronizeFixtures();
for (let t = e.m_contactList; t; t = t.next) {
t.contact.m_toiFlag = false;
t.contact.m_islandFlag = false;
}
}
this.m_contactManager.FindNewContacts();
if (this.m_subStepping) {
this.m_stepComplete = false;
break;
}
}
}
AddController(t) {
t.m_next = this.m_controllerList;
t.m_prev = null;
if (this.m_controllerList) {
this.m_controllerList.m_prev = t;
}
this.m_controllerList = t;
++this.m_controllerCount;
return t;
}
RemoveController(t) {
if (t.m_prev) {
t.m_prev.m_next = t.m_next;
}
if (t.m_next) {
t.m_next.m_prev = t.m_prev;
}
if (this.m_controllerList === t) {
this.m_controllerList = t.m_next;
}
--this.m_controllerCount;
t.m_prev = null;
t.m_next = null;
return t;
}
}
b2World.Step_s_step = new b2TimeStep;
b2World.Step_s_stepTimer = new b2Timer;
b2World.Step_s_timer = new b2Timer;
b2World.DebugDraw_s_color = new b2Color(0, 0, 0);
b2World.DebugDraw_s_vs = b2Vec2.MakeArray(4);
b2World.DebugDraw_s_xf = new b2Transform;
b2World.QueryFixtureShape_s_aabb = new b2AABB;
b2World.RayCast_s_input = new b2RayCastInput;
b2World.RayCast_s_output = new b2RayCastOutput;
b2World.RayCast_s_point = new b2Vec2;
b2World.SolveTOI_s_subStep = new b2TimeStep;
b2World.SolveTOI_s_backup = new b2Sweep;
b2World.SolveTOI_s_backup1 = new b2Sweep;
b2World.SolveTOI_s_backup2 = new b2Sweep;
b2World.SolveTOI_s_toi_input = new b2TOIInput;
b2World.SolveTOI_s_toi_output = new b2TOIOutput;