/*******************************************************************************
* Copyright (c) 2011, Daniel Murphy
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* * Neither the name of the <organization> nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL DANIEL MURPHY BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
******************************************************************************/
package org.jbox2d.dynamics;
import org.jbox2d.collision.broadphase.BroadPhase;
import org.jbox2d.collision.shapes.MassData;
import org.jbox2d.collision.shapes.Shape;
import org.jbox2d.common.Mat22;
import org.jbox2d.common.MathUtils;
import org.jbox2d.common.Sweep;
import org.jbox2d.common.Transform;
import org.jbox2d.common.Vec2;
import org.jbox2d.dynamics.contacts.Contact;
import org.jbox2d.dynamics.contacts.ContactEdge;
import org.jbox2d.dynamics.joints.JointEdge;
// updated to rev 100
// thead safe pooling
/**
* A rigid body. These are created via World.createBody.
*
* @author Daniel Murphy
*/
public class Body {
public static final int e_islandFlag = 0x0001;
public static final int e_awakeFlag = 0x0002;
public static final int e_autoSleepFlag = 0x0004;
public static final int e_bulletFlag = 0x0008;
public static final int e_fixedRotationFlag = 0x0010;
public static final int e_activeFlag = 0x0020;
public static final int e_toiFlag = 0x0040;
public BodyType m_type;
public int m_flags;
public int m_islandIndex;
/**
* The body origin transform.
*/
public final Transform m_xf = new Transform();
/**
* The swept motion for CCD
*/
public final Sweep m_sweep = new Sweep();
public final Vec2 m_linearVelocity = new Vec2();
public float m_angularVelocity = 0;
public final Vec2 m_force = new Vec2();
public float m_torque = 0;
public World m_world;
public Body m_prev;
public Body m_next;
public Fixture m_fixtureList;
public int m_fixtureCount;
public JointEdge m_jointList;
public ContactEdge m_contactList;
public float m_mass, m_invMass;
// Rotational inertia about the center of mass.
public float m_I, m_invI;
public float m_linearDamping;
public float m_angularDamping;
public float m_sleepTime;
public Object m_userData;
public Body(final BodyDef bd, World world) {
assert (bd.position.isValid());
assert (bd.linearVelocity.isValid());
assert (bd.inertiaScale >= 0.0f);
assert (bd.angularDamping >= 0.0f);
assert (bd.linearDamping >= 0.0f);
m_flags = 0;
if (bd.bullet) {
m_flags |= e_bulletFlag;
}
if (bd.fixedRotation) {
m_flags |= e_fixedRotationFlag;
}
if (bd.allowSleep) {
m_flags |= e_autoSleepFlag;
}
if (bd.awake) {
m_flags |= e_awakeFlag;
}
if (bd.active) {
m_flags |= e_activeFlag;
}
m_world = world;
m_xf.position.set(bd.position);
m_xf.R.set(bd.angle);
m_sweep.localCenter.setZero();
m_sweep.a0 = m_sweep.a = bd.angle;
// m_sweep.c0 = m_sweep.c = Transform.mul(m_xf, m_sweep.localCenter);
Transform.mulToOut(m_xf, m_sweep.localCenter, m_sweep.c0);
m_sweep.c.set(m_sweep.c0);
m_jointList = null;
m_contactList = null;
m_prev = null;
m_next = null;
m_linearVelocity.set(bd.linearVelocity);
m_angularVelocity = bd.angularVelocity;
m_linearDamping = bd.linearDamping;
m_angularDamping = bd.angularDamping;
m_force.setZero();
m_torque = 0.0f;
m_sleepTime = 0.0f;
m_type = bd.type;
if (m_type == BodyType.DYNAMIC) {
m_mass = 1f;
m_invMass = 1f;
}
else {
m_mass = 0f;
m_invMass = 0f;
}
m_I = 0.0f;
m_invI = 0.0f;
m_userData = bd.userData;
m_fixtureList = null;
m_fixtureCount = 0;
}
// TODO djm: check out about this new fixture here
/**
* 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 def
* the fixture definition.
* @warning This function is locked during callbacks.
*/
public final Fixture createFixture(FixtureDef def) {
assert (m_world.isLocked() == false);
if (m_world.isLocked() == true) {
return null;
}
// djm TODO from pool?
Fixture fixture = new Fixture();
fixture.create(this, def);
if ((m_flags & e_activeFlag) == e_activeFlag) {
BroadPhase broadPhase = m_world.m_contactManager.m_broadPhase;
fixture.createProxy(broadPhase, m_xf);
}
fixture.m_next = m_fixtureList;
m_fixtureList = fixture;
++m_fixtureCount;
fixture.m_body = this;
// Adjust mass properties if needed.
if (fixture.m_density > 0.0f) {
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.
m_world.m_flags |= World.NEW_FIXTURE;
return fixture;
}
private final FixtureDef fixDef = new FixtureDef();
/**
* Creates a fixture from a shape and attach it to this body.
* This is a convenience function. Use FixtureDef if you need to set parameters
* like friction, restitution, user data, or filtering.
* If the density is non-zero, 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 final Fixture createFixture(Shape shape, float density) {
fixDef.shape = shape;
fixDef.density = density;
return createFixture(fixDef);
}
/**
* 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 final void destroyFixture(Fixture fixture) {
assert (m_world.isLocked() == false);
if (m_world.isLocked() == true) {
return;
}
assert (fixture.m_body == this);
// Remove the fixture from this body's singly linked list.
assert (m_fixtureCount > 0);
Fixture node = m_fixtureList;
Fixture last = null; // java change
boolean found = false;
while (node != null) {
if (node == fixture) {
node = fixture.m_next;
found = true;
break;
}
last = node;
node = node.m_next;
}
// You tried to remove a shape that is not attached to this body.
assert (found);
// java change, remove it from the list
if (last == null) {
m_fixtureList = fixture.m_next;
}
else {
last.m_next = fixture.m_next;
}
// Destroy any contacts associated with the fixture.
ContactEdge edge = m_contactList;
while (edge != null) {
Contact c = edge.contact;
edge = edge.next;
Fixture fixtureA = c.getFixtureA();
Fixture fixtureB = c.getFixtureB();
if (fixture == fixtureA || fixture == fixtureB) {
// This destroys the contact and removes it from
// this body's contact list.
m_world.m_contactManager.destroy(c);
}
}
if ((m_flags & e_activeFlag) == e_activeFlag) {
assert (fixture.m_proxy != null);
BroadPhase broadPhase = m_world.m_contactManager.m_broadPhase;
fixture.destroyProxy(broadPhase);
}
else {
assert (fixture.m_proxy == null);
}
fixture.destroy();
fixture.m_body = null;
fixture.m_next = null;
fixture = null;
--m_fixtureCount;
// Reset the mass data.
resetMassData();
}
/**
* Set the position of the body's origin and rotation.
* This breaks any contacts and wakes the other bodies.
* Manipulating a body's transform may cause non-physical behavior.
*
* @param position
* the world position of the body's local origin.
* @param angle
* the world rotation in radians.
*/
public final void setTransform(Vec2 position, float angle) {
assert (m_world.isLocked() == false);
if (m_world.isLocked() == true) {
return;
}
m_xf.R.set(angle);
m_xf.position.set(position);
// m_sweep.c0 = m_sweep.c = Mul(m_xf, m_sweep.localCenter);
Transform.mulToOut(m_xf, m_sweep.localCenter, m_sweep.c0);
m_sweep.c.set(m_sweep.c0);
m_sweep.a0 = m_sweep.a = angle;
BroadPhase broadPhase = m_world.m_contactManager.m_broadPhase;
for (Fixture f = m_fixtureList; f != null; f = f.m_next) {
f.synchronize(broadPhase, m_xf, m_xf);
}
m_world.m_contactManager.findNewContacts();
}
/**
* Get the body transform for the body's origin.
*
* @return the world transform of the body's origin.
*/
public final Transform getTransform() {
return m_xf;
}
/**
* Get the world body origin position. Do not modify.
*
* @return the world position of the body's origin.
*/
public final Vec2 getPosition() {
return m_xf.position;
}
/**
* Get the angle in radians.
*
* @return the current world rotation angle in radians.
*/
public final float getAngle() {
return m_sweep.a;
}
/**
* Get the world position of the center of mass. Do not modify.
*/
public final Vec2 getWorldCenter() {
return m_sweep.c;
}
/**
* Get the local position of the center of mass. Do not modify.
*/
public final Vec2 getLocalCenter() {
return m_sweep.localCenter;
}
/**
* Set the linear velocity of the center of mass.
*
* @param v
* the new linear velocity of the center of mass.
*/
public final void setLinearVelocity(Vec2 v) {
if (m_type == BodyType.STATIC) {
return;
}
if (Vec2.dot(v, v) > 0.0f) {
setAwake(true);
}
m_linearVelocity.set(v);
}
/**
* Get the linear velocity of the center of mass. Do not modify,
* instead use {@link #setLinearVelocity(Vec2)}.
*
* @return the linear velocity of the center of mass.
*/
public final Vec2 getLinearVelocity() {
return m_linearVelocity;
}
/**
* Set the angular velocity.
*
* @param omega
* the new angular velocity in radians/second.
*/
public final void setAngularVelocity(float w) {
if (m_type == BodyType.STATIC) {
return;
}
if (w * w > 0f) {
setAwake(true);
}
m_angularVelocity = w;
}
/**
* Get the angular velocity.
*
* @return the angular velocity in radians/second.
*/
public final float getAngularVelocity() {
return m_angularVelocity;
}
/**
* 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 final void applyForce(Vec2 force, Vec2 point) {
if (m_type != BodyType.DYNAMIC) {
return;
}
if (isAwake() == false) {
setAwake(true);
}
// m_force.addLocal(force);
// Vec2 temp = tltemp.get();
// temp.set(point).subLocal(m_sweep.c);
// m_torque += Vec2.cross(temp, force);
m_force.x += force.x;
m_force.y += force.y;
m_torque += (point.x - m_sweep.c.x) * force.y - (point.y - 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 final void applyTorque(float torque) {
if (m_type != BodyType.DYNAMIC) {
return;
}
if (isAwake() == false) {
setAwake(true);
}
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 final void applyLinearImpulse(Vec2 impulse, Vec2 point) {
if (m_type != BodyType.DYNAMIC) {
return;
}
if (isAwake() == false) {
setAwake(true);
}
// Vec2 temp = tltemp.get();
// temp.set(impulse).mulLocal(m_invMass);
// m_linearVelocity.addLocal(temp);
//
// temp.set(point).subLocal(m_sweep.c);
// m_angularVelocity += m_invI * Vec2.cross(temp, impulse);
m_linearVelocity.x += impulse.x * m_invMass;
m_linearVelocity.y += impulse.y * m_invMass;
m_angularVelocity += m_invI * ((point.x - m_sweep.c.x) * impulse.y - (point.y - m_sweep.c.y) * impulse.x);
}
/**
* Apply an angular impulse.
*
* @param impulse
* the angular impulse in units of kg*m*m/s
*/
public void applyAngularImpulse(float impulse) {
if (m_type != BodyType.DYNAMIC) {
return;
}
if (isAwake() == false) {
setAwake(true);
}
m_angularVelocity += m_invI * impulse;
}
/**
* Get the total mass of the body.
*
* @return the mass, usually in kilograms (kg).
*/
public final float getMass() {
return m_mass;
}
/**
* Get the central rotational inertia of the body.
*
* @return the rotational inertia, usually in kg-m^2.
*/
public final float getInertia() {
return m_I + m_mass
* (m_sweep.localCenter.x * m_sweep.localCenter.x + m_sweep.localCenter.y * m_sweep.localCenter.y);
}
/**
* Get the mass data of the body. The rotational inertia is relative
* to the center of mass.
*
* @return a struct containing the mass, inertia and center of the body.
*/
public final void getMassData(MassData data) {
// data.mass = m_mass;
// data.I = m_I + m_mass * Vec2.dot(m_sweep.localCenter, m_sweep.localCenter);
// data.center.set(m_sweep.localCenter);
data.mass = m_mass;
data.I = m_I + m_mass
* (m_sweep.localCenter.x * m_sweep.localCenter.x + m_sweep.localCenter.y * m_sweep.localCenter.y);
data.center.x = m_sweep.localCenter.x;
data.center.y = m_sweep.localCenter.y;
}
/**
* 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.
*
* @param massData
* the mass properties.
*/
public final void setMassData(MassData massData) {
// TODO_ERIN adjust linear velocity and torque to account for movement of center.
assert (m_world.isLocked() == false);
if (m_world.isLocked() == true) {
return;
}
if (m_type != BodyType.DYNAMIC) {
return;
}
m_invMass = 0.0f;
m_I = 0.0f;
m_invI = 0.0f;
m_mass = massData.mass;
if (m_mass <= 0.0f) {
m_mass = 1f;
}
m_invMass = 1.0f / m_mass;
if (massData.I > 0.0f && (m_flags & e_fixedRotationFlag) == 0) {
m_I = massData.I - m_mass * Vec2.dot(massData.center, massData.center);
assert (m_I > 0.0f);
m_invI = 1.0f / m_I;
}
final Vec2 oldCenter = m_world.getPool().popVec2();
// Move center of mass.
oldCenter.set(m_sweep.c);
m_sweep.localCenter.set(massData.center);
// m_sweep.c0 = m_sweep.c = Mul(m_xf, m_sweep.localCenter);
Transform.mulToOut(m_xf, m_sweep.localCenter, m_sweep.c0);
m_sweep.c.set(m_sweep.c0);
// Update center of mass velocity.
// m_linearVelocity += Cross(m_angularVelocity, m_sweep.c - oldCenter);
final Vec2 temp = m_world.getPool().popVec2();
temp.set(m_sweep.c).subLocal(oldCenter);
Vec2.crossToOut(m_angularVelocity, temp, temp);
m_linearVelocity.addLocal(temp);
m_world.getPool().pushVec2(2);
}
private final MassData pmd = new MassData();
/**
* 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 you later want to reset the mass.
*/
public final void resetMassData() {
// Compute mass data from shapes. Each shape has its own density.
m_mass = 0.0f;
m_invMass = 0.0f;
m_I = 0.0f;
m_invI = 0.0f;
m_sweep.localCenter.setZero();
// Static and kinematic bodies have zero mass.
if (m_type == BodyType.STATIC || m_type == BodyType.KINEMATIC) {
// m_sweep.c0 = m_sweep.c = m_xf.position;
m_sweep.c.set(m_xf.position);
m_sweep.c0.set(m_xf.position);
return;
}
assert (m_type == BodyType.DYNAMIC);
// Accumulate mass over all fixtures.
final Vec2 center = m_world.getPool().popVec2();
center.setZero();
final Vec2 temp = m_world.getPool().popVec2();
final MassData massData = pmd;
for (Fixture f = m_fixtureList; f != null; f = f.m_next) {
if (f.m_density == 0.0f) {
continue;
}
f.getMassData(massData);
m_mass += massData.mass;
// center += massData.mass * massData.center;
temp.set(massData.center).mulLocal(massData.mass);
center.addLocal(temp);
m_I += massData.I;
}
// Compute center of mass.
if (m_mass > 0.0f) {
m_invMass = 1.0f / m_mass;
center.mulLocal(m_invMass);
}
else {
// Force all dynamic bodies to have a positive mass.
m_mass = 1.0f;
m_invMass = 1.0f;
}
if (m_I > 0.0f && (m_flags & e_fixedRotationFlag) == 0) {
// Center the inertia about the center of mass.
m_I -= m_mass * Vec2.dot(center, center);
assert (m_I > 0.0f);
m_invI = 1.0f / m_I;
}
else {
m_I = 0.0f;
m_invI = 0.0f;
}
Vec2 oldCenter = m_world.getPool().popVec2();
// Move center of mass.
oldCenter.set(m_sweep.c);
m_sweep.localCenter.set(center);
// m_sweep.c0 = m_sweep.c = Mul(m_xf, m_sweep.localCenter);
Transform.mulToOut(m_xf, m_sweep.localCenter, m_sweep.c0);
m_sweep.c.set(m_sweep.c0);
// Update center of mass velocity.
// m_linearVelocity += Cross(m_angularVelocity, m_sweep.c - oldCenter);
temp.set(m_sweep.c).subLocal(oldCenter);
Vec2.crossToOut(m_angularVelocity, temp, temp);
m_linearVelocity.addLocal(temp);
m_world.getPool().pushVec2(3);
}
/**
* 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 final Vec2 getWorldPoint(Vec2 localPoint) {
Vec2 v = new Vec2();
getWorldPointToOut(localPoint, v);
return v;
}
public final void getWorldPointToOut(Vec2 localPoint, Vec2 out) {
Transform.mulToOut(m_xf, localPoint, out);
}
/**
* 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 final Vec2 getWorldVector(Vec2 localVector) {
Vec2 out = new Vec2();
getWorldVectorToOut(localVector, out);
return out;
}
public final void getWorldVectorToOut(Vec2 localVector, Vec2 out) {
Mat22.mulToOut(m_xf.R, localVector, out);
}
/**
* 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 final Vec2 getLocalPoint(Vec2 worldPoint) {
Vec2 out = new Vec2();
getLocalPointToOut(worldPoint, out);
return out;
}
public final void getLocalPointToOut(Vec2 worldPoint, Vec2 out) {
Transform.mulTransToOut(m_xf, worldPoint, out);
}
/**
* Gets a local vector given a world vector.
*
* @param a
* vector in world coordinates.
* @return the corresponding local vector.
*/
public final Vec2 getLocalVector(Vec2 worldVector) {
Vec2 out = new Vec2();
getLocalVectorToOut(worldVector, out);
return out;
}
public final void getLocalVectorToOut(Vec2 worldVector, Vec2 out) {
Mat22.mulTransToOut(m_xf.R, worldVector, out);
}
/**
* 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 final Vec2 getLinearVelocityFromWorldPoint(Vec2 worldPoint) {
Vec2 out = new Vec2();
getLinearVelocityFromWorldPointToOut(worldPoint, out);
return out;
}
public final void getLinearVelocityFromWorldPointToOut(Vec2 worldPoint, Vec2 out) {
out.set(worldPoint).subLocal(m_sweep.c);
Vec2.crossToOut(m_angularVelocity, out, out);
out.addLocal(m_linearVelocity);
}
/**
* Get the world velocity of a local point.
*
* @param a
* point in local coordinates.
* @return the world velocity of a point.
*/
public final Vec2 getLinearVelocityFromLocalPoint(Vec2 localPoint) {
Vec2 out = new Vec2();
getLinearVelocityFromLocalPointToOut(localPoint, out);
return out;
}
public final void getLinearVelocityFromLocalPointToOut(Vec2 localPoint, Vec2 out) {
getWorldPointToOut(localPoint, out);
getLinearVelocityFromWorldPointToOut(out, out);
}
/** Get the linear damping of the body. */
public final float getLinearDamping() {
return m_linearDamping;
}
/** Set the linear damping of the body. */
public final void setLinearDamping(float linearDamping) {
m_linearDamping = linearDamping;
}
/** Get the angular damping of the body. */
public final float getAngularDamping() {
return m_angularDamping;
}
/** Set the angular damping of the body. */
public final void setAngularDamping(float angularDamping) {
m_angularDamping = angularDamping;
}
public BodyType getType() {
return m_type;
}
/**
* Set the type of this body. This may alter the mass and velocity.
*
* @param type
*/
public void setType(BodyType type) {
if (m_type == type) {
return;
}
m_type = type;
resetMassData();
if (m_type == BodyType.STATIC) {
m_linearVelocity.setZero();
m_angularVelocity = 0.0f;
}
setAwake(true);
m_force.setZero();
m_torque = 0.0f;
// Since the body type changed, we need to flag contacts for filtering.
for (ContactEdge ce = m_contactList; ce != null; ce = ce.next) {
ce.contact.flagForFiltering();
}
}
/** Is this body treated like a bullet for continuous collision detection? */
public final boolean isBullet() {
return (m_flags & e_bulletFlag) == e_bulletFlag;
}
/** Should this body be treated like a bullet for continuous collision detection? */
public final void setBullet(boolean flag) {
if (flag) {
m_flags |= e_bulletFlag;
}
else {
m_flags &= ~e_bulletFlag;
}
}
/**
* You can disable sleeping on this body. If you disable sleeping, the
* body will be woken.
*
* @param flag
*/
public void setSleepingAllowed(boolean flag) {
if (flag) {
m_flags |= e_autoSleepFlag;
}
else {
m_flags &= ~e_autoSleepFlag;
setAwake(true);
}
}
/**
* Is this body allowed to sleep
*
* @return
*/
public boolean isSleepingAllowed() {
return (m_flags & e_autoSleepFlag) == e_autoSleepFlag;
}
/**
* Set the sleep state of the body. A sleeping body has very
* low CPU cost.
*
* @param flag
* set to true to put body to sleep, false to wake it.
* @param flag
*/
public void setAwake(boolean flag) {
if (flag) {
if ((m_flags & e_awakeFlag) == 0) {
m_flags |= e_awakeFlag;
m_sleepTime = 0.0f;
}
}
else {
m_flags &= ~e_awakeFlag;
m_sleepTime = 0.0f;
m_linearVelocity.setZero();
m_angularVelocity = 0.0f;
m_force.setZero();
m_torque = 0.0f;
}
}
/**
* Get the sleeping state of this body.
*
* @return true if the body is sleeping.
*/
public boolean isAwake() {
return (m_flags & e_awakeFlag) == e_awakeFlag;
}
/**
* 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 World object and remains
* in the body list.
*
* @param flag
*/
public void setActive(boolean flag) {
if (flag == isActive()) {
return;
}
if (flag) {
m_flags |= e_activeFlag;
// Create all proxies.
BroadPhase broadPhase = m_world.m_contactManager.m_broadPhase;
for (Fixture f = m_fixtureList; f != null; f = f.m_next) {
f.createProxy(broadPhase, m_xf);
}
// Contacts are created the next time step.
}
else {
m_flags &= ~e_activeFlag;
// Destroy all proxies.
BroadPhase broadPhase = m_world.m_contactManager.m_broadPhase;
for (Fixture f = m_fixtureList; f != null; f = f.m_next) {
f.destroyProxy(broadPhase);
}
// Destroy the attached contacts.
ContactEdge ce = m_contactList;
while (ce != null) {
ContactEdge ce0 = ce;
ce = ce.next;
m_world.m_contactManager.destroy(ce0.contact);
}
m_contactList = null;
}
}
/**
* Get the active state of the body.
*
* @return
*/
public boolean isActive() {
return (m_flags & e_activeFlag) == e_activeFlag;
}
/**
* Set this body to have fixed rotation. This causes the mass
* to be reset.
*
* @param flag
*/
public void setFixedRotation(boolean flag) {
if (flag) {
m_flags |= e_fixedRotationFlag;
}
else {
m_flags &= ~e_fixedRotationFlag;
}
resetMassData();
}
/**
* Does this body have fixed rotation?
*
* @return
*/
public boolean isFixedRotation() {
return (m_flags & e_fixedRotationFlag) == e_fixedRotationFlag;
}
/** Get the list of all fixtures attached to this body. */
public final Fixture getFixtureList() {
return m_fixtureList;
}
/** Get the list of all joints attached to this body. */
public final JointEdge getJointList() {
return m_jointList;
}
/**
* Get the list of all contacts attached to this body.
*
* @warning this list changes during the time step and you may
* miss some collisions if you don't use ContactListener.
*/
public final ContactEdge getContactList() {
return m_contactList;
}
/** Get the next body in the world's body list. */
public final Body getNext() {
return m_next;
}
/** Get the user data pointer that was provided in the body definition. */
public final Object getUserData() {
return m_userData;
}
/**
* Set the user data. Use this to store your application specific data.
*/
public final void setUserData(Object data) {
m_userData = data;
}
/**
* Get the parent world of this body.
*/
public final World getWorld() {
return m_world;
}
// djm pooling
private final Transform pxf = new Transform();
protected final void synchronizeFixtures() {
final Transform xf1 = pxf;
xf1.R.set(m_sweep.a0);
// xf1.position = m_sweep.c0 - Mul(xf1.R, m_sweep.localCenter);
Mat22.mulToOut(xf1.R, m_sweep.localCenter, xf1.position);
xf1.position.mulLocal(-1).addLocal(m_sweep.c0);
BroadPhase broadPhase = m_world.m_contactManager.m_broadPhase;
for (Fixture f = m_fixtureList; f != null; f = f.m_next) {
f.synchronize(broadPhase, xf1, m_xf);
}
}
public final void synchronizeTransform() {
// m_xf.R.set(m_sweep.a);
//
// //m_xf.position = m_sweep.c - Mul(m_xf.R, m_sweep.localCenter);
// Mat22.mulToOut(m_xf.R, m_sweep.localCenter, m_xf.position);
// m_xf.position.mulLocal(-1).addLocal(m_sweep.c);
final float c = MathUtils.cos(m_sweep.a), s = MathUtils.sin(m_sweep.a);
m_xf.R.m11 = c;
m_xf.R.m21 = -s;
m_xf.R.m12 = s;
m_xf.R.m22 = c;
m_xf.position.x = m_xf.R.m11 * m_sweep.localCenter.x + m_xf.R.m21 * m_sweep.localCenter.y;
m_xf.position.y = m_xf.R.m12 * m_sweep.localCenter.x + m_xf.R.m22 * m_sweep.localCenter.y;
m_xf.position.x *= -1f;
m_xf.position.y *= -1f;
m_xf.position.x += m_sweep.c.x;
m_xf.position.y += m_sweep.c.y;
}
/**
* This is used to prevent connected bodies from colliding.
* It may lie, depending on the collideConnected flag.
*
* @param other
* @return
*/
public boolean shouldCollide(Body other) {
// At least one body should be dynamic.
if (m_type != BodyType.DYNAMIC && other.m_type != BodyType.DYNAMIC) {
return false;
}
// Does a joint prevent collision?
for (JointEdge jn = m_jointList; jn != null; jn = jn.next) {
if (jn.other == other) {
if (jn.joint.m_collideConnected == false) {
return false;
}
}
}
return true;
}
protected final void advance(float t) {
// Advance to the new safe time.
m_sweep.advance(t);
m_sweep.c.set(m_sweep.c0);
m_sweep.a = m_sweep.a0;
synchronizeTransform();
}
}