package games.fighter.davidalan.util;
import java.awt.geom.Point2D;
import util.Vector;
/**
* Physics methods for dealing with various forces and collision.
*
* @author Wayne You
*
*/
public class Physics {
/**
* Calculates an elastic collision given two objects of given masses and
* velocities.
*
* @param aVelocity
* The velocity of object A
* @param aLocation
* The location of object A
* @param aMass
* The mass of object A
* @param bVelocity
* The velocity of object B
* @param bLocation
* The location of object B
* @param bMass
* The mass of object B
* @return Two vectors in an array, the first is the new velocity of object
* A and the second is
* the new velocity of object B.
*/
public static Vector[] elasticCollision(Vector aVelocity,
Point2D aLocation, int aMass, Vector bVelocity, Point2D bLocation,
int bMass) {
return partiallyInelasticCollision(1, aVelocity, aLocation, aMass,
bVelocity, bLocation, bMass);
}
/**
* Calculates a perfectly inelastic collision given two objects of given
* masses and velocities.
*
* @param aVelocity
* The velocity of object A
* @param aLocation
* The location of object A
* @param aMass
* The mass of object A
* @param bVelocity
* The velocity of object B
* @param bLocation
* The location of object B
* @param bMass
* The mass of object B
* @return Two vectors in an array, the first is the new velocity of object
* A and the second is
* the new velocity of object B.
*/
public static Vector[] inelasticCollision(Vector aVelocity,
Point2D aLocation, int aMass, Vector bVelocity, Point2D bLocation,
int bMass) {
return partiallyInelasticCollision(0, aVelocity, aLocation, aMass,
bVelocity, bLocation, bMass);
}
/**
* Calculates a partially inelastic collision given two objects of given
* masses and velocities.
*
* @param restitution
* The coefficient of restitution where 1 is perfectly elastic
* and 0 is
* perfectly inelastic
* @param aVelocity
* The velocity of object A
* @param aLocation
* The location of object A
* @param aMass
* The mass of object A
* @param bVelocity
* The velocity of object B
* @param bLocation
* The location of object B
* @param bMass
* The mass of object B
* @return Two vectors in an array, the first is the new velocity of object
* A and the second is
* the new velocity of object B.
*/
public static Vector[] partiallyInelasticCollision(double restitution,
Vector aVelocity, Point2D aLocation, int aMass, Vector bVelocity,
Point2D bLocation, int bMass) {
double referenceAngle = Math.toDegrees(Math.atan2(aLocation.getY()
- bLocation.getY(), aLocation.getX() - bLocation.getX()));
Vector aTurned = new Vector(aVelocity);
aTurned.turn(-referenceAngle);
Vector bTurned = new Vector(bVelocity);
bTurned.turn(-referenceAngle);
double aVectorTurnedDX = ((restitution * bMass * (bTurned.getXChange() - aTurned
.getXChange())) + (aMass * aTurned.getXChange()) + (bMass * bTurned
.getXChange())) / (aMass + bMass);
double bVectorTurnedDX = ((restitution * aMass * (aTurned.getXChange() - bTurned
.getXChange())) + (aMass * aTurned.getXChange()) + (bMass * bTurned
.getXChange())) / (aMass + bMass);
Vector[] newDirections = new Vector[2];
newDirections[0] = new Vector();
newDirections[1] = new Vector();
newDirections[0].setVectorByComponent(aVectorTurnedDX,
aTurned.getYChange());
newDirections[1].setVectorByComponent(bVectorTurnedDX,
bTurned.getYChange());
newDirections[0].turn(-referenceAngle);
newDirections[1].turn(-referenceAngle);
return newDirections;
}
/**
* Computes a vector after gravitational force is applied.
*
* @param velocity
* The velocity of the object
* @param gravitationalAcceleration
* The acceleration due to gravity.
* @param terminalSpeed
* The max speed an object can fall down.
* @return A vector with gravity applied for one time period of
* acceleration.
*/
public static Vector gravity(Vector velocity,
double gravitationalAcceleration, double terminalSpeed) {
double dY = velocity.getYChange() - gravitationalAcceleration;
if (dY < -terminalSpeed) {
dY = -terminalSpeed;
}
Vector outputVector = new Vector();
outputVector.setVectorByComponent(velocity.getXChange(), dY);
return outputVector;
}
/**
* Reduces the magnitude of a vector due to friction.
* A crude representation that does not work by opposing force.
*
* @param velocity
* The original velocity.
* @param coefficientOfFriction
* The coefficient of friction (between 0 and 1)
* @return A reduced velocity vector.
*/
public static Vector friction(Vector velocity, double coefficientOfFriction) {
Vector velocityClone = new Vector(velocity);
velocityClone.scale(coefficientOfFriction);
return velocityClone;
}
/**
* Applies gravity to an object in contact with something acting as the
* ground with a particular angle.
*
* @param velocity
* The current velocity of the object.
* @param gravitationalAcceleration
* The acceleration due to gravity
* @param terminalSpeed
* The maximum magnitude the velocity may have.
* @param inclineAngle
* The incline of the angled slope in degrees. [0, 180)
* @param coefficientOfFriction
* The coefficient of friction.
* @return A modified velocity vector after applying gravity.
*/
public static Vector sliding(Vector velocity,
double gravitationalAcceleration, double terminalSpeed,
double inclineAngle, double coefficientOfFriction) {
double terminalXVelocity = -(Math.sin(Math.toRadians(inclineAngle)) * terminalSpeed);
double terminalYVelocity = -(Math.cos(Math.toRadians(inclineAngle)) * terminalSpeed);
// Represents the adjustment to the velocity by one time period.
// The adjustment scales linearly with how
// close the velocities are to matching and inversely with the
// coefficient of friction, where a higher
// coefficient represents a slower change and slower max speed.
double gravityDXVelocity = -(Math.sin(Math.toRadians(inclineAngle)) * gravitationalAcceleration)
* ((terminalSpeed * coefficientOfFriction) - velocity
.getMagnitude()) * (1 - coefficientOfFriction);
double gravityDYVelocity = (Math.cos(Math.toRadians(inclineAngle)) * gravitationalAcceleration)
* ((terminalSpeed * coefficientOfFriction) - velocity
.getMagnitude()) * (1 - coefficientOfFriction);
double newXVelocity = velocity.getXChange() + gravityDXVelocity;
double newYVelocity = velocity.getYChange() + gravityDYVelocity;
// Don't overshoot the change and reverse direction.
if (((terminalXVelocity - newXVelocity) <= 0) != ((terminalXVelocity - velocity
.getXChange()) <= 0)) {
newXVelocity = terminalXVelocity;
}
if (((terminalYVelocity - newYVelocity) <= 0) != ((terminalYVelocity - velocity
.getYChange()) <= 0)) {
newYVelocity = terminalYVelocity;
}
Vector outputVector = new Vector();
outputVector.setVectorByComponent(newXVelocity, newYVelocity);
return outputVector;
}
/**
* Returns a velocity with no magnitude in the y axis. Useful for simulating normal force.
* @param velocity The velocity of the object.
* @return The velocity with only an x component.
*/
public static Vector negateFalling (Vector velocity) {
Vector newVector = new Vector(velocity);
newVector.setVectorByComponent(velocity.getXChange(), 0);
return newVector;
}
/**
* Returns the velocity vector reflected about a wall of impact. Assumes a
* perfect elastic
* collision.
*
* @param velocity
* The velocity of the object
* @param inclineAngle
* The angle of the wall being hit. [0, 180)
* @return A reflected velocity vector.
*/
public static Vector bounce(Vector velocity, double inclineAngle) {
Vector wall = new Vector(Math.cos(Math.toRadians(inclineAngle)),
Math.sin(Math.toRadians(inclineAngle)));
Vector reflectedVector = new Vector(wall);
reflectedVector.scale(2 * (velocity.dotProduct(wall) / wall
.dotProduct(wall)));
reflectedVector.difference(velocity);
return reflectedVector;
}
/**
* Applies a force on an object with a given velocity and mass.
*
* @param velocity
* The object's velocity
* @param mass
* The object's mass
* @param force
* The force applied to the object
* @return The new velocity with force applied
*/
public static Vector applyForce(Vector velocity, double mass, Vector force) {
Vector modifiableForce = new Vector(force);
modifiableForce.scale(1 / mass);
Vector newVelocity = new Vector(velocity);
newVelocity.sum(modifiableForce);
return newVelocity;
}
/**
* Applies a force on an object with a given velocity and mass. Limits the
* maximum speed of the object.
*
* @param velocity
* The object's velocity
* @param mass
* The object's mass
* @param force
* The force applied to the object
* @param terminalSpeed
* The maximum speed the object may have.
* @return The new velocity with force applied
*/
public static Vector applyForce(Vector velocity, double mass, Vector force,
double terminalSpeed) {
Vector newVelocity = applyForce(velocity, mass, force);
if (newVelocity.getMagnitude() > terminalSpeed) {
newVelocity.scale(terminalSpeed / newVelocity.getMagnitude());
}
return newVelocity;
}
}