UNPKG

@awayfl/awayfl-player

Version:

Flash Player emulator for executing SWF files (published for FP versions 6 and up) in javascript

1,248 lines (1,062 loc) 36.7 kB
import { b2EdgeShape } from '../Collision/Shapes/b2EdgeShape'; import { b2Math, b2Vec2, b2Transform, b2Mat22, b2Sweep } from '../Common/Math'; import { b2Settings } from '../Common/b2Settings'; import { b2BodyDef } from './b2BodyDef'; import { b2Fixture } from './b2Fixture'; import { b2FixtureDef } from './b2FixtureDef'; import { IBroadPhase } from '../Collision/IBroadPhase'; import { b2World } from './b2World'; import { b2Shape } from '../Collision/Shapes/b2Shape'; import { b2ContactEdge } from './Contacts'; import { b2Contact } from './Contacts'; import { b2JointEdge } from './Joints'; import { b2MassData } from '../Collision/Shapes/b2MassData'; import { b2ControllerEdge } from './Controllers/b2ControllerEdge'; /** * A rigid body. */ export class b2Body { __fast__ = true; private connectEdges(s1: b2EdgeShape, s2: b2EdgeShape, angle1: number): number { const angle2: number = Math.atan2(s2.GetDirectionVector().y, s2.GetDirectionVector().x); const coreOffset: number = Math.tan((angle2 - angle1) * 0.5); let core: b2Vec2 = b2Math.MulFV(coreOffset, s2.GetDirectionVector()); core = b2Math.SubtractVV(core, s2.GetNormalVector()); core = b2Math.MulFV(b2Settings.b2_toiSlop, core); core = b2Math.AddVV(core, s2.GetVertex1()); const cornerDir: b2Vec2 = b2Math.AddVV(s1.GetDirectionVector(), s2.GetDirectionVector()); cornerDir.Normalize(); const convex: boolean = b2Math.Dot(s1.GetDirectionVector(), s2.GetNormalVector()) > 0.0; s1.SetNextEdge(s2, core, cornerDir, convex); s2.SetPrevEdge(s1, core, cornerDir, convex); return angle2; } /** * Creates a fixture and attach it to this body. Use this function if you need * to set some fixture parameters, like friction. Otherwise you can create the * fixture directly from a shape. * If the density is non-zero, this function automatically updates the mass of the body. * Contacts are not created until the next time step. * @param fixtureDef the fixture definition. * @warning This function is locked during callbacks. */ public CreateFixture(def: b2FixtureDef): b2Fixture { //b2Settings.b2Assert(this.m_world.IsLocked() == false); if (this.m_world.IsLocked() == true) { return null; } // TODO: Decide on a better place to initialize edgeShapes. (b2Shape::Create() can't // return more than one shape to add to parent body... maybe it should add // shapes directly to the body instead of returning them?) /* if (def.type == b2Shape.e_edgeShape) { var edgeDef: b2EdgeChainDef = def as b2EdgeChainDef; var v1: b2Vec2; var v2: b2Vec2; var i: int; if (edgeDef.isALoop) { v1 = edgeDef.vertices[edgeDef.vertexCount-1]; i = 0; } else { v1 = edgeDef.vertices[0]; i = 1; } var s0: b2EdgeShape = null; var s1: b2EdgeShape = null; var s2: b2EdgeShape = null; var angle: number = 0.0; for (; i < edgeDef.vertexCount; i++) { v2 = edgeDef.vertices[i]; //void* mem = this.m_world->m_blockAllocator.Allocate(sizeof(b2EdgeShape)); s2 = new b2EdgeShape(v1, v2, def); s2.this.m_next = m_shapeList; m_shapeList = s2; ++m_shapeCount; s2.m_body = this; s2.CreateProxy(this.m_world.m_broadPhase, this.m_xf); s2.UpdateSweepRadius(this.m_sweep.localCenter); if (s1 == null) { s0 = s2; angle = Math.atan2(s2.GetDirectionVector().y, s2.GetDirectionVector().x); } else { angle = connectEdges(s1, s2, angle); } s1 = s2; v1 = v2; } if (edgeDef.isALoop) connectEdges(s1, s0, angle); return s0; }*/ const fixture: b2Fixture = new b2Fixture(); fixture.Create(this, this.m_xf, def); if (this.m_flags & b2Body.e_activeFlag) { const broadPhase: IBroadPhase = this.m_world.m_contactManager.m_broadPhase; fixture.CreateProxy(broadPhase, this.m_xf); } fixture.m_next = this.m_fixtureList; this.m_fixtureList = fixture; ++this.m_fixtureCount; fixture.m_body = this; // Adjust mass properties if needed if (fixture.m_density > 0.0) { this.ResetMassData(); } // Let the world know we have a new fixture. This will cause new contacts to be created // at the beginning of the next time step. this.m_world.m_flags |= b2World.e_newFixture; return fixture; } /** * Creates a fixture from a shape and attach it to this body. * This is a convenience function. Use b2FixtureDef if you need to set parameters * like friction, restitution, user data, or filtering. * This function automatically updates the mass of the body. * @param shape the shape to be cloned. * @param density the shape density (set to zero for static bodies). * @warning This function is locked during callbacks. */ public CreateFixture2(shape: b2Shape, density: number = 0.0): b2Fixture { const def: b2FixtureDef = new b2FixtureDef(); def.shape = shape; def.density = density; return this.CreateFixture(def); } /** * Destroy a fixture. This removes the fixture from the broad-phase and * destroys all contacts associated with this fixture. This will * automatically adjust the mass of the body if the body is dynamic and the * fixture has positive density. * All fixtures attached to a body are implicitly destroyed when the body is destroyed. * @param fixture the fixture to be removed. * @warning This function is locked during callbacks. */ public DestroyFixture(fixture: b2Fixture): void { //b2Settings.b2Assert(this.m_world.IsLocked() == false); if (this.m_world.IsLocked() == true) { return; } //b2Settings.b2Assert(this.m_fixtureCount > 0); //b2Fixture** node = &this.m_fixtureList; let node: b2Fixture = this.m_fixtureList; let ppF: b2Fixture = null; // Fix pointer-pointer stuff let found: boolean = false; while (node != null) { if (node == fixture) { if (ppF) ppF.m_next = fixture.m_next; else this.m_fixtureList = fixture.m_next; //node = fixture.this.m_next; found = true; break; } ppF = node; node = node.m_next; } // You tried to remove a shape that is not attached to this body. //b2Settings.b2Assert(found); // Destroy any contacts associated with the fixture. let edge: b2ContactEdge = this.m_contactList; while (edge) { const c: b2Contact = edge.contact; edge = edge.next; const fixtureA: b2Fixture = c.GetFixtureA(); const fixtureB: b2Fixture = c.GetFixtureB(); if (fixture == fixtureA || fixture == fixtureB) { // This destros the contact and removes it from // this body's contact list this.m_world.m_contactManager.Destroy(c); } } if (this.m_flags & b2Body.e_activeFlag) { const broadPhase: IBroadPhase = this.m_world.m_contactManager.m_broadPhase; fixture.DestroyProxy(broadPhase); } else { //b2Assert(fixture->m_proxyId == b2BroadPhase::e_nullProxy); } fixture.Destroy(); fixture.m_body = null; fixture.m_next = null; --this.m_fixtureCount; // Reset the mass data. this.ResetMassData(); } /** * Set the position of the body's origin and rotation (radians). * This breaks any contacts and wakes the other bodies. * @param position the new world position of the body's origin (not necessarily * the center of mass). * @param angle the new world rotation angle of the body in radians. */ public SetPositionAndAngle(position: b2Vec2, angle: number): void { let f: b2Fixture; //b2Settings.b2Assert(this.m_world.IsLocked() == false); if (this.m_world.IsLocked() == true) { return; } this.m_xf.R.Set(angle); this.m_xf.position.SetV(position); //this.m_sweep.c0 = this.m_sweep.c = b2Mul(this.m_xf, this.m_sweep.localCenter); //b2MulMV(this.m_xf.R, this.m_sweep.localCenter); const tMat: b2Mat22 = this.m_xf.R; const tVec: b2Vec2 = this.m_sweep.localCenter; // (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y) this.m_sweep.c.x = (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); // (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y) this.m_sweep.c.y = (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); //return T.position + b2Mul(T.R, v); this.m_sweep.c.x += this.m_xf.position.x; this.m_sweep.c.y += this.m_xf.position.y; //this.m_sweep.c0 = this.m_sweep.c this.m_sweep.c0.SetV(this.m_sweep.c); this.m_sweep.a0 = this.m_sweep.a = angle; const broadPhase: IBroadPhase = this.m_world.m_contactManager.m_broadPhase; for (f = this.m_fixtureList; f; f = f.m_next) { f.Synchronize(broadPhase, this.m_xf, this.m_xf); } this.m_world.m_contactManager.FindNewContacts(); } /** * Set the position of the body's origin and rotation (radians). * This breaks any contacts and wakes the other bodies. * Note this is less efficient than the other overload - you should use that * if the angle is available. * @param xf the transform of position and angle to set the bdoy to. */ public SetTransform(xf: b2Transform): void { this.SetPositionAndAngle(xf.position, xf.GetAngle()); } /** * Get the body transform for the body's origin. * @return the world transform of the body's origin. */ public GetTransform(): b2Transform { return this.m_xf; } /** * Get the world body origin position. * @return the world position of the body's origin. */ public GetPosition(): b2Vec2 { return this.m_xf.position; } /** * Setthe world body origin position. * @param position the new position of the body */ public SetPosition(position: b2Vec2): void { this.SetPositionAndAngle(position, this.GetAngle()); } /** * Get the angle in radians. * @return the current world rotation angle in radians. */ public GetAngle(): number { return this.m_sweep.a; } /** * Set the world body angle * @param angle the new angle of the body. */ public SetAngle(angle: number): void { this.SetPositionAndAngle(this.GetPosition(), angle); } /** * Get the world position of the center of mass. */ public GetWorldCenter(): b2Vec2 { return this.m_sweep.c; } /** * Get the local position of the center of mass. */ public GetLocalCenter(): b2Vec2 { return this.m_sweep.localCenter; } /** * Set the linear velocity of the center of mass. * @param v the new linear velocity of the center of mass. */ public SetLinearVelocity(v: b2Vec2): void { if (this.m_type == b2Body.b2_staticBody) { return; } this.m_linearVelocity.SetV(v); } /** * Get the linear velocity of the center of mass. * @return the linear velocity of the center of mass. */ public GetLinearVelocity(): b2Vec2 { return this.m_linearVelocity; } /** * Set the angular velocity. * @param omega the new angular velocity in radians/second. */ public SetAngularVelocity(omega: number): void { if (this.m_type == b2Body.b2_staticBody) { return; } this.m_angularVelocity = omega; } /** * Get the angular velocity. * @return the angular velocity in radians/second. */ public GetAngularVelocity(): number { return this.m_angularVelocity; } /** * Get the definition containing the body properties. * @asonly */ public GetDefinition(): b2BodyDef { const bd: b2BodyDef = new b2BodyDef(); bd.type = this.GetType(); bd.allowSleep = (this.m_flags & b2Body.e_allowSleepFlag) == b2Body.e_allowSleepFlag; bd.angle = this.GetAngle(); bd.angularDamping = this.m_angularDamping; bd.angularVelocity = this.m_angularVelocity; bd.fixedRotation = (this.m_flags & b2Body.e_fixedRotationFlag) == b2Body.e_fixedRotationFlag; bd.bullet = (this.m_flags & b2Body.e_bulletFlag) == b2Body.e_bulletFlag; bd.awake = (this.m_flags & b2Body.e_awakeFlag) == b2Body.e_awakeFlag; bd.linearDamping = this.m_linearDamping; bd.linearVelocity.SetV(this.GetLinearVelocity()); bd.position = this.GetPosition(); bd.userData = this.GetUserData(); return bd; } /** * Apply a force at a world point. If the force is not * applied at the center of mass, it will generate a torque and * affect the angular velocity. This wakes up the body. * @param force the world force vector, usually in Newtons (N). * @param point the world position of the point of application. */ public ApplyForce(force: b2Vec2, point: b2Vec2): void { if (this.m_type != b2Body.b2_dynamicBody) { return; } if (this.IsAwake() == false) { this.SetAwake(true); } //this.m_force += force; this.m_force.x += force.x; this.m_force.y += force.y; //this.m_torque += b2Cross(point - this.m_sweep.c, force); this.m_torque += ((point.x - this.m_sweep.c.x) * force.y - (point.y - this.m_sweep.c.y) * force.x); } /** * Apply a torque. This affects the angular velocity * without affecting the linear velocity of the center of mass. * This wakes up the body. * @param torque about the z-axis (out of the screen), usually in N-m. */ public ApplyTorque(torque: number): void { if (this.m_type != b2Body.b2_dynamicBody) { return; } if (this.IsAwake() == false) { this.SetAwake(true); } this.m_torque += torque; } /** * Apply an impulse at a point. This immediately modifies the velocity. * It also modifies the angular velocity if the point of application * is not at the center of mass. This wakes up the body. * @param impulse the world impulse vector, usually in N-seconds or kg-m/s. * @param point the world position of the point of application. */ public ApplyImpulse(impulse: b2Vec2, point: b2Vec2): void { if (this.m_type != b2Body.b2_dynamicBody) { return; } if (this.IsAwake() == false) { this.SetAwake(true); } //this.m_linearVelocity += this.m_invMass * impulse; this.m_linearVelocity.x += this.m_invMass * impulse.x; this.m_linearVelocity.y += this.m_invMass * impulse.y; //this.m_angularVelocity += this.m_invI * b2Cross(point - this.m_sweep.c, impulse); this.m_angularVelocity += this.m_invI * ((point.x - this.m_sweep.c.x) * impulse.y - (point.y - this.m_sweep.c.y) * impulse.x); } /** * Splits a body into two, preserving dynamic properties * @param callback Called once per fixture, return true to move this fixture to the new body * <code>function Callback(fixture:b2Fixture):boolean</code> * @return The newly created bodies * @asonly */ public Split(callback: Function): b2Body { const linearVelocity: b2Vec2 = this.GetLinearVelocity().Copy();//Reset mass will alter this const angularVelocity: number = this.GetAngularVelocity(); const center: b2Vec2 = this.GetWorldCenter(); const body1: b2Body = this; const body2: b2Body = this.m_world.CreateBody(this.GetDefinition()); let prev: b2Fixture; for (let f: b2Fixture = body1.m_fixtureList; f;) { if (callback(f)) { const next: b2Fixture = f.m_next; // Remove fixture if (prev) { prev.m_next = next; } else { body1.m_fixtureList = next; } body1.m_fixtureCount--; // Add fixture f.m_next = body2.m_fixtureList; body2.m_fixtureList = f; body2.m_fixtureCount++; f.m_body = body2; f = next; } else { prev = f; f = f.m_next; } } body1.ResetMassData(); body2.ResetMassData(); // Compute consistent velocites for new bodies based on cached velocity const center1: b2Vec2 = body1.GetWorldCenter(); const center2: b2Vec2 = body2.GetWorldCenter(); const velocity1: b2Vec2 = b2Math.AddVV(linearVelocity, b2Math.CrossFV(angularVelocity, b2Math.SubtractVV(center1, center))); const velocity2: b2Vec2 = b2Math.AddVV(linearVelocity, b2Math.CrossFV(angularVelocity, b2Math.SubtractVV(center2, center))); body1.SetLinearVelocity(velocity1); body2.SetLinearVelocity(velocity2); body1.SetAngularVelocity(angularVelocity); body2.SetAngularVelocity(angularVelocity); body1.SynchronizeFixtures(); body2.SynchronizeFixtures(); return body2; } /** * Merges another body into this. Only fixtures, mass and velocity are effected, * Other properties are ignored * @asonly */ public Merge(other: b2Body): void { let f: b2Fixture; for (f = other.m_fixtureList; f;) { const next: b2Fixture = f.m_next; // Remove fixture other.m_fixtureCount--; // Add fixture f.m_next = this.m_fixtureList; this.m_fixtureList = f; this.m_fixtureCount++; f.m_body = body2; f = next; } body1.m_fixtureCount = 0; // Recalculate velocities var body1: b2Body = this; var body2: b2Body = other; // Compute consistent velocites for new bodies based on cached velocity const center1: b2Vec2 = body1.GetWorldCenter(); const center2: b2Vec2 = body2.GetWorldCenter(); const velocity1: b2Vec2 = body1.GetLinearVelocity().Copy(); const velocity2: b2Vec2 = body2.GetLinearVelocity().Copy(); const angular1: number = body1.GetAngularVelocity(); const angular: number = body2.GetAngularVelocity(); // TODO body1.ResetMassData(); this.SynchronizeFixtures(); } /** * Get the total mass of the body. * @return the mass, usually in kilograms (kg). */ public GetMass(): number { return this.m_mass; } /** * Get the central rotational inertia of the body. * @return the rotational inertia, usually in kg-m^2. */ public GetInertia(): number { return this.m_I; } /** * Get the mass data of the body. The rotational inertial is relative to the center of mass. */ public GetMassData(data: b2MassData): void { data.mass = this.m_mass; data.I = this.m_I; data.center.SetV(this.m_sweep.localCenter); } /** * Set the mass properties to override the mass properties of the fixtures * Note that this changes the center of mass position. * Note that creating or destroying fixtures can also alter the mass. * This function has no effect if the body isn't dynamic. * @warning The supplied rotational inertia should be relative to the center of mass * @param data the mass properties. */ public SetMassData(massData: b2MassData): void { b2Settings.b2Assert(this.m_world.IsLocked() == false); if (this.m_world.IsLocked() == true) { return; } if (this.m_type != b2Body.b2_dynamicBody) { return; } this.m_invMass = 0.0; this.m_I = 0.0; this.m_invI = 0.0; this.m_mass = massData.mass; // Compute the center of mass. if (this.m_mass <= 0.0) { this.m_mass = 1.0; } this.m_invMass = 1.0 / this.m_mass; if (massData.I > 0.0 && (this.m_flags & b2Body.e_fixedRotationFlag) == 0) { // Center the inertia about the center of mass this.m_I = massData.I - this.m_mass * (massData.center.x * massData.center.x + massData.center.y * massData.center.y); this.m_invI = 1.0 / this.m_I; } // Move center of mass const oldCenter: b2Vec2 = this.m_sweep.c.Copy(); this.m_sweep.localCenter.SetV(massData.center); this.m_sweep.c0.SetV(b2Math.MulX(this.m_xf, this.m_sweep.localCenter)); this.m_sweep.c.SetV(this.m_sweep.c0); // Update center of mass velocity //this.m_linearVelocity += b2Cross(this.m_angularVelocity, this.m_sweep.c - oldCenter); this.m_linearVelocity.x += this.m_angularVelocity * -(this.m_sweep.c.y - oldCenter.y); this.m_linearVelocity.y += this.m_angularVelocity * +(this.m_sweep.c.x - oldCenter.x); } /** * This resets the mass properties to the sum of the mass properties of the fixtures. * This normally does not need to be called unless you called SetMassData to override * the mass and later you want to reset the mass. */ public ResetMassData(): void { // Compute mass data from shapes. Each shape has it's own density this.m_mass = 0.0; this.m_invMass = 0.0; this.m_I = 0.0; this.m_invI = 0.0; this.m_sweep.localCenter.SetZero(); // Static and kinematic bodies have zero mass. if (this.m_type == b2Body.b2_staticBody || this.m_type == b2Body.b2_kinematicBody) { return; } //b2Assert(this.m_type == b2Body.b2_dynamicBody); // Accumulate mass over all fixtures. const center: b2Vec2 = b2Vec2.Make(0, 0); for (let f: b2Fixture = this.m_fixtureList; f; f = f.m_next) { if (f.m_density == 0.0) { continue; } const massData: b2MassData = f.GetMassData(); this.m_mass += massData.mass; center.x += massData.center.x * massData.mass; center.y += massData.center.y * massData.mass; this.m_I += massData.I; } // Compute the center of mass. if (this.m_mass > 0.0) { this.m_invMass = 1.0 / this.m_mass; center.x *= this.m_invMass; center.y *= this.m_invMass; } else { // Force all dynamic bodies to have a positive mass. this.m_mass = 1.0; this.m_invMass = 1.0; } if (this.m_I > 0.0 && (this.m_flags & b2Body.e_fixedRotationFlag) == 0) { // Center the inertia about the center of mass this.m_I -= this.m_mass * (center.x * center.x + center.y * center.y); this.m_I *= this.m_inertiaScale; b2Settings.b2Assert(this.m_I > 0); this.m_invI = 1.0 / this.m_I; } else { this.m_I = 0.0; this.m_invI = 0.0; } // Move center of mass const oldCenter: b2Vec2 = this.m_sweep.c.Copy(); this.m_sweep.localCenter.SetV(center); this.m_sweep.c0.SetV(b2Math.MulX(this.m_xf, this.m_sweep.localCenter)); this.m_sweep.c.SetV(this.m_sweep.c0); // Update center of mass velocity //this.m_linearVelocity += b2Cross(this.m_angularVelocity, this.m_sweep.c - oldCenter); this.m_linearVelocity.x += this.m_angularVelocity * -(this.m_sweep.c.y - oldCenter.y); this.m_linearVelocity.y += this.m_angularVelocity * +(this.m_sweep.c.x - oldCenter.x); } /** * Get the world coordinates of a point given the local coordinates. * @param localPoint a point on the body measured relative the the body's origin. * @return the same point expressed in world coordinates. */ public GetWorldPoint(localPoint: b2Vec2): b2Vec2 { //return b2Math.b2MulX(this.m_xf, localPoint); const A: b2Mat22 = this.m_xf.R; const u: b2Vec2 = new b2Vec2(A.col1.x * localPoint.x + A.col2.x * localPoint.y, A.col1.y * localPoint.x + A.col2.y * localPoint.y); u.x += this.m_xf.position.x; u.y += this.m_xf.position.y; return u; } /** * Get the world coordinates of a vector given the local coordinates. * @param localVector a vector fixed in the body. * @return the same vector expressed in world coordinates. */ public GetWorldVector(localVector: b2Vec2): b2Vec2 { return b2Math.MulMV(this.m_xf.R, localVector); } /** * Gets a local point relative to the body's origin given a world point. * @param a point in world coordinates. * @return the corresponding local point relative to the body's origin. */ public GetLocalPoint(worldPoint: b2Vec2): b2Vec2 { return b2Math.MulXT(this.m_xf, worldPoint); } /** * Gets a local vector given a world vector. * @param a vector in world coordinates. * @return the corresponding local vector. */ public GetLocalVector(worldVector: b2Vec2): b2Vec2 { return b2Math.MulTMV(this.m_xf.R, worldVector); } /** * Get the world linear velocity of a world point attached to this body. * @param a point in world coordinates. * @return the world velocity of a point. */ public GetLinearVelocityFromWorldPoint(worldPoint: b2Vec2): b2Vec2 { //return this.m_linearVelocity + b2Cross(this.m_angularVelocity, worldPoint - this.m_sweep.c); return new b2Vec2(this.m_linearVelocity.x - this.m_angularVelocity * (worldPoint.y - this.m_sweep.c.y), this.m_linearVelocity.y + this.m_angularVelocity * (worldPoint.x - this.m_sweep.c.x)); } /** * Get the world velocity of a local point. * @param a point in local coordinates. * @return the world velocity of a point. */ public GetLinearVelocityFromLocalPoint(localPoint: b2Vec2): b2Vec2 { //return GetLinearVelocityFromWorldPoint(GetWorldPoint(localPoint)); const A: b2Mat22 = this.m_xf.R; const worldPoint: b2Vec2 = new b2Vec2(A.col1.x * localPoint.x + A.col2.x * localPoint.y, A.col1.y * localPoint.x + A.col2.y * localPoint.y); worldPoint.x += this.m_xf.position.x; worldPoint.y += this.m_xf.position.y; return new b2Vec2(this.m_linearVelocity.x - this.m_angularVelocity * (worldPoint.y - this.m_sweep.c.y), this.m_linearVelocity.y + this.m_angularVelocity * (worldPoint.x - this.m_sweep.c.x)); } /** * Get the linear damping of the body. */ public GetLinearDamping(): number { return this.m_linearDamping; } /** * Set the linear damping of the body. */ public SetLinearDamping(linearDamping: number): void { this.m_linearDamping = linearDamping; } /** * Get the angular damping of the body */ public GetAngularDamping(): number { return this.m_angularDamping; } /** * Set the angular damping of the body. */ public SetAngularDamping(angularDamping: number): void { this.m_angularDamping = angularDamping; } /** * Set the type of this body. This may alter the mass and velocity * @param type - enum stored as a static member of b2Body */ public SetType(type: number /** uint */): void { if (this.m_type == type) { return; } this.m_type = type; this.ResetMassData(); if (this.m_type == b2Body.b2_staticBody) { this.m_linearVelocity.SetZero(); this.m_angularVelocity = 0.0; } this.SetAwake(true); this.m_force.SetZero(); this.m_torque = 0.0; // Since the body type changed, we need to flag contacts for filtering. for (let ce: b2ContactEdge = this.m_contactList; ce; ce = ce.next) { ce.contact.FlagForFiltering(); } } /** * Get the type of this body. * @return type enum as a uint */ public GetType(): number /** uint */ { return this.m_type; } /** * Should this body be treated like a bullet for continuous collision detection? */ public SetBullet(flag: boolean): void { if (flag) { this.m_flags |= b2Body.e_bulletFlag; } else { this.m_flags &= ~b2Body.e_bulletFlag; } } /** * Is this body treated like a bullet for continuous collision detection? */ public IsBullet(): Boolean { return (this.m_flags & b2Body.e_bulletFlag) == b2Body.e_bulletFlag; } /** * Is this body allowed to sleep * @param flag */ public SetSleepingAllowed(flag: boolean): void { if (flag) { this.m_flags |= b2Body.e_allowSleepFlag; } else { this.m_flags &= ~b2Body.e_allowSleepFlag; this.SetAwake(true); } } /** * Set the sleep state of the body. A sleeping body has vety low CPU cost. * @param flag - set to true to put body to sleep, false to wake it */ public SetAwake(flag: boolean): void { if (flag) { this.m_flags |= b2Body.e_awakeFlag; this.m_sleepTime = 0.0; } else { this.m_flags &= ~b2Body.e_awakeFlag; this.m_sleepTime = 0.0; this.m_linearVelocity.SetZero(); this.m_angularVelocity = 0.0; this.m_force.SetZero(); this.m_torque = 0.0; } } /** * Get the sleeping state of this body. * @return true if body is sleeping */ public IsAwake(): boolean { return (this.m_flags & b2Body.e_awakeFlag) == b2Body.e_awakeFlag; } /** * Set this body to have fixed rotation. This causes the mass to be reset. * @param fixed - true means no rotation */ public SetFixedRotation(fixed: boolean): void { if (fixed) { this.m_flags |= b2Body.e_fixedRotationFlag; } else { this.m_flags &= ~b2Body.e_fixedRotationFlag; } this.ResetMassData(); } /** * Does this body have fixed rotation? * @return true means fixed rotation */ public IsFixedRotation(): boolean { return (this.m_flags & b2Body.e_fixedRotationFlag) == b2Body.e_fixedRotationFlag; } /** Set the active state of the body. An inactive body is not * simulated and cannot be collided with or woken up. * If you pass a flag of true, all fixtures will be added to the * broad-phase. * If you pass a flag of false, all fixtures will be removed from * the broad-phase and all contacts will be destroyed. * Fixtures and joints are otherwise unaffected. You may continue * to create/destroy fixtures and joints on inactive bodies. * Fixtures on an inactive body are implicitly inactive and will * not participate in collisions, ray-casts, or queries. * Joints connected to an inactive body are implicitly inactive. * An inactive body is still owned by a b2World object and remains * in the body list. */ public SetActive(flag: boolean): void { if (flag == this.IsActive()) { return; } let broadPhase: IBroadPhase; let f: b2Fixture; if (flag) { this.m_flags |= b2Body.e_activeFlag; // Create all proxies. broadPhase = this.m_world.m_contactManager.m_broadPhase; for (f = this.m_fixtureList; f; f = f.m_next) { f.CreateProxy(broadPhase, this.m_xf); } // Contacts are created the next time step. } else { this.m_flags &= ~b2Body.e_activeFlag; // Destroy all proxies. broadPhase = this.m_world.m_contactManager.m_broadPhase; for (f = this.m_fixtureList; f; f = f.m_next) { f.DestroyProxy(broadPhase); } // Destroy the attached contacts. let ce: b2ContactEdge = this.m_contactList; while (ce) { const ce0: b2ContactEdge = ce; ce = ce.next; this.m_world.m_contactManager.Destroy(ce0.contact); } this.m_contactList = null; } } /** * Get the active state of the body. * @return true if active. */ public IsActive(): boolean { return (this.m_flags & b2Body.e_activeFlag) == b2Body.e_activeFlag; } /** * Is this body allowed to sleep? */ public IsSleepingAllowed(): boolean { return (this.m_flags & b2Body.e_allowSleepFlag) == b2Body.e_allowSleepFlag; } /** * Get the list of all fixtures attached to this body. */ public GetFixtureList(): b2Fixture { return this.m_fixtureList; } /** * Get the list of all joints attached to this body. */ public GetJointList(): b2JointEdge { return this.m_jointList; } /** * Get the list of all controllers attached to this body. */ public GetControllerList(): b2ControllerEdge { return this.m_controllerList; } /** * Get a list of all contacts attached to this body. */ public GetContactList(): b2ContactEdge { return this.m_contactList; } /** * Get the next body in the world's body list. */ public GetNext(): b2Body { return this.m_next; } /** * Get the user data pointer that was provided in the body definition. */ public GetUserData(): any { return this.m_userData; } /** * Set the user data. Use this to store your application specific data. */ public SetUserData(data: any): void { this.m_userData = data; } /** * Get the parent world of this body. */ public GetWorld(): b2World { return this.m_world; } //--------------- Internals Below ------------------- // Constructor /** * @private */ constructor(bd: b2BodyDef, world: b2World) { //b2Settings.b2Assert(world.IsLocked() == false); //b2Settings.b2Assert(bd.position.IsValid()); //b2Settings.b2Assert(bd.linearVelocity.IsValid()); //b2Settings.b2Assert(b2Math.b2IsValid(bd.angle)); //b2Settings.b2Assert(b2Math.b2IsValid(bd.angularVelocity)); //b2Settings.b2Assert(b2Math.b2IsValid(bd.inertiaScale) && bd.inertiaScale >= 0.0); //b2Settings.b2Assert(b2Math.b2IsValid(bd.angularDamping) && bd.angularDamping >= 0.0); //b2Settings.b2Assert(b2Math.b2IsValid(bd.linearDamping) && bd.linearDamping >= 0.0); this.m_flags = 0; if (bd.bullet) { this.m_flags |= b2Body.e_bulletFlag; } if (bd.fixedRotation) { this.m_flags |= b2Body.e_fixedRotationFlag; } if (bd.allowSleep) { this.m_flags |= b2Body.e_allowSleepFlag; } if (bd.awake) { this.m_flags |= b2Body.e_awakeFlag; } if (bd.active) { this.m_flags |= b2Body.e_activeFlag; } this.m_world = world; this.m_xf.position.SetV(bd.position); this.m_xf.R.Set(bd.angle); this.m_sweep.localCenter.SetZero(); this.m_sweep.t0 = 1.0; this.m_sweep.a0 = this.m_sweep.a = bd.angle; //this.m_sweep.c0 = this.m_sweep.c = b2Mul(this.m_xf, this.m_sweep.localCenter); //b2MulMV(this.m_xf.R, this.m_sweep.localCenter); const tMat: b2Mat22 = this.m_xf.R; const tVec: b2Vec2 = this.m_sweep.localCenter; // (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y) this.m_sweep.c.x = (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); // (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y) this.m_sweep.c.y = (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); //return T.position + b2Mul(T.R, v); this.m_sweep.c.x += this.m_xf.position.x; this.m_sweep.c.y += this.m_xf.position.y; //this.m_sweep.c0 = this.m_sweep.c this.m_sweep.c0.SetV(this.m_sweep.c); this.m_jointList = null; this.m_controllerList = null; this.m_contactList = null; this.m_controllerCount = 0; this.m_prev = null; this.m_next = null; this.m_linearVelocity.SetV(bd.linearVelocity); this.m_angularVelocity = bd.angularVelocity; this.m_linearDamping = bd.linearDamping; this.m_angularDamping = bd.angularDamping; this.m_force.Set(0.0, 0.0); this.m_torque = 0.0; this.m_sleepTime = 0.0; this.m_type = bd.type; if (this.m_type == b2Body.b2_dynamicBody) { this.m_mass = 1.0; this.m_invMass = 1.0; } else { this.m_mass = 0.0; this.m_invMass = 0.0; } this.m_I = 0.0; this.m_invI = 0.0; this.m_inertiaScale = bd.inertiaScale; this.m_userData = bd.userData; this.m_fixtureList = null; this.m_fixtureCount = 0; } // Destructor //~b2Body(); // private static s_xf1: b2Transform = new b2Transform(); // public SynchronizeFixtures(): void { const xf1: b2Transform = b2Body.s_xf1; xf1.R.Set(this.m_sweep.a0); //xf1.position = this.m_sweep.c0 - b2Mul(xf1.R, this.m_sweep.localCenter); const tMat: b2Mat22 = xf1.R; const tVec: b2Vec2 = this.m_sweep.localCenter; xf1.position.x = this.m_sweep.c0.x - (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); xf1.position.y = this.m_sweep.c0.y - (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); let f: b2Fixture; const broadPhase: IBroadPhase = this.m_world.m_contactManager.m_broadPhase; for (f = this.m_fixtureList; f; f = f.m_next) { f.Synchronize(broadPhase, xf1, this.m_xf); } } public SynchronizeTransform(): void { this.m_xf.R.Set(this.m_sweep.a); //this.m_xf.position = this.m_sweep.c - b2Mul(this.m_xf.R, this.m_sweep.localCenter); const tMat: b2Mat22 = this.m_xf.R; const tVec: b2Vec2 = this.m_sweep.localCenter; this.m_xf.position.x = this.m_sweep.c.x - (tMat.col1.x * tVec.x + tMat.col2.x * tVec.y); this.m_xf.position.y = this.m_sweep.c.y - (tMat.col1.y * tVec.x + tMat.col2.y * tVec.y); } // This is used to prevent connected bodies from colliding. // It may lie, depending on the collideConnected flag. public ShouldCollide(other: b2Body): Boolean { // At least one body should be dynamic if (this.m_type != b2Body.b2_dynamicBody && other.m_type != b2Body.b2_dynamicBody) { return false; } // Does a joint prevent collision? for (let jn: b2JointEdge = this.m_jointList; jn; jn = jn.next) { if (jn.other == other) if (jn.joint.m_collideConnected == false) { return false; } } return true; } public Advance(t: number): void { // Advance to the new safe time. this.m_sweep.Advance(t); this.m_sweep.c.SetV(this.m_sweep.c0); this.m_sweep.a = this.m_sweep.a0; this.SynchronizeTransform(); } public m_flags: number /** uint */; public m_type: number /** int */; public m_islandIndex: number /** int */; public m_xf: b2Transform = new b2Transform(); // the body origin transform public m_sweep: b2Sweep = new b2Sweep(); // the swept motion for CCD public m_linearVelocity: b2Vec2 = new b2Vec2(); public m_angularVelocity: number; public m_force: b2Vec2 = new b2Vec2(); public m_torque: number; public m_world: b2World; public m_prev: b2Body; public m_next: b2Body; public m_fixtureList: b2Fixture; public m_fixtureCount: number /** int */; public m_controllerList: b2ControllerEdge; public m_controllerCount: number /** int */; public m_jointList: b2JointEdge; public m_contactList: b2ContactEdge; public m_mass: number; public m_invMass: number; public m_I: number public m_invI: number; public m_inertiaScale: number; public m_linearDamping: number; public m_angularDamping: number; public m_sleepTime: number; private m_userData: any; // m_flags //enum //{ public static e_islandFlag: number /** uint */ = 0x0001; public static e_awakeFlag: number /** uint */ = 0x0002; public static e_allowSleepFlag: number /** uint */ = 0x0004; public static e_bulletFlag: number /** uint */ = 0x0008; public static e_fixedRotationFlag: number /** uint */ = 0x0010; public static e_activeFlag: number /** uint */ = 0x0020; //}; // this.m_type //enum //{ /// The body type. /// static: zero mass, zero velocity, may be manually moved /// kinematic: zero mass, non-zero velocity set by user, moved by solver /// dynamic: positive mass, non-zero velocity determined by forces, moved by solver public static b2_staticBody: number /** uint */ = 0; public static b2_kinematicBody: number /** uint */ = 1; public static b2_dynamicBody: number /** uint */ = 2; //}; }