use of com.almasb.fxgl.physics.box2d.dynamics.contacts.ContactEdge in project FXGL by AlmasB.
the class World method createJoint.
/**
* Create a joint to constrain bodies together.
* No reference to the definition is retained.
* This may cause the connected bodies to cease colliding.
* This function is locked during callbacks.
* Note: creating a joint doesn't wake the bodies.
*
* @param def joint definition
* @return joint
*/
public Joint createJoint(JointDef def) {
assertNotLocked();
Joint j = Joint.create(this, def);
// Connect to the world list.
j.m_prev = null;
j.m_next = m_jointList;
if (m_jointList != null) {
m_jointList.m_prev = j;
}
m_jointList = j;
++jointCount;
// Connect to the bodies' doubly linked lists.
j.m_edgeA.joint = j;
j.m_edgeA.other = j.getBodyB();
j.m_edgeA.prev = null;
j.m_edgeA.next = j.getBodyA().m_jointList;
if (j.getBodyA().m_jointList != null) {
j.getBodyA().m_jointList.prev = j.m_edgeA;
}
j.getBodyA().m_jointList = j.m_edgeA;
j.m_edgeB.joint = j;
j.m_edgeB.other = j.getBodyA();
j.m_edgeB.prev = null;
j.m_edgeB.next = j.getBodyB().m_jointList;
if (j.getBodyB().m_jointList != null) {
j.getBodyB().m_jointList.prev = j.m_edgeB;
}
j.getBodyB().m_jointList = j.m_edgeB;
Body bodyA = def.bodyA;
Body bodyB = def.bodyB;
// If the joint prevents collisions, then flag any contacts for filtering.
if (!def.collideConnected) {
ContactEdge edge = bodyB.getContactList();
while (edge != null) {
if (edge.other == bodyA) {
// Flag the contact for filtering at the next time step (where either body is awake).
edge.contact.flagForFiltering();
}
edge = edge.next;
}
}
return j;
}
use of com.almasb.fxgl.physics.box2d.dynamics.contacts.ContactEdge in project FXGL by AlmasB.
the class World method solveTOI.
private void solveTOI(final TimeStep step) {
final Island island = toiIsland;
island.init(2 * JBoxSettings.maxTOIContacts, JBoxSettings.maxTOIContacts, 0, contactManager.getContactListener());
if (stepComplete) {
for (Body b : bodies) {
b.m_flags &= ~Body.e_islandFlag;
b.m_sweep.alpha0 = 0.0f;
}
for (Contact c = contactManager.contactList; c != null; c = c.m_next) {
// Invalidate TOI
c.m_flags &= ~(Contact.TOI_FLAG | Contact.ISLAND_FLAG);
c.m_toiCount = 0;
c.m_toi = 1.0f;
}
}
// Find TOI events and solve them.
for (; ; ) {
// Find the first TOI.
Contact minContact = null;
float minAlpha = 1.0f;
for (Contact c = contactManager.contactList; c != null; c = c.m_next) {
// Is this contact disabled?
if (!c.isEnabled()) {
continue;
}
// Prevent excessive sub-stepping.
if (c.m_toiCount > JBoxSettings.maxSubSteps) {
continue;
}
float alpha = 1.0f;
if ((c.m_flags & Contact.TOI_FLAG) != 0) {
// This contact has a valid cached TOI.
alpha = c.m_toi;
} else {
Fixture fA = c.getFixtureA();
Fixture fB = c.getFixtureB();
// Is there a sensor?
if (fA.isSensor() || fB.isSensor()) {
continue;
}
Body bA = fA.getBody();
Body bB = fB.getBody();
BodyType typeA = bA.getType();
BodyType typeB = bB.getType();
assert (typeA == BodyType.DYNAMIC || typeB == BodyType.DYNAMIC);
boolean activeA = bA.isAwake() && typeA != BodyType.STATIC;
boolean activeB = bB.isAwake() && typeB != BodyType.STATIC;
// Is at least one body active (awake and dynamic or kinematic)?
if (!activeA && !activeB) {
continue;
}
boolean collideA = bA.isBullet() || typeA != BodyType.DYNAMIC;
boolean collideB = bB.isBullet() || typeB != BodyType.DYNAMIC;
// Are these two non-bullet dynamic bodies?
if (!collideA && !collideB) {
continue;
}
// Compute the TOI for this contact.
// Put the sweeps onto the same time interval.
float alpha0 = bA.m_sweep.alpha0;
if (bA.m_sweep.alpha0 < bB.m_sweep.alpha0) {
alpha0 = bB.m_sweep.alpha0;
bA.m_sweep.advance(alpha0);
} else if (bB.m_sweep.alpha0 < bA.m_sweep.alpha0) {
alpha0 = bA.m_sweep.alpha0;
bB.m_sweep.advance(alpha0);
}
assert (alpha0 < 1.0f);
int indexA = c.getChildIndexA();
int indexB = c.getChildIndexB();
// Compute the time of impact in interval [0, minTOI]
final TOIInput input = toiInput;
input.proxyA.set(fA.getShape(), indexA);
input.proxyB.set(fB.getShape(), indexB);
input.sweepA.set(bA.m_sweep);
input.sweepB.set(bB.m_sweep);
input.tMax = 1.0f;
pool.getTimeOfImpact().timeOfImpact(toiOutput, input);
// Beta is the fraction of the remaining portion of the .
float beta = toiOutput.t;
if (toiOutput.state == TOIOutputState.TOUCHING) {
alpha = JBoxUtils.min(alpha0 + (1.0f - alpha0) * beta, 1.0f);
} else {
alpha = 1.0f;
}
c.m_toi = alpha;
c.m_flags |= Contact.TOI_FLAG;
}
if (alpha < minAlpha) {
// This is the minimum TOI found so far.
minContact = c;
minAlpha = alpha;
}
}
if (minContact == null || 1.0f - 10.0f * JBoxSettings.EPSILON < minAlpha) {
// No more TOI events. Done!
stepComplete = true;
break;
}
// Advance the bodies to the TOI.
Fixture fA = minContact.getFixtureA();
Fixture fB = minContact.getFixtureB();
Body bA = fA.getBody();
Body bB = fB.getBody();
backup1.set(bA.m_sweep);
backup2.set(bB.m_sweep);
bA.advance(minAlpha);
bB.advance(minAlpha);
// The TOI contact likely has some new contact points.
minContact.update(contactManager.getContactListener());
minContact.m_flags &= ~Contact.TOI_FLAG;
++minContact.m_toiCount;
// Is the contact solid?
if (!minContact.isEnabled() || !minContact.isTouching()) {
// Restore the sweeps.
minContact.setEnabled(false);
bA.m_sweep.set(backup1);
bB.m_sweep.set(backup2);
bA.synchronizeTransform();
bB.synchronizeTransform();
continue;
}
bA.setAwake(true);
bB.setAwake(true);
// Build the island
island.clear();
island.add(bA);
island.add(bB);
island.add(minContact);
bA.m_flags |= Body.e_islandFlag;
bB.m_flags |= Body.e_islandFlag;
minContact.m_flags |= Contact.ISLAND_FLAG;
// Get contacts on bodyA and bodyB.
tempBodies[0] = bA;
tempBodies[1] = bB;
for (int i = 0; i < 2; ++i) {
Body body = tempBodies[i];
if (body.getType() == BodyType.DYNAMIC) {
for (ContactEdge ce = body.m_contactList; ce != null; ce = ce.next) {
if (island.m_bodyCount == island.m_bodyCapacity) {
break;
}
if (island.m_contactCount == island.m_contactCapacity) {
break;
}
Contact contact = ce.contact;
// Has this contact already been added to the island?
if ((contact.m_flags & Contact.ISLAND_FLAG) != 0) {
continue;
}
// Only add static, kinematic, or bullet bodies.
Body other = ce.other;
if (other.getType() == BodyType.DYNAMIC && !body.isBullet() && !other.isBullet()) {
continue;
}
// Skip sensors.
boolean sensorA = contact.m_fixtureA.isSensor();
boolean sensorB = contact.m_fixtureB.isSensor();
if (sensorA || sensorB) {
continue;
}
// Tentatively advance the body to the TOI.
backup1.set(other.m_sweep);
if ((other.m_flags & Body.e_islandFlag) == 0) {
other.advance(minAlpha);
}
// Update the contact points
contact.update(contactManager.getContactListener());
// Was the contact disabled by the user?
if (!contact.isEnabled()) {
other.m_sweep.set(backup1);
other.synchronizeTransform();
continue;
}
// Are there contact points?
if (!contact.isTouching()) {
other.m_sweep.set(backup1);
other.synchronizeTransform();
continue;
}
// Add the contact to the island
contact.m_flags |= Contact.ISLAND_FLAG;
island.add(contact);
// Has the other body already been added to the island?
if ((other.m_flags & Body.e_islandFlag) != 0) {
continue;
}
// Add the other body to the island.
other.m_flags |= Body.e_islandFlag;
if (other.getType() != BodyType.STATIC) {
other.setAwake(true);
}
island.add(other);
}
}
}
subStep.dt = (1.0f - minAlpha) * step.dt;
subStep.inv_dt = 1.0f / subStep.dt;
subStep.dtRatio = 1.0f;
subStep.positionIterations = 20;
subStep.velocityIterations = step.velocityIterations;
subStep.warmStarting = false;
island.solveTOI(subStep, bA.m_islandIndex, bB.m_islandIndex);
// Reset island flags and synchronize broad-phase proxies.
for (int i = 0; i < island.m_bodyCount; ++i) {
Body body = island.m_bodies[i];
body.m_flags &= ~Body.e_islandFlag;
if (body.getType() != BodyType.DYNAMIC) {
continue;
}
body.synchronizeFixtures();
// Invalidate all contact TOIs on this displaced body.
for (ContactEdge ce = body.m_contactList; ce != null; ce = ce.next) {
ce.contact.m_flags &= ~(Contact.TOI_FLAG | Contact.ISLAND_FLAG);
}
}
// Commit fixture proxy movements to the broad-phase so that new contacts are created.
// Also, some contacts can be destroyed.
contactManager.findNewContacts();
if (subStepping) {
stepComplete = false;
break;
}
}
}
use of com.almasb.fxgl.physics.box2d.dynamics.contacts.ContactEdge in project FXGL by AlmasB.
the class Body method destroyFixture.
/**
* 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.
* Note: this function is locked during callbacks.
*
* @param fixture the fixture to be removed
*/
public void destroyFixture(Fixture fixture) {
world.assertNotLocked();
assert (fixture.getBody() == this);
assert (fixtures.size() > 0);
assert fixtures.contains(fixture);
fixtures.remove(fixture);
// 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.
world.getContactManager().destroy(c);
}
}
if ((m_flags & e_activeFlag) == e_activeFlag) {
BroadPhase broadPhase = world.getContactManager().broadPhase;
fixture.destroyProxies(broadPhase);
}
fixture.destroy();
resetMassData();
}
use of com.almasb.fxgl.physics.box2d.dynamics.contacts.ContactEdge in project FXGL by AlmasB.
the class ContactManager method addPair.
/**
* Broad-phase callback.
*
* @param proxyUserDataA proxy user data A
* @param proxyUserDataB proxy user data B
*/
@Override
public void addPair(Object proxyUserDataA, Object proxyUserDataB) {
Fixture.FixtureProxy proxyA = (Fixture.FixtureProxy) proxyUserDataA;
Fixture.FixtureProxy proxyB = (Fixture.FixtureProxy) proxyUserDataB;
Fixture fixtureA = proxyA.fixture;
Fixture fixtureB = proxyB.fixture;
int indexA = proxyA.childIndex;
int indexB = proxyB.childIndex;
Body bodyA = fixtureA.getBody();
Body bodyB = fixtureB.getBody();
// Are the fixtures on the same body?
if (bodyA == bodyB) {
return;
}
// TODO_ERIN use a hash table to remove a potential bottleneck when both
// bodies have a lot of contacts.
// Does a contact already exist?
ContactEdge edge = bodyB.getContactList();
while (edge != null) {
if (edge.other == bodyA) {
Fixture fA = edge.contact.getFixtureA();
Fixture fB = edge.contact.getFixtureB();
int iA = edge.contact.getChildIndexA();
int iB = edge.contact.getChildIndexB();
if (fA == fixtureA && iA == indexA && fB == fixtureB && iB == indexB) {
// A contact already exists.
return;
}
if (fA == fixtureB && iA == indexB && fB == fixtureA && iB == indexA) {
// A contact already exists.
return;
}
}
edge = edge.next;
}
// Does a joint override collision? is at least one body dynamic?
if (!bodyB.shouldCollide(bodyA)) {
return;
}
// Check user filtering.
if (contactFilter != null && !contactFilter.shouldCollide(fixtureA, fixtureB)) {
return;
}
// Call the factory.
Contact c = popContact(fixtureA, indexA, fixtureB, indexB);
if (c == null) {
return;
}
// Contact creation may swap fixtures.
fixtureA = c.getFixtureA();
fixtureB = c.getFixtureB();
indexA = c.getChildIndexA();
indexB = c.getChildIndexB();
bodyA = fixtureA.getBody();
bodyB = fixtureB.getBody();
// Insert into the world.
c.m_prev = null;
c.m_next = contactList;
if (contactList != null) {
contactList.m_prev = c;
}
contactList = c;
// Connect to island graph.
// Connect to body A
c.m_nodeA.contact = c;
c.m_nodeA.other = bodyB;
c.m_nodeA.prev = null;
c.m_nodeA.next = bodyA.m_contactList;
if (bodyA.m_contactList != null) {
bodyA.m_contactList.prev = c.m_nodeA;
}
bodyA.m_contactList = c.m_nodeA;
// Connect to body B
c.m_nodeB.contact = c;
c.m_nodeB.other = bodyA;
c.m_nodeB.prev = null;
c.m_nodeB.next = bodyB.m_contactList;
if (bodyB.m_contactList != null) {
bodyB.m_contactList.prev = c.m_nodeB;
}
bodyB.m_contactList = c.m_nodeB;
// wake up the bodies
if (!fixtureA.isSensor() && !fixtureB.isSensor()) {
bodyA.setAwake(true);
bodyB.setAwake(true);
}
++contactCount;
}
Aggregations