Break Out Collision Detection - java

I'm experimenting with a simple Break Out clone to get an understanding of Game States, Game Loops etc.
One of the things I'm having difficulty with is the collision detection.
I have a GameItem class that is extended by Ball, Brick and Paddle. In this class I have a getBounds() method to return the bounding Rectangle of the object, a collision(GameItem item) method to determine whether 2 GameItem objects have collided as well as methods for hitTop(), hitBottom(), hitLeft() and hitRight() to determine which side the object collided with the other.
These methods are as follows:
public Rectangle getBounds()
{
return new Rectangle(x, y, width, height);
}
public boolean collision(GameItem item)
{
return getBounds().intersects(item.getBounds());
}
public boolean hitTop(GameItem item)
{
return getY()+getHeight()>=item.getY();
}
public boolean hitLeft(GameItem item)
{
return getX()+getWidth()>=item.getX();
}
public boolean hitBottom(GameItem item)
{
return getY()<=item.getY()+item.getHeight();
}
public boolean hitRight(GameItem item)
{
return getX()<=item.getX()+item.getWidth();
}
The ball class has a method called checkBallCollissions(GameItem item) to determine when the ball has hit another object. This is as follows:
public boolean checkBallCollisions(GameItem item)
{
if(this.collision(item))
{
if(this.hitTop(item))
{
this.setVY(-1*this.getVY());
return true;
}
else if(this.hitBottom(item))
{
this.setVY(-1*this.getVY());
return true;
}
else if(this.hitLeft(item))
{
this.setVX(-1*this.getVX());
return true;
}
else if(this.hitRight(item))
{
this.setVX(-1*this.getVX());
return true;
}
return false;
}
return false;
}
Which would be called as follows:
ball.checkBallCollisions(paddle);
As you can see, if it hits one of the 4 edges, the x/y direction is reversed accordingly.
However, this doesn't work. Analysing the code it seems there's an obvious issue that I can't fathom a solution to.
The 3 images below show a collision of the ball with an object from above, below and the right.
With the code as it is, it first detects a collision based on the bounding Rectangles and the intersects() method. It then determines which side it hit. If it hits from above it works. However, when it hits form the bottom or right then hitTop() will return true since getY()+getHeight()>=item.getY() is true for both these cases (i.e the bottom edge of the ball has a greater y value than the top edge of the object it's colliding with).
What conditions am I missing to resolve this and have perfect collision detection?

for circles you use the circle's radius rather than bounds, as bounds is a rectangle.
i believe there are methods for doing that in java but i do not know them yet, so a little research should do it.
also, for advanced collision people tend to use vectors, again i never fiddled with them before so you will have to research that as well.
here is something to get you going:
Java area and intersection

The issue here is that as you mentioned
"hitTop() will return true since getY()+getHeight()>=item.getY() is true for both these cases (i.e the bottom edge of the ball has a greater y value than the top edge of the object it's colliding with)."
In order to fix this you also need a check to ensure that the y position of the circle is less than the y position of the gameobject + height of gameobject (possibly subtracting some offset from it as well).
Which should look something like this (not worrying about offset):
public boolean hitTop(GameItem item)
{
return getY() + getHeight() >= item.getY() &&
getY() < item.getY() + item.getHeight();
}
You will need to do this for all of the collisions.

Related

Java chess game: how to check whether a piece is already on the tile?

I´m currently programming my first chess game and I have a small problem with my pieces. I´ll add some of my code below, but generally, I would like to check whether the tile a player moves a certain piece (in this example the king) to, is already occupied by another piece because in that case the other piece would either be killed (if the piece belongs to the other player) or the move would be false (tile occupied by own piece).
If you have any ideas how it could be done, I´d appreciate it greatly.
Best regards
public abstract class Piece
{
protected int x;
protected int y;
protected Tile finalTile;
protected Type type;
protected boolean killed;
protected boolean white;
public Piece(boolean white, int x, int y)
{
this.setWhite(white);
this.x = x;
this.y = y;
this.finalTile = finalTile;
}
public boolean isWhite() {
return this.white;
}
public void setWhite (boolean white) {
this.white = white;
}
public boolean isKilled() {
return this.killed;
}
public void setKilled (boolean killed) {
this.killed = killed;
}
// which type of Piece is being used
public abstract Type getType();
//is the chosen move valid?
public abstract boolean canMovePiece (Chessboard chessboard, int finalX, int finalY);
//The validation of the move does not show in which direction the piece is being moved. To set
the piece at its new spot (tile), a determination of the direction is needed for the
// calculation of the new spot on the chessboard
public abstract void setNewPieceLocation();
}
public class King extends Piece
{
public King(boolean white, int x, int y)
{
super(white, x, y);
type = Type.KING;
}
public Type getType() {
return Type.KING;
}
#Override
public boolean canMovePiece(Chessboard chessboard, int finalX, int finalY) {
int x_diff = Math.abs(finalX - this.x);
int y_diff = Math.abs(finalY - this.y);
//the king can only move one tile per round. The direction does not matter. Therefore, the
movements can be either one on the x-axis, the y-axis or one on both.
if ( x_diff == 1 && y_diff == 0 || x_diff == 0 && y_diff == 1 || x_diff == 1 && y_diff ==1) {
return true;
}
}
#Override
public void setNewPieceLocation() {
int finalX = this.x;
int finalY = this.y;
}
}
In tile-based computer games, you always have to make a very important initial design decision about what you choose as your central data structure:
The field itself, e.g. as a two-dimensional array, where the state of each tile in the field represents which piece is on it or
A collection of pieces with coordinates.
Option 1 is great if you have a small field and the pieces can only be directly on a tile.
Option 2 should only be done if option 2 is not possible, i.e.:
your game world is very large and sparse, e.g. 1 million x 1 million, then you would have an array with one trillion entries or (inclusive or)
your pieces can be halfway or otherwise fractionally located respectively with the tiles
Option 1 is easiest to implement if there is at most one piece at any one tile at the same time but you can work around that and it would depend on the specific circumstances, which one is best.
Now which case do we have in chess? As an exercise you can think about this yourself but I will give the solution below:
The first option is the perfect fit for chess, because you have a very small field (8x8), the pieces are exactly on the tiles (in theory, even if they may be a few millimeters off in practice) and there can be at most one piece per tile.
Option 1 has the advantage that it becomes extremely easy to check, which piece is on a certain tile: just check the field data structure at that point!
Another very important point for beginners is however how to map your coordinate system to your data structure especially in the case of a two dimensional array. Which dimension of the array is which axis of your game world and in which direction? There is however no right or wrong here, just clearly document it and be consistent!
For example, I personally like to have y going from top to bottom as the first dimension of the array and x going from left to right as field[y][x] because computer graphics memory is aligned that way (at least it was this way in the old 10h 320x200 8 bit palette video mode) but a mathematics teacher may very well prefer x first and y going from bottom to top as field[x][y] because that's how you usually draw 2-dimensional plots and write points with x first in mathematical notation.
So in my mental model, checking the top left would be checking the value field[0][0], top right would be field[0][7], bottom left field[7][0] and bottom right would be field[7][7].
Our hypothetical mathematics teacher could instead use field[0][7] for top left, top right would be field[7][7], bottom left field[0][0] and bottom right would be field[7][0].
Just use what works for you (and your team if you have one).
In order to prevent problems with object equality vs object identity I would not use a class for the type but an enum as that is the perfect fit for this case. As an empty field, you can either use null, but then you may need a bunch of checks to prevent NullPointerException, or you create a special value for an empty field.
Checking, which piece is in a certain spot with option 2 is not hard either, but as option 1 is so much easier here and also faster in case that matters, I will not get into detail about that here as that is not the best solution to your problem.

My game collision system doesn't work on more than one tile

I'm working on a collision system for my game, however I can't get it to work, if I add more than one wall (which is the object I'm rendering) the collision system doesn't work and I can get through the block.
However if I leave only one wall the collision works correctly, or if at the end of the loop I add a break;
the collision works but only on the first wall of the map, the others don't get the collision.
Would anyone know how to solve this? I've been trying to solve it for 2 days and I couldn't.
public boolean checkCollisionWall(int xnext, int ynext){
int[] xpoints1 = {xnext+3,xnext+3,xnext+4,xnext+3,xnext+3,xnext+4,xnext+10,xnext+11,xnext+11,xnext+10,xnext+11,xnext+11};
int[] ypoints1 = {ynext+0,ynext+8,ynext+9,ynext+11,ynext+12,ynext+15,ynext+15,ynext+12,ynext+11,ynext+9,ynext+8,ynext+0};
int npoints1 = 12;
Polygon player = new Polygon(xpoints1,ypoints1,npoints1);
Area area = new Area(player);
for(int i = 0; i < Game.walls.size(); i++){
Wall atual = Game.walls.get(i);
int[] xpoints2 = {atual.getX(),atual.getX(),atual.getX()+16,atual.getX()+16};
int[] ypoints2 = {atual.getY(),atual.getY()+16,atual.getY()+16,atual.getY()};
int npoints2 = 4;
Polygon Wall = new Polygon(xpoints2,ypoints2,npoints2);
area.intersect(new Area(Wall));
if(area.isEmpty()){
return true;
}
}
return false;
}
I'm pretty sure the problem is this call:
area.intersect(new Area(Wall));
Here's the JavaDoc for that method:
public void intersect(Area rhs)
Sets the shape of this Area to the intersection of its current shape
and the shape of the specified Area. The resulting shape of this Area
will include only areas that were contained in both this Area and also
in the specified Area.
So area, which represents the shape of your player, is going to be modified by each test with a wall, which is why it's only working with one wall.
You could fix the issue by simply making the player Area the argument of the call, as in:
Area wallArea = new Area(Wall);
wallArea.intersect(area);
if(wallArea.isEmpty()){
return true;
}
By the way, this logic is reversed isn't it. Don't you want to check that the resulting area is not empty, i.e. there was an overlap between the player and the wall?
The other option, if each Wall is actually a rectangle, would be to use the this Area method instead:
public boolean intersects(double x,
double y,
double w,
double h)
Tests if the interior of the Shape intersects the interior of a
specified rectangular area. The rectangular area is considered to
intersect the Shape if any point is contained in both the interior of
the Shape and the specified rectangular area.
Something like this:
if(area.intersects(atual.getX(), atual.getY(), 16, 16)) {
return true;
}
As this avoids the creation of an Area object for each wall, and the intersection test is going to be much simpler, and faster.

Need algorithmic help in Minesweeper regarding revealing adjacent tiles

I am writing a simple minesweeper, but I can't find a way to reveal the adjacent tiles properly. If a tile is blank, it is revealed and then the algorithm reveals all adjacent blank tiles. However I would like to reveal a layer of non blank tiles as well, just like the real minesweeper.
Here is my code:
void revealAdjCells(Tile [][] t,int x, int y) {
if (!checkBounds(x,y)) {
return; // check for bounds
}
if ((t[x][y].getNeighbours() == 0) && (!t[x][y].getVisibleState())) { // NO neighbours and not revealed
t[x][y].setVisibleState(true); // reveal tile
revealAdjCells(t,x+1,y); // recursion, reveal adjacent tiles
revealAdjCells(t,x-1,y);
revealAdjCells(t,x,y-1);
revealAdjCells(t,x,y+1);
}
else
{
return;
}
}
getNeighbours() returns the amount of bombs that surround a nearby tile (horizontal,vertical,diagonal) and getVisibleState() returns a boolean that indicates whether a tile has been revealed or not.
Things that I have tried:
1) Removing getVisibleState() from if condition (terrible idea, leads obviously to stack overflow).
2) Checking bounds (x-1,x+1,y+1,y-1) and then revealing the tiles accordingly (doesn't work, getVisibleState() won't let the statement execute, because the tile that is examined by the recursion is already revealed).
So... yeah... I am stuck and I can't find a solution. Any algorithmic help is appreciated.
Your code is close, but you're not revealing the tile if t[x][y].getNeighbours() != 0 and you should be doing this. Perhaps something like:
void revealAdjCells(Tile [][] t,int x, int y) {
// if out of bounds **or** if already revealed, return
if (!checkBounds(x,y) || t[x][y].getVisibleState()) {
return;
}
t[x][y].setVisibleState(true); // reveal tile **here **
// do recursion only if no neighbors
if (t[x][y].getNeighbours() == 0) {
// t[x][y].setVisibleState(true); // not **here**
revealAdjCells(t,x+1,y);
revealAdjCells(t,x-1,y);
revealAdjCells(t,x,y-1);
revealAdjCells(t,x,y+1);
} else {
return;
}
}

