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