Reputation: 1048
I'm building a top-down 2D scroller using java swing with very similar gameplay to that of the classic game Bomberman, where the player can move the character in all 4 cardinal directions.
All the game objects have instance variables containing the (x,y) coordinates of where they are to be rendered on the JPanel, they also have instance variables for the previous (x,y) coordinate where they were rendered in the last frame. My collision detection algorithm essentially checks to see if the player object intersects one of the walls present in the grid every time we refresh the screen - This can be seen in the bit of code below:
if (playerRectangle.intersects(wallRectangle)) {
player.restorePreviousPosition();
}
The restorePreviousPosition() method sets the (x,y) coordinates of the player to what they were before the collision occurred. This methods works fine, it prevents the player from going through objects. However, the controls seem very jagged because if the player is, for example, trying to move left and up while in contact with a wall, the character remains still. In other words, the character can't touch a wall and still move parallel to it. In order to fix this problem I created four rectangles drawn on top of the player object that I use to determine the side that is colliding with another object, so that instead of restoring the (x,y) coordinates I can restore x or y depending on which side is colliding. For example, if I know that the top is colliding with something, then I can restore the y position and allow the x to change freely. Below you can see a picture of the player object with the rectangles drawn on it:
This idea is very unreliable, specially in corners where it is difficult to determine from which side the collision is coming from. So, my question is, how can I reliably determine which side of a rectangle is colliding with another rectangle in java using swing? Or, do you have a better alternative to my approach towards detecting collisions?
Note that player movement is completely free, my implementation doesn't snap the character from tile to tile. And that the distance between tiles is 32x32 pixels, and the player is 30x30 pixels.
Thank you for the help. If you have any extra questions about my implementation, please let me know.
Upvotes: 3
Views: 2786
Reputation: 11
rects.stream().forEach((re) ->
{
double w = 0.5 * (re.width + player.width);
double h = 0.5 * (re.height + player.height);
double dx = re.getCenterX() - player.getCenterX();
double dy = re.getCenterY() - player.getCenterY();
if (abs(dx) < w && abs(dy) < h)//collision
{
double wy = w * dy;
double hx = h * dx;
if (wy >= hx)
if (wy >= -hx)//top of block
player.y = re.y - player.height;//align edges
else//right of block
player.x = re.x + re.width;//align edges
else
if (wy >= -hx)//left of block
player.x = re.x - player.width;//align edges
else//bottom of block
player.y = re.y + re.height;//align edges
}
});
This will find which side is being hit and correct the player's position to line up with that side's edge. I am using a slightly more complicated version of this code in my game, but the idea is the same. (do this AFTER you reposition your player in your updating method.)
Upvotes: 1
Reputation: 694
One really simple solution (given what you already have written) is to split the code for Test-and-Move into two checks.
//update.player.x.position
if (playerRectangle.intersects(wallRectangle)) {
player.restorePreviousPosition();
}
//update.player.y.position
if (playerRectangle.intersects(wallRectangle)) {
player.restorePreviousPosition();
}
Upvotes: 1
Reputation: 5496
Kind of simple, take a collision that happens at the bottom right corner of some rectangle A by B, and you want to find out if B collided into A more from the right, or more from the bottom. All you have to do is measure how many pixels the top y coordinate of B is above A's lowest y coordinate, and measure how many pixels B's far left x coordinate is to the left of A's far right x coordinate.
If there's more of a difference between the x coordinates than the y coordinates then it's a collision from the bottom, otherwise it's a collision from the side.
Upvotes: 0