Collision detection: Shapes overlap even after using intersects method

I am writing a code in which a circle moves randomly in a box and if it collides with any of the small rectangles inside it, it changes its heading direction/ bounces back. I am using the intersects method to find the collision between them. But the circle sometimes overlaps the rectangles rather than bouncing back on contact. I am bouncing back the ball by changing the orientation (180+current_orientation).
I am trying to solve this issue, but did not found any success yet. I read that intersects is finding the match by checking overlap of the bounding rectangles. But, how can I fix this issue. Is this problem due to the intersection or is there any issue with the way i am changing orientation. Any idea?
Code:
private void collisionAvoidanceRobot(int x, int y, int r, double robot_orientation2)
{
boolean collide1=false;
boolean collide2=false;
boolean collide3=false;
boolean collide4=false;
boolean collide5=false;
boolean collide6=false;
r+=5;
Shape collisionrobot=new Ellipse2D.Double(x,y,r,r);
collide1=collisionrobot.intersects(obst1);
if(collide1)
{
robot_orientation=180+robot_orientation;
}
collide2=collisionrobot.intersects(obst2);
if(collide2)
{
robot_orientation=180+robot_orientation;
}
collide3=collisionrobot.intersects(obst3);
if(collide3)
{
robot_orientation=180+robot_orientation;
}
collide4=collisionrobot.intersects(obst4);
if(collide4)
{
robot_orientation=180+robot_orientation;
}
collide5=collisionrobot.intersects(obst5);
if(collide5)
{
robot_orientation=180+robot_orientation;
}
collide6=collisionrobot.intersects(obst6);
if(collide6)
{
robot_orientation=180+robot_orientation;
}
}
public void setXPosition_robot(int x)
{
double distance=0;
distance = unit_moved + randomDouble(0, forwardNoise);
robot_x= (int) (x + Math.sin(Math.toRadians(robot_orientation))*distance);
//System.out.println("Robot_X:"+robot_x);
}
public void setYPosition_robot(int y)
{
double distance=0;
distance = unit_moved + randomDouble(0, forwardNoise);
robot_y=(int) (y+ Math.cos(Math.toRadians(robot_orientation))*distance);
//System.out.println("Robot_Y:"+robot_y);
}
private void createRobot(Graphics2D g)
{
ArrayList<Integer> robot_list= new ArrayList<Integer>();
robot_list=positionRobot(robot_x,robot_y);
robot_x=robot_list.get(0);
robot_y=robot_list.get(1);
setNoise(0.05,0.05,5.0);
//System.out.println("Robot:"+robot_x+"--"+robot_y+"--"+robot_orientation);
adjustRobotOrientation();
collisionAvoidanceRobot(robot_x,robot_y,robot_radius,robot_orientation);
drawRobot(g,robot_x,robot_y,robot_radius);
}
Screenshot:
Does the circle appear to wobble? since you are moving the circle a random distance each iteration, the distance that it moved into the square could be greater than the distance it gets on the next iteration to move in the opposite direction, this would cause the circle to "stick".
also, your collisionAvoidanceRobot could use a for loop instead of all those ifs

