// This interface defines a Euclidean metric space with edges that bounce // to be used in a SpaceWar game. package SpaceWar; import java.awt.*; import java.awt.geom.*; import java.util.*; class MetricSpaceEuclideanBounce implements MetricSpace, SpaceBackground { ////////////////////////////////////////////////////////////////////// // // Instance Variables. protected double minX = 0.; protected double maxX = 512.; protected double minY = 0.; protected double maxY = 512.; protected Color boundaryColor = new Color(150, 220, 150); protected int boundaryVibrate = 2; protected Random rng = new Random(System.currentTimeMillis()); protected int[] xPoints = new int[4]; protected int[] yPoints = new int[4]; ////////////////////////////////////////////////////////////////////// // // Constructors. public MetricSpaceEuclideanBounce() { } public MetricSpaceEuclideanBounce(int mnX, int mxX, int mnY, int mxY) { setSize(mnX, mxX, mnY, mxY); } ////////////////////////////////////////////////////////////////////// // // Get-set methods. // Set the size of the space, presumably in response to a change // in frame size. public void setSize(int mnX, int mxX, int mnY, int mxY) { minX = (double)mnX; maxX = (double)mxX; minY = (double)mnY; maxY = (double)mxY; } // Check for collisions, given initial and final points for a // pair of objects, along with their radii. This is a simple // implementation that simply checks the pairs of points. // Returns true if a collision was detected. public boolean checkCollision(Point2D.Double p1, Point2D.Double p2, double pr, Point2D.Double q1, Point2D.Double q2, double qr) { double dist = pr + qr; if ((p1.distance(q1) < dist) || (p2.distance(q2) < dist)) { return (true); } return (false); } // Compute the distance between a pair of objects. Return the // distance, and also compute unit direction vectors from each // object to the other. Note that the shortest distance may // be wrapped around the edge of the screen... // // Note that u1 will contain the unit direction vector from p1 // to p2, and u2 will contain the unit direction vector from p2 // to p1. public double computeDistance(Point2D.Double p1, Point2D.Double p2, Point2D.Double u1, Point2D.Double u2) { double d; double dx; double dy; d = p1.distance(p2); if ((u1 == null) && (u2 == null)) { return (d); } dx = p2.getX() - p1.getX(); dy = p2.getY() - p1.getY(); dx /= d; dy /= d; if (u1 != null) { u1.setLocation(dx, dy); } if (u2 != null) { u2.setLocation(-dx, -dy); } return (d); } // Scale a position vector. Note that this is simple linear // scaling in a Euclidean metric space, and (for example) modular // scaling in a Riemannian metric space. public void scalePosition(Point2D.Double p, double scale) { p.setLocation(p.getX() * scale, p.getY() * scale); } // Add a pair of position vectors, placing the result in the // first vector. public void addPosition(Point2D.Double p1, Point2D.Double p2) { p1.setLocation(p1.getX() + p2.getX(), p1.getY() + p2.getY()); } // Scale a velocity vector. Note that this is simple linear // scaling in a Euclidean metric space, and (for example) Lorenz // transformations in the real universe. public void scaleVelocity(Point2D.Double p, double scale) { scalePosition(p, scale); } // Add a pair of velocity vectors, placing the result in the // first vector. public void addVelocity(Point2D.Double p1, Point2D.Double p2) { addPosition(p1, p2); } // Scale an acceleration vector. Note that this is simple linear // scaling in a Euclidean metric space. Alternate transformations // for alternate metric spaces are left as an exercise. ;-) public void scaleAcceleration(Point2D.Double p, double scale) { scalePosition(p, scale); } // Add a pair of acceleration vectors, placing the result in the // first vector. public void addAcceleration(Point2D.Double p1, Point2D.Double p2) { addPosition(p1, p2); } // Update a position, given the object's acceleration, velocity, // initial position, and radius. Returns true if the motion // was continuous, and false if it was discontinuous (e.g., it // bounced or wrapped). Knowledge of discontinuity is important // for display methods that simulate speed blur. public boolean updatePosition(Point2D.Double acceleration, Point2D.Double velocity, Point2D.Double position, double r) { boolean discontinuity = false; double vx; double vy; double x; double y; // Compute new position. vx = velocity.getX() + acceleration.getX(); vy = velocity.getY() + acceleration.getY(); x = position.getX() + vx; y = position.getY() + vy; // Check for bounces... if (x < minX + r) { x = 2 * (minX + r) - x; vx = -vx; discontinuity = true; } else if (x > maxX - r) { x = 2 * (maxX - r) - x; vx = -vx; discontinuity = true; } else if (y < minY + r) { y = 2 * (minY + r) - y; vy = -vy; discontinuity = true; } else if (y > maxY - r) { y = 2 * (maxY - r) - y; vy = -vy; discontinuity = true; } // Update the velocity and position. velocity.setLocation(vx, vy); position.setLocation(x, y); // Tell the sender whether we bounced. return (discontinuity); } // Convert a fraction in the range [0,1] to a corresponding integer // denoting the corresponding display x-coordinate. public int fractionToX(double xFraction) { return ((int)((maxX - minX) * xFraction + minX)); } // Convert a fraction in the range [0,1] to a corresponding integer // denoting the corresponding display y-coordinate. public int fractionToY(double yFraction) { return ((int)((maxY - minY) * yFraction + minY)); } // Paint the pale green boundary that objects bounce off of. public void paint(SpaceGraphics g) { xPoints[0] = (int)minX; xPoints[1] = (int)maxX; xPoints[2] = (int)maxX; xPoints[3] = (int)minX; yPoints[0] = (int)minY; yPoints[1] = (int)minY; yPoints[2] = (int)maxY; yPoints[3] = (int)maxY; g.setColor(boundaryColor); g.drawPolygon(xPoints, yPoints, 4); } }