UNPKG

the-world-engine

Version:

three.js based, unity like game engine for browser

680 lines (664 loc) 21.5 kB
import { b2Maybe } from "../common/b2_settings.js"; import { b2Vec2, b2Rot, b2Transform, b2Sweep } from "../common/b2_math.js"; import { b2Shape, b2MassData } from "../collision/b2_shape.js"; import { b2Fixture, b2FixtureDef } from "./b2_fixture.js"; export var b2BodyType; (function(t) { t[t["b2_unknown"] = -1] = "b2_unknown"; t[t["b2_staticBody"] = 0] = "b2_staticBody"; t[t["b2_kinematicBody"] = 1] = "b2_kinematicBody"; t[t["b2_dynamicBody"] = 2] = "b2_dynamicBody"; })(b2BodyType || (b2BodyType = {})); export class b2BodyDef { constructor() { this.type = b2BodyType.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.enabled = true; this.userData = null; this.gravityScale = 1; } } export class b2Body { constructor(t, i) { this.m_type = b2BodyType.b2_staticBody; this.m_islandFlag = false; this.m_awakeFlag = false; this.m_autoSleepFlag = false; this.m_bulletFlag = false; this.m_fixedRotationFlag = false; this.m_enabledFlag = false; this.m_toiFlag = false; this.m_islandIndex = 0; this.m_xf = new b2Transform; this.m_xf0 = new b2Transform; this.m_sweep = new b2Sweep; this.m_linearVelocity = new b2Vec2; this.m_angularVelocity = 0; this.m_force = new b2Vec2; this.m_torque = 0; this.m_prev = null; this.m_next = null; this.m_fixtureList = null; this.m_fixtureCount = 0; this.m_jointList = null; this.m_contactList = null; this.m_mass = 1; this.m_invMass = 1; this.m_I = 0; this.m_invI = 0; this.m_linearDamping = 0; this.m_angularDamping = 0; this.m_gravityScale = 1; this.m_sleepTime = 0; this.m_userData = null; this.m_controllerList = null; this.m_controllerCount = 0; this.m_bulletFlag = b2Maybe(t.bullet, false); this.m_fixedRotationFlag = b2Maybe(t.fixedRotation, false); this.m_autoSleepFlag = b2Maybe(t.allowSleep, true); if (b2Maybe(t.awake, true) && b2Maybe(t.type, b2BodyType.b2_staticBody) !== b2BodyType.b2_staticBody) { this.m_awakeFlag = true; } this.m_enabledFlag = b2Maybe(t.enabled, true); this.m_world = i; this.m_xf.p.Copy(b2Maybe(t.position, b2Vec2.ZERO)); this.m_xf.q.SetAngle(b2Maybe(t.angle, 0)); this.m_xf0.Copy(this.m_xf); this.m_sweep.localCenter.SetZero(); this.m_sweep.c0.Copy(this.m_xf.p); this.m_sweep.c.Copy(this.m_xf.p); this.m_sweep.a0 = this.m_sweep.a = this.m_xf.q.GetAngle(); this.m_sweep.alpha0 = 0; this.m_linearVelocity.Copy(b2Maybe(t.linearVelocity, b2Vec2.ZERO)); this.m_angularVelocity = b2Maybe(t.angularVelocity, 0); this.m_linearDamping = b2Maybe(t.linearDamping, 0); this.m_angularDamping = b2Maybe(t.angularDamping, 0); this.m_gravityScale = b2Maybe(t.gravityScale, 1); this.m_force.SetZero(); this.m_torque = 0; this.m_sleepTime = 0; this.m_type = b2Maybe(t.type, b2BodyType.b2_staticBody); this.m_mass = 0; this.m_invMass = 0; this.m_I = 0; this.m_invI = 0; this.m_userData = t.userData; this.m_fixtureList = null; this.m_fixtureCount = 0; this.m_controllerList = null; this.m_controllerCount = 0; } CreateFixture(t, i = 0) { if (t instanceof b2Shape) { return this.CreateFixtureShapeDensity(t, i); } else { return this.CreateFixtureDef(t); } } CreateFixtureDef(t) { if (this.m_world.IsLocked()) { throw new Error; } const i = new b2Fixture(this, t); if (this.m_enabledFlag) { i.CreateProxies(); } i.m_next = this.m_fixtureList; this.m_fixtureList = i; ++this.m_fixtureCount; if (i.m_density > 0) { this.ResetMassData(); } this.m_world.m_newContacts = true; return i; } CreateFixtureShapeDensity(t, i = 0) { const s = b2Body.CreateFixtureShapeDensity_s_def; s.shape = t; s.density = i; return this.CreateFixtureDef(s); } DestroyFixture(t) { if (this.m_world.IsLocked()) { throw new Error; } let i = this.m_fixtureList; let s = null; while (i !== null) { if (i === t) { if (s) { s.m_next = t.m_next; } else { this.m_fixtureList = t.m_next; } break; } s = i; i = i.m_next; } let h = this.m_contactList; while (h) { const i = h.contact; h = h.next; const s = i.GetFixtureA(); const e = i.GetFixtureB(); if (t === s || t === e) { this.m_world.m_contactManager.Destroy(i); } } if (this.m_enabledFlag) { t.DestroyProxies(); } t.m_next = null; t.Reset(); --this.m_fixtureCount; this.ResetMassData(); } SetTransformVec(t, i) { this.SetTransformXY(t.x, t.y, i); } SetTransformXY(t, i, s) { if (this.m_world.IsLocked()) { throw new Error; } this.m_xf.q.SetAngle(s); this.m_xf.p.Set(t, i); this.m_xf0.Copy(this.m_xf); b2Transform.MulXV(this.m_xf, this.m_sweep.localCenter, this.m_sweep.c); this.m_sweep.a = s; this.m_sweep.c0.Copy(this.m_sweep.c); this.m_sweep.a0 = s; for (let t = this.m_fixtureList; t; t = t.m_next) { t.SynchronizeProxies(this.m_xf, this.m_xf); } this.m_world.m_newContacts = true; } SetTransform(t) { this.SetTransformVec(t.p, t.GetAngle()); } GetTransform() { return this.m_xf; } GetPosition() { return this.m_xf.p; } SetPosition(t) { this.SetTransformVec(t, this.GetAngle()); } SetPositionXY(t, i) { this.SetTransformXY(t, i, this.GetAngle()); } GetAngle() { return this.m_sweep.a; } SetAngle(t) { this.SetTransformVec(this.GetPosition(), t); } GetWorldCenter() { return this.m_sweep.c; } GetLocalCenter() { return this.m_sweep.localCenter; } SetLinearVelocity(t) { if (this.m_type === b2BodyType.b2_staticBody) { return; } if (b2Vec2.DotVV(t, t) > 0) { this.SetAwake(true); } this.m_linearVelocity.Copy(t); } GetLinearVelocity() { return this.m_linearVelocity; } SetAngularVelocity(t) { if (this.m_type === b2BodyType.b2_staticBody) { return; } if (t * t > 0) { this.SetAwake(true); } this.m_angularVelocity = t; } GetAngularVelocity() { return this.m_angularVelocity; } GetDefinition(t) { t.type = this.GetType(); t.allowSleep = this.m_autoSleepFlag; t.angle = this.GetAngle(); t.angularDamping = this.m_angularDamping; t.gravityScale = this.m_gravityScale; t.angularVelocity = this.m_angularVelocity; t.fixedRotation = this.m_fixedRotationFlag; t.bullet = this.m_bulletFlag; t.awake = this.m_awakeFlag; t.linearDamping = this.m_linearDamping; t.linearVelocity.Copy(this.GetLinearVelocity()); t.position.Copy(this.GetPosition()); t.userData = this.GetUserData(); return t; } ApplyForce(t, i, s = true) { if (this.m_type !== b2BodyType.b2_dynamicBody) { return; } if (s && !this.m_awakeFlag) { this.SetAwake(true); } if (this.m_awakeFlag) { this.m_force.x += t.x; this.m_force.y += t.y; this.m_torque += (i.x - this.m_sweep.c.x) * t.y - (i.y - this.m_sweep.c.y) * t.x; } } ApplyForceToCenter(t, i = true) { if (this.m_type !== b2BodyType.b2_dynamicBody) { return; } if (i && !this.m_awakeFlag) { this.SetAwake(true); } if (this.m_awakeFlag) { this.m_force.x += t.x; this.m_force.y += t.y; } } ApplyTorque(t, i = true) { if (this.m_type !== b2BodyType.b2_dynamicBody) { return; } if (i && !this.m_awakeFlag) { this.SetAwake(true); } if (this.m_awakeFlag) { this.m_torque += t; } } ApplyLinearImpulse(t, i, s = true) { if (this.m_type !== b2BodyType.b2_dynamicBody) { return; } if (s && !this.m_awakeFlag) { this.SetAwake(true); } if (this.m_awakeFlag) { this.m_linearVelocity.x += this.m_invMass * t.x; this.m_linearVelocity.y += this.m_invMass * t.y; this.m_angularVelocity += this.m_invI * ((i.x - this.m_sweep.c.x) * t.y - (i.y - this.m_sweep.c.y) * t.x); } } ApplyLinearImpulseToCenter(t, i = true) { if (this.m_type !== b2BodyType.b2_dynamicBody) { return; } if (i && !this.m_awakeFlag) { this.SetAwake(true); } if (this.m_awakeFlag) { this.m_linearVelocity.x += this.m_invMass * t.x; this.m_linearVelocity.y += this.m_invMass * t.y; } } ApplyAngularImpulse(t, i = true) { if (this.m_type !== b2BodyType.b2_dynamicBody) { return; } if (i && !this.m_awakeFlag) { this.SetAwake(true); } if (this.m_awakeFlag) { this.m_angularVelocity += this.m_invI * t; } } GetMass() { return this.m_mass; } GetInertia() { return this.m_I + this.m_mass * b2Vec2.DotVV(this.m_sweep.localCenter, this.m_sweep.localCenter); } GetMassData(t) { t.mass = this.m_mass; t.I = this.m_I + this.m_mass * b2Vec2.DotVV(this.m_sweep.localCenter, this.m_sweep.localCenter); t.center.Copy(this.m_sweep.localCenter); return t; } SetMassData(t) { if (this.m_world.IsLocked()) { throw new Error; } if (this.m_type !== b2BodyType.b2_dynamicBody) { return; } this.m_invMass = 0; this.m_I = 0; this.m_invI = 0; this.m_mass = t.mass; if (this.m_mass <= 0) { this.m_mass = 1; } this.m_invMass = 1 / this.m_mass; if (t.I > 0 && !this.m_fixedRotationFlag) { this.m_I = t.I - this.m_mass * b2Vec2.DotVV(t.center, t.center); this.m_invI = 1 / this.m_I; } const i = b2Body.SetMassData_s_oldCenter.Copy(this.m_sweep.c); this.m_sweep.localCenter.Copy(t.center); b2Transform.MulXV(this.m_xf, this.m_sweep.localCenter, this.m_sweep.c); this.m_sweep.c0.Copy(this.m_sweep.c); b2Vec2.AddVCrossSV(this.m_linearVelocity, this.m_angularVelocity, b2Vec2.SubVV(this.m_sweep.c, i, b2Vec2.s_t0), this.m_linearVelocity); } ResetMassData() { 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 === b2BodyType.b2_staticBody || this.m_type === b2BodyType.b2_kinematicBody) { this.m_sweep.c0.Copy(this.m_xf.p); this.m_sweep.c.Copy(this.m_xf.p); this.m_sweep.a0 = this.m_sweep.a; return; } const t = b2Body.ResetMassData_s_localCenter.SetZero(); for (let i = this.m_fixtureList; i; i = i.m_next) { if (i.m_density === 0) { continue; } const s = i.GetMassData(b2Body.ResetMassData_s_massData); this.m_mass += s.mass; t.x += s.center.x * s.mass; t.y += s.center.y * s.mass; this.m_I += s.I; } if (this.m_mass > 0) { this.m_invMass = 1 / this.m_mass; t.x *= this.m_invMass; t.y *= this.m_invMass; } if (this.m_I > 0 && !this.m_fixedRotationFlag) { this.m_I -= this.m_mass * b2Vec2.DotVV(t, t); this.m_invI = 1 / this.m_I; } else { this.m_I = 0; this.m_invI = 0; } const i = b2Body.ResetMassData_s_oldCenter.Copy(this.m_sweep.c); this.m_sweep.localCenter.Copy(t); b2Transform.MulXV(this.m_xf, this.m_sweep.localCenter, this.m_sweep.c); this.m_sweep.c0.Copy(this.m_sweep.c); b2Vec2.AddVCrossSV(this.m_linearVelocity, this.m_angularVelocity, b2Vec2.SubVV(this.m_sweep.c, i, b2Vec2.s_t0), this.m_linearVelocity); } GetWorldPoint(t, i) { return b2Transform.MulXV(this.m_xf, t, i); } GetWorldVector(t, i) { return b2Rot.MulRV(this.m_xf.q, t, i); } GetLocalPoint(t, i) { return b2Transform.MulTXV(this.m_xf, t, i); } GetLocalVector(t, i) { return b2Rot.MulTRV(this.m_xf.q, t, i); } GetLinearVelocityFromWorldPoint(t, i) { return b2Vec2.AddVCrossSV(this.m_linearVelocity, this.m_angularVelocity, b2Vec2.SubVV(t, this.m_sweep.c, b2Vec2.s_t0), i); } GetLinearVelocityFromLocalPoint(t, i) { return this.GetLinearVelocityFromWorldPoint(this.GetWorldPoint(t, i), i); } GetLinearDamping() { return this.m_linearDamping; } SetLinearDamping(t) { this.m_linearDamping = t; } GetAngularDamping() { return this.m_angularDamping; } SetAngularDamping(t) { this.m_angularDamping = t; } GetGravityScale() { return this.m_gravityScale; } SetGravityScale(t) { this.m_gravityScale = t; } SetType(t) { if (this.m_world.IsLocked()) { throw new Error; } if (this.m_type === t) { return; } this.m_type = t; this.ResetMassData(); if (this.m_type === b2BodyType.b2_staticBody) { this.m_linearVelocity.SetZero(); this.m_angularVelocity = 0; this.m_sweep.a0 = this.m_sweep.a; this.m_sweep.c0.Copy(this.m_sweep.c); this.m_awakeFlag = false; this.SynchronizeFixtures(); } this.SetAwake(true); this.m_force.SetZero(); this.m_torque = 0; let i = this.m_contactList; while (i) { const t = i; i = i.next; this.m_world.m_contactManager.Destroy(t.contact); } this.m_contactList = null; for (let t = this.m_fixtureList; t; t = t.m_next) { t.TouchProxies(); } } GetType() { return this.m_type; } SetBullet(t) { this.m_bulletFlag = t; } IsBullet() { return this.m_bulletFlag; } SetSleepingAllowed(t) { this.m_autoSleepFlag = t; if (!t) { this.SetAwake(true); } } IsSleepingAllowed() { return this.m_autoSleepFlag; } SetAwake(t) { if (this.m_type === b2BodyType.b2_staticBody) { return; } if (t) { this.m_awakeFlag = true; this.m_sleepTime = 0; } else { this.m_awakeFlag = false; this.m_sleepTime = 0; this.m_linearVelocity.SetZero(); this.m_angularVelocity = 0; this.m_force.SetZero(); this.m_torque = 0; } } IsAwake() { return this.m_awakeFlag; } SetEnabled(t) { if (this.m_world.IsLocked()) { throw new Error; } if (t === this.IsEnabled()) { return; } this.m_enabledFlag = t; if (t) { for (let t = this.m_fixtureList; t; t = t.m_next) { t.CreateProxies(); } this.m_world.m_newContacts = true; } else { for (let t = this.m_fixtureList; t; t = t.m_next) { t.DestroyProxies(); } let t = this.m_contactList; while (t) { const i = t; t = t.next; this.m_world.m_contactManager.Destroy(i.contact); } this.m_contactList = null; } } IsEnabled() { return this.m_enabledFlag; } SetFixedRotation(t) { if (this.m_fixedRotationFlag === t) { return; } this.m_fixedRotationFlag = t; this.m_angularVelocity = 0; this.ResetMassData(); } IsFixedRotation() { return this.m_fixedRotationFlag; } GetFixtureList() { return this.m_fixtureList; } GetJointList() { return this.m_jointList; } GetContactList() { return this.m_contactList; } GetNext() { return this.m_next; } GetUserData() { return this.m_userData; } SetUserData(t) { this.m_userData = t; } GetWorld() { return this.m_world; } Dump(t) { const i = this.m_islandIndex; t("{\n"); t(" const bd: b2BodyDef = new b2BodyDef();\n"); let s = ""; switch (this.m_type) { case b2BodyType.b2_staticBody: s = "b2BodyType.b2_staticBody"; break; case b2BodyType.b2_kinematicBody: s = "b2BodyType.b2_kinematicBody"; break; case b2BodyType.b2_dynamicBody: s = "b2BodyType.b2_dynamicBody"; break; default: break; } t(" bd.type = %s;\n", s); t(" bd.position.Set(%.15f, %.15f);\n", this.m_xf.p.x, this.m_xf.p.y); t(" bd.angle = %.15f;\n", this.m_sweep.a); t(" bd.linearVelocity.Set(%.15f, %.15f);\n", this.m_linearVelocity.x, this.m_linearVelocity.y); t(" bd.angularVelocity = %.15f;\n", this.m_angularVelocity); t(" bd.linearDamping = %.15f;\n", this.m_linearDamping); t(" bd.angularDamping = %.15f;\n", this.m_angularDamping); t(" bd.allowSleep = %s;\n", this.m_autoSleepFlag ? "true" : "false"); t(" bd.awake = %s;\n", this.m_awakeFlag ? "true" : "false"); t(" bd.fixedRotation = %s;\n", this.m_fixedRotationFlag ? "true" : "false"); t(" bd.bullet = %s;\n", this.m_bulletFlag ? "true" : "false"); t(" bd.active = %s;\n", this.m_enabledFlag ? "true" : "false"); t(" bd.gravityScale = %.15f;\n", this.m_gravityScale); t("\n"); t(" bodies[%d] = this.m_world.CreateBody(bd);\n", this.m_islandIndex); t("\n"); for (let s = this.m_fixtureList; s; s = s.m_next) { t(" {\n"); s.Dump(t, i); t(" }\n"); } t("}\n"); } SynchronizeFixtures() { if (this.m_awakeFlag) { const t = b2Body.SynchronizeFixtures_s_xf1; t.q.SetAngle(this.m_sweep.a0); b2Rot.MulRV(t.q, this.m_sweep.localCenter, t.p); b2Vec2.SubVV(this.m_sweep.c0, t.p, t.p); for (let i = this.m_fixtureList; i; i = i.m_next) { i.SynchronizeProxies(t, this.m_xf); } } else { for (let t = this.m_fixtureList; t; t = t.m_next) { t.SynchronizeProxies(this.m_xf, this.m_xf); } } } SynchronizeTransform() { this.m_xf.q.SetAngle(this.m_sweep.a); b2Rot.MulRV(this.m_xf.q, this.m_sweep.localCenter, this.m_xf.p); b2Vec2.SubVV(this.m_sweep.c, this.m_xf.p, this.m_xf.p); } ShouldCollide(t) { if (this.m_type === b2BodyType.b2_staticBody && t.m_type === b2BodyType.b2_staticBody) { return false; } return this.ShouldCollideConnected(t); } ShouldCollideConnected(t) { for (let i = this.m_jointList; i; i = i.next) { if (i.other === t) { if (!i.joint.m_collideConnected) { return false; } } } return true; } Advance(t) { this.m_sweep.Advance(t); this.m_sweep.c.Copy(this.m_sweep.c0); this.m_sweep.a = this.m_sweep.a0; this.m_xf.q.SetAngle(this.m_sweep.a); b2Rot.MulRV(this.m_xf.q, this.m_sweep.localCenter, this.m_xf.p); b2Vec2.SubVV(this.m_sweep.c, this.m_xf.p, this.m_xf.p); } GetControllerList() { return this.m_controllerList; } GetControllerCount() { return this.m_controllerCount; } } b2Body.CreateFixtureShapeDensity_s_def = new b2FixtureDef; b2Body.SetMassData_s_oldCenter = new b2Vec2; b2Body.ResetMassData_s_localCenter = new b2Vec2; b2Body.ResetMassData_s_oldCenter = new b2Vec2; b2Body.ResetMassData_s_massData = new b2MassData; b2Body.SynchronizeFixtures_s_xf1 = new b2Transform;