Java Gaming collision detection, (side collision) with rectangles

I have been writing a Game Engine and I have a problem with my actor class. I want to determine the collision with a rectangle (above) and a side of a rectangle. I had written two methods for them.
public boolean isLeftCollision(Actor actor) {
boolean bool = false;
Rectangle LeftBounds = new Rectangle(x, y, x-velocity, image.getHeight(null));
bool = LeftBounds.intersects(actor.getBounds());
return bool;
}
public boolean isRightCollision(Actor actor) {
boolean bool = false;
Rectangle RightBounds = new Rectangle(x+image.getWidth(null), y, image.getWidth(null)+velocity, image.getHeight(null));
bool = RightBounds.intersects(actor.getBounds());
return bool;
}
Here velocity is the movement for next step.
But they both give me error (ie., false judgements). How can I solve this in the actor class.
I admit I can hardly read your code and I'm sorry if my answer isn't helpful. My guess is that the velocity in the collision produces the errors. Depending on how often you check and what values velocity holds you might register collisions that haven't occured yet...
I'd do the collision detection in two steps.
Test for a collision
Determine if it's above or to one side.
here's some pseudocode:
Rectangle self_shape=this.getBounds();
Rectangle other_shape=actor.getBounds();
bool collision = self_shape.intersects(other_shape);
if(collision){
//create two new variables self_centerx and self_centery
//and two new variables other_centerx and other_centery
//let them point to the coordinates of the center of the
//corresponding rectangle
bool left=self_centerx - other_centerx<0
bool up=self_centery - other_centery<0
}
That way you can look where the other actor is positioned relative to you. If it's above or to one side.
Remember that the third parameter to Rectangle is the width, not the x of the other side. So, what you really want is probably like this:
public boolean isLeftCollision(Actor actor) {
return new Rectangle(x - velocity, y, velocity, image.getHeight(null))
.intersects(actor.getBounds());
}
public boolean isRightCollision(Actor actor) {
return new Rectangle(x + image.getWidth(null), y, velocity, image.getHeight(null))
.intersects(actor.getBounds());
}
(Assuming velocity is the (positive) distance to move left or right, and only the method for the direction you are moving will be called)

Categories

Resources