Last active
December 23, 2015 02:28
-
-
Save mnstrspeed/6566662 to your computer and use it in GitHub Desktop.
Collisions based on lines
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package nl.tomsanders.game.egine.util; | |
public class Line | |
{ | |
private final double slope; | |
private final double intercept; | |
private final Vector pointA; | |
private final Vector pointB; | |
public Line(Vector a, Vector b) | |
{ | |
Vector d = b.subtract(a); | |
this.slope = d.getY() / d.getX(); | |
this.intercept = a.getY() - this.slope * a.getX(); | |
this.pointA = a; | |
this.pointB = b; | |
} | |
public double getSlope() | |
{ | |
return this.slope; | |
} | |
public double getIntercept() | |
{ | |
return this.intercept; | |
} | |
public Vector getPointA() | |
{ | |
return this.pointA; | |
} | |
public Vector getPointB() | |
{ | |
return this.pointB; | |
} | |
public boolean isOnLine(Vector b) | |
{ | |
if (this.isVertical()) | |
{ | |
return (b.getY() >= this.pointA.getY() && b.getY() <= this.pointB.getY() || | |
b.getY() >= this.pointB.getY() && b.getY() <= this.pointA.getY()); | |
} | |
else | |
{ | |
return (b.getX() >= this.pointA.getX() && b.getX() <= this.pointB.getX()) || | |
(b.getX() >= this.pointB.getX() && b.getX() <= this.pointA.getX()); | |
} | |
} | |
public boolean isVertical() | |
{ | |
return this.slope == Double.POSITIVE_INFINITY || | |
this.slope == Double.NEGATIVE_INFINITY; | |
} | |
public double intersect(Line b) | |
{ | |
if (this.isVertical()) | |
{ | |
return this.pointA.getX(); | |
} | |
else | |
{ | |
return (b.getIntercept() - this.getIntercept()) / | |
(this.getSlope() - b.getSlope()); | |
} | |
} | |
public Vector project(double x) | |
{ | |
return new Vector(x, this.slope * x + this.intercept); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import java.awt.Color; | |
import java.awt.Graphics; | |
import java.util.ArrayList; | |
import java.util.List; | |
import nl.tomsanders.game.egine.Game; | |
import nl.tomsanders.game.egine.GameTime; | |
import nl.tomsanders.game.egine.util.Line; | |
import nl.tomsanders.game.egine.util.Rectangle; | |
import nl.tomsanders.game.egine.util.Size; | |
import nl.tomsanders.game.egine.util.Vector; | |
public class PhysicsGame extends Game | |
{ | |
private Rectangle obstacle; | |
private Rectangle x; | |
private Rectangle dx; | |
private Vector speed; | |
public PhysicsGame() | |
{ | |
/* | |
// Horizontal test from top | |
this.obstacle = new Rectangle( | |
new Vector(400, 400), | |
new Size(400, 50)); | |
this.x = new Rectangle( | |
new Vector(500, 250), | |
new Size(50, 50)); | |
this.speed = new Vector(200, 250); | |
*/ | |
// Vertical test from right | |
this.obstacle = new Rectangle( | |
new Vector(600, 200), | |
new Size(50, 300)); | |
this.x = new Rectangle( | |
new Vector(800, 300), | |
new Size(50, 50)); | |
this.speed = new Vector(-400, 100); | |
// Calculate next frame position | |
this.dx = new Rectangle( | |
this.x.getPosition().translate(this.speed), | |
this.x.getSize()); | |
} | |
private boolean showIntersectionPoints = false; | |
private boolean drawTrajectoryLines = true; | |
private boolean drawObstacleLines = false; | |
@Override | |
public void render(Graphics g) | |
{ | |
super.render(g); | |
g.setColor(Color.BLACK); | |
this.drawBox(g, this.obstacle); | |
this.drawBox(g, this.x); | |
this.drawBox(g, this.dx); | |
if (drawTrajectoryLines) | |
{ | |
g.setColor(Color.LIGHT_GRAY); | |
for (Line line : this.x.getConnectingLines(this.dx)) | |
{ | |
this.drawLine(g, line); | |
} | |
} | |
if (drawObstacleLines) | |
{ | |
g.setColor(Color.BLUE); | |
for (Line line : this.obstacle.getLines()) | |
{ | |
this.drawLine(g, line); | |
} | |
} | |
this.drawBoxAfterCollision(g); | |
} | |
private void drawBoxAfterCollision(Graphics g) | |
{ | |
// Basically, the "first" (or "closest") intersection | |
// will determine how far the object can travel | |
Vector closestDelta = this.speed; | |
for (Line line : this.obstacle.getLines()) // Lines bounding the rectangle of the obstacle | |
{ | |
for (Line trajectory : this.x.getConnectingLines(this.dx)) // Lines connecting the corners of rectangles in current and next frame | |
{ | |
for (Vector intersection : this.determineIntersections(line, trajectory)) // 0 or 1 intersections | |
{ | |
Vector delta = intersection.subtract(trajectory.getPointA()); | |
if (delta.getLengthSquared() < closestDelta.getLengthSquared()) | |
{ | |
closestDelta = delta; | |
} | |
// For debugging purposes | |
if (showIntersectionPoints) | |
{ | |
g.setColor(Color.GREEN); | |
g.fillOval((int)intersection.getX() - 5, (int)intersection.getY() - 5, 10, 10); | |
} | |
} | |
} | |
} | |
// Draw box | |
g.setColor(Color.RED); | |
Rectangle box = new Rectangle( | |
this.x.getPosition().translate(closestDelta), | |
this.x.getSize()); | |
this.drawBox(g, box); | |
} | |
private List<Vector> determineIntersections(Line a, Line b) | |
{ | |
ArrayList<Vector> result = new ArrayList<Vector>(); | |
if (a.isVertical()) | |
{ | |
if (b.isVertical()) | |
{ | |
// Perpendicular lines, so no intersections | |
return result; | |
} | |
// Swap a and b | |
return this.determineIntersections(b, a); | |
} | |
Vector intersection = a.project(b.intersect(a)); | |
if (a.isOnLine(intersection) && b.isOnLine(intersection)) | |
{ | |
result.add(intersection); | |
} | |
return result; | |
} | |
private void drawBox(Graphics g, Rectangle box) | |
{ | |
g.drawRect((int)box.getTopLeftCorner().getX(), (int)box.getTopLeftCorner().getY(), | |
(int)box.getSize().getWidth(), (int)box.getSize().getHeight()); | |
} | |
public static void main(String[] args) | |
{ | |
new PhysicsGame().start(); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package nl.tomsanders.game.egine.util; | |
import java.util.ArrayList; | |
import java.util.List; | |
public class Rectangle { | |
private final Vector position; | |
private final Size size; | |
public Rectangle(Vector position, Size size) { | |
this.position = position; | |
this.size = size; | |
} | |
public Size getSize() { | |
return this.size; | |
} | |
public Vector getPosition() { | |
return this.position; | |
} | |
public Vector getTopLeftCorner() { | |
return this.position; | |
} | |
public Vector getTopRightCorner() { | |
return new Vector( | |
this.position.x + this.size.getWidth(), | |
this.position.y); | |
} | |
public Vector getBottomLeftCorner() { | |
return new Vector( | |
this.position.x, | |
this.position.y + this.size.getHeight()); | |
} | |
public Vector getBottomRightCorner() { | |
return new Vector( | |
this.position.x + this.size.getWidth(), | |
this.position.y + this.size.getHeight()); | |
} | |
public double getTop() { | |
return this.position.getY(); | |
} | |
public double getBottom() { | |
return this.position.getY() + this.size.getHeight(); | |
} | |
public double getLeft() { | |
return this.position.getX(); | |
} | |
public double getRight() { | |
return this.position.getX() + this.size.getWidth(); | |
} | |
public List<Line> getLines() { | |
ArrayList<Line> lines = new ArrayList<Line>(); | |
lines.add(new Line(this.getTopLeftCorner(), this.getTopRightCorner())); | |
lines.add(new Line(this.getTopRightCorner(), this.getBottomRightCorner())); | |
lines.add(new Line(this.getBottomLeftCorner(), this.getBottomRightCorner())); | |
lines.add(new Line(this.getTopLeftCorner(), this.getBottomLeftCorner())); | |
return lines; | |
} | |
public List<Line> getConnectingLines(Rectangle b) | |
{ | |
ArrayList<Line> lines = new ArrayList<Line>(); | |
lines.add(new Line(this.getTopLeftCorner(), b.getTopLeftCorner())); | |
lines.add(new Line(this.getTopRightCorner(), b.getTopRightCorner())); | |
lines.add(new Line(this.getBottomLeftCorner(), b.getBottomLeftCorner())); | |
lines.add(new Line(this.getBottomRightCorner(), b.getBottomRightCorner())); | |
return lines; | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package nl.tomsanders.game.egine.util; | |
public class Vector | |
{ | |
public final double x; | |
public final double y; | |
public Vector(double x, double y) | |
{ | |
this.x = x; | |
this.y = y; | |
} | |
public Vector(Vector v) | |
{ | |
this.x = v.getX(); | |
this.y = v.getY(); | |
} | |
public double getX() | |
{ | |
return this.x; | |
} | |
public double getY() | |
{ | |
return this.y; | |
} | |
public double getLength() | |
{ | |
return Math.sqrt(this.getLengthSquared()); | |
} | |
public double getLengthSquared() | |
{ | |
return this.x * this.x + this.y * this.y; | |
} | |
public Vector subtract(Vector b) | |
{ | |
return new Vector( | |
this.getX() - b.getX(), | |
this.getY() - b.getY()); | |
} | |
// ... | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment