Hi! I’ve got some issues with collision detection in a game me and a couple of other guys are working on.
It’s a 2D game where you move a player around in a world filled with other collidable objects (enemies, walls, etc.). The entities (subclasses of CollidableObject
) should collide with each other. I’m using the Java class Rectangle
for the objects’ collision boxes.
Rectangle
has two handy methods I’m using below: intersects
and outcode
. I’m using outcode when checking in which direction another given collidable object is, in order to block that direction.
/**
* Check whether this object is colliding with another CollidableObject.
*
* The objects are colliding if their collision boxes intersect.
*
* @param obj The specified CollidableObject
* @return True if the objects are colliding, false otherwise
*/
public boolean isColliding(CollidableObject obj){
return this.collisionBox.intersects(obj.getCollisionBox());
}
public Direction getCollisionDirection(CollidableObject obj) {
int code = this.collisionBox.outcode(obj.getCollisionBox().getLocation());
Direction d = Direction.ORIGIN;
boolean top = false, bottom = false, right = false, left = false;
if((code & Rectangle.OUT_TOP) == Rectangle.OUT_TOP)
top = true;
if((code & Rectangle.OUT_RIGHT) == Rectangle.OUT_RIGHT)
right = true;
if((code & Rectangle.OUT_LEFT) == Rectangle.OUT_LEFT)
left = true;
if((code & Rectangle.OUT_BOTTOM) == Rectangle.OUT_BOTTOM)
bottom = true;
if(top && left)
d = Direction.NORTH_WEST;
else if(top && right)
d = Direction.NORTH_EAST;
else if(top)
d = Direction.NORTH;
else if(left && bottom)
d = Direction.SOUTH_WEST;
else if(right && bottom)
d = Direction.SOUTH_EAST;
else if(left)
d = Direction.WEST;
else if(right)
d = Direction.EAST;
else if(bottom)
d = Direction.SOUTH;
return d;
}
Below is the relevant code in the main game loop. entities
is a List with all the entities in the game.
/**
* Updates the game model.
* @param dt The time since the last update.
*/
public void update(double dt) {
moveEntities(dt);
}
private void moveEntities(double dt) {
for(Entity t : this.entities) {
checkCollisions(t);
t.move(dt);
}
}
private void checkCollisions(Entity t) {
for(Entity w : this.entities) {
// This baby is in need of a grave refactor :)
boolean stop = false;
if(t != w && t.isColliding(w)) {
Direction currentDirection = t.getDirection();
Direction blockedDirection = t.getCollisionDirection(w);
if(t != w && t instanceof Player){
System.out.println("-----\nPlayer direction: "+currentDirection);
System.out.println("Collision direction: "+blockedDirection);
int c = t.getCode(w);
System.out.println("CODE: "+c);
System.out.println("Top: "+ ((c & Rectangle.OUT_TOP) == Rectangle.OUT_TOP));
System.out.println("Bottom: "+ ((c & Rectangle.OUT_BOTTOM) == Rectangle.OUT_BOTTOM));
System.out.println("Left: "+ ((c & Rectangle.OUT_LEFT) == Rectangle.OUT_LEFT));
System.out.println("Right: "+ ((c & Rectangle.OUT_RIGHT) == Rectangle.OUT_RIGHT));
}
System.out.println("----------\n"+t);
System.out.println(w+"\n------------");
if( (blockedDirection == Direction.NORTH_WEST ||
blockedDirection == Direction.WEST)
&& (currentDirection == Direction.WEST ||
currentDirection == Direction.NORTH_WEST ||
currentDirection == Direction.NORTH)) {
stop = true;
}
if( (blockedDirection == Direction.NORTH_EAST ||
blockedDirection == Direction.EAST)
&& (currentDirection == Direction.EAST ||
currentDirection == Direction.NORTH_EAST ||
currentDirection == Direction.NORTH) ){
stop = true;
}
if( (blockedDirection == Direction.SOUTH_WEST ||
blockedDirection == Direction.WEST)
&& (currentDirection == Direction.WEST ||
currentDirection == Direction.SOUTH_WEST ||
currentDirection == Direction.SOUTH) ){
stop = true;
}
if( (blockedDirection == Direction.SOUTH_EAST ||
blockedDirection == Direction.EAST)
&& (currentDirection == Direction.EAST ||
currentDirection == Direction.SOUTH_EAST ||
currentDirection == Direction.SOUTH)){
stop = true;
}
if(blockedDirection == currentDirection){
stop = true;
}
if(stop)
t.stop();
}
}
}
Direction
is an enum with the eight directions (N, S, E, W, NE, NW, SE, SW).
The problem: it’s only working in some directions. If the player moves to another object from north or west, collisions aren’t working. I’ve debugged the code, and it indeed does run through the code above. The printouts are showing legit results, but still the if blocks aren’t catching the correct direction.
I can’t for my life figure out why it’s only north and west. My unit tests are (supposedly) testing this (green).
I’d deeply appreciate any assistance. The project code is located in a repo at GitHub: https://github.com/johanbrook/medioqre/
Thanks!