package collisions;import physics.PhysicsData;import physics.Vector2;/* * A contact represents two objects in contact (in this case * Contact representing two particles). Resolving a * contact removes their interpenetration, and applies sufficient * impulse to keep them apart. Colliding bodies may also rebound. * * The contact has no callable functions, it just holds the * contact details. To resolve a set of contacts, use the particle * contact resolver class. */public class Contact { /* * Holds the particles that are involved in the contact. The * second of these can be null, for contacts with the scenery. */ private PhysicsData[] pdArray = {null, null}; /* * Holds the normal restitution coefficient at the contact. */ private float restitution = 1.0f; /* * Holds the depth of the interpenetration. */ private float penetration; /* * Holds the direction of the contact */ private Vector2 contactNormal; public Contact(PhysicsData pd1, PhysicsData pd2, float restitution, float penetration, Vector2 contactNormal) { this.pdArray[0] = pd1; this.pdArray[1] = pd2; this.penetration = penetration; this.contactNormal = contactNormal; } /* * Resolves this contact, for both velocity and interpenetration. */ public void resolve(long timePassed) { this.resolveVelocity(timePassed); this.resolveInterpenetration(timePassed); } /* * Calculates the separating velocity at this contact. */ public float calculateSeperatingVelocity() { Vector2 relativeVelocity = new Vector2(this.pdArray[0].getVelocity()); if (this.pdArray[1] != null) relativeVelocity.subtract(this.pdArray[1].getVelocity()); return relativeVelocity.dotProduct(this.contactNormal); } /* * Handles the impulse calculations for this collision. */ private void resolveVelocity(long timePassed) { // Find the velocity in the direction of the contact. float separatingVelocity = this.calculateSeperatingVelocity(); if (separatingVelocity > 0) // The contact is either separating or stationary - there’s // no impulse required. return; // Calculate the new separating velocity. float newSepVelocity = -separatingVelocity * this.restitution; float deltaVelocity = newSepVelocity - separatingVelocity; /* * We apply the change in velocity to each object in proportion to * its inverse mass (i.e., those with lower inverse mass [higher * actual mass] get less change in velocity). */ float totalInverseMass = this.pdArray[0].getInverseMass(); if (this.pdArray[1] != null) totalInverseMass += this.pdArray[1].getInverseMass(); // If all particles have infinite mass, then impulses have no effect. if (totalInverseMass <= 0) return; // Calculate the impulse to apply. float impulse = deltaVelocity / totalInverseMass; Vector2 impulsePerIMass = Vector2.multiplyByScalar(this.contactNormal, impulse); // Apply impulses: they are applied in the direction of the contact, // and are proportional to the inverse mass. this.pdArray[0].setVelocity(Vector2.add(this.pdArray[0].getVelocity(), Vector2.multiplyByScalar(impulsePerIMass, this.pdArray[0].getInverseMass()))); if (this.pdArray[1] != null) this.pdArray[1].setVelocity(Vector2.add(this.pdArray[1].getVelocity(), Vector2.multiplyByScalar(impulsePerIMass, -this.pdArray[1].getInverseMass()))); } /* * Handles the interpenetration resolution for this contact */ private void resolveInterpenetration(long timePassed) { if (this.penetration <= 0) return; // The movement of each object is based on its inverse mass. float totalInverseMass = this.pdArray[0].getInverseMass(); if (this.pdArray[1] != null) totalInverseMass += this.pdArray[1].getInverseMass(); // If all particles have infinite mass, we do nothing if (totalInverseMass <= 0) return; // Find the amount of penetration resolution per unit of inverse mass. Vector2 movePerIMass = Vector2.multiplyByScalar(this.contactNormal, -this.penetration / totalInverseMass); // Apply the penetration resolution. this.pdArray[0].setPosition(Vector2.add(this.pdArray[0].getPosition(), Vector2.multiplyByScalar(movePerIMass, this.pdArray[0].getInverseMass()))); if (this.pdArray[1] != null) this.pdArray[1].setPosition(Vector2.add(this.pdArray[1].getPosition(), Vector2.multiplyByScalar(movePerIMass, this.pdArray[1].getInverseMass()))); }}