package chu.engine;
/**
* Abstract class that determines how an object deals with collisions.
* Entities without defined hitboxes cannot collide with other objects.
* Entities with defined hitboxes will consult their hitbox for collision
* detection. Child classes of Hitbox define how the entity checks for
* collision.
* @author Shawn
*
*/
public class Hitbox {
protected Entity parent;
protected float offsetX;
protected float offsetY;
public Hitbox(Entity p, int x, int y) {
parent = p;
offsetX = x;
offsetY = y;
}
public float getX() {
return parent.x + offsetX;
}
public float getY() {
return parent.y + offsetY;
}
public static int collisionExists(Entity e, Entity f, int x, int y) {
Hitbox a = e.hitbox;
Hitbox b = f.hitbox;
if(a instanceof RectangleHitbox) {
RectangleHitbox r1 = (RectangleHitbox)a;
if(b instanceof RectangleHitbox) {
RectangleHitbox r2 = (RectangleHitbox)b;
return checkCollision(r1, r2, x, y);
} else if(b instanceof LineHitbox) {
LineHitbox l2 = (LineHitbox)b;
return checkCollision(r1, l2, x, y);
}
} else if(a instanceof LineHitbox) {
LineHitbox l1 = (LineHitbox)a;
if(b instanceof RectangleHitbox) {
RectangleHitbox r2 = (RectangleHitbox)b;
return checkCollision(r2, l1, x, y);
} else if(b instanceof LineHitbox) {
LineHitbox l2 = (LineHitbox)b;
return checkCollision(l1, l2, x, y);
}
}
return -1;
}
public static int collisionExists(Entity e, Entity f) {
return collisionExists(e, f, 0, 0);
}
//@Override
public static int checkCollision(RectangleHitbox rect, LineHitbox line, int offsetX, int offsetY) {
//Liang-Barsky algorithm incoming.
int x0 = (int)line.getX();
int y0 = (int)line.getY();
int x1 = (int)line.getEndX();
int y1 = (int)line.getEndY();
int xmin = (int)(rect.getX() + offsetX);
int ymin = (int)(rect.getY() + offsetY);
int xmax = (int)(xmin + rect.getWidth());
int ymax = (int)(ymin + rect.getHeight());
int dx = x1 - x0;
int dy = y1 - y0;
double u0 = 0; //For a line defined as x = x0 + u*dx, and y = y0 + u*dy
double u1 = 1; //basically how far along the line the intersection is
for(int k=0; k<4; k++) {
double p,q;
if(k == 0) { //Left
p = -dx;
q = x0 - xmin;
} else if(k == 1) { //Right
p = dx;
q = xmax - x0;
} else if(k == 2) { //Up
p = -dy;
q = y0 - ymin;
} else { //Down
p = dy;
q = ymax - y0;
}
//Check for parallel lines (p == 0)
if(p == 0) {
//If q < 0, then the line is completely outside: eliminate
if(q < 0) return -1;
} else {
double r = q/p;
//If p < 0, then the line goes from outside to inside.
if(p < 0) {
if(r > u1) return -1;
if(r > u0) u0 = r;
}
//If p > 0, then the line goes from inside to outside.
if(p > 0) {
if(r < u0) return -1;
if(r < u1) u1 = r;
}
}
}
return 1;
}
public static double getIntersection(RectangleHitbox rect, LineHitbox line, int offsetX, int offsetY) {
//Liang-Barsky algorithm incoming.
float x0 = line.getX();
float y0 = line.getY();
float x1 = line.getEndX();
float y1 = line.getEndY();
float xmin = rect.getX() + offsetX;
float ymin = rect.getY() + offsetY;
float xmax = xmin + rect.getWidth();
float ymax = ymin + rect.getHeight();
float dx = x1 - x0;
float dy = y1 - y0;
double u0 = 0; //For a line defined as x = x0 + u*dx, and y = y0 + u*dy
double u1 = 1; //basically how far along the line the intersection is
for(int k=0; k<4; k++) {
double p,q;
if(k == 0) { //Left
p = -dx;
q = x0 - xmin;
} else if(k == 1) { //Right
p = dx;
q = xmax - x0;
} else if(k == 2) { //Up
p = -dy;
q = y0 - ymin;
} else { //Down
p = dy;
q = ymax - y0;
}
//Check for parallel lines (p == 0)
if(p == 0) {
//If q < 0, then the line is completely outside: eliminate
if(q < 0) return -1;
} else {
double r = q/p;
//If p < 0, then the line goes from outside to inside.
if(p < 0) {
if(r > u1) return -1;
if(r > u0) u0 = r;
}
//If p > 0, then the line goes from inside to outside.
if(p > 0) {
if(r < u0) return -1;
if(r < u1) u1 = r;
}
}
}
return u0;
}
private static int checkCollision(RectangleHitbox a, RectangleHitbox b, int offsetX, int offsetY) {
if((int)(a.getX()+offsetX) >= (int)(b.getX() + b.getWidth())) return -1;
if((int)(a.getX()+offsetX + a.getWidth()) <= (int)(b.getX())) return -1;
if((int)(a.getY()+offsetY) >= (int)(b.getY() + b.getHeight())) return -1;
if((int)(a.getY()+offsetY + a.getHeight()) <= (int)(b.getY())) return -1;
return 1;
}
private static int checkCollision(LineHitbox a, LineHitbox b, int offsetX, int offsetY) {
float first, second;
float aX = a.getX() + offsetX;
float aY = a.getY() + offsetY;
float bX = a.getEndX() + offsetX;
float bY = a.getEndY() + offsetX;
float cX = b.getX();
float cY = b.getY();
float dX = b.getEndX();
float dY = b.getEndY();
first = aX*(bY-cY) + bX*(cY-aY) + cX*(aY-bY);
second = aX*(bY-dY) + bX*(dY-aY) + dX*(aY-bY);
if(first < 0 && second < 0) return -1;
if(first > 0 && second > 0) return -1;
return 1;
}
}