Collision detection: Shapes overlap even after using intersects method - java

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

Related

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.

Extracting the Silhouettes Coordinates

From the image I posted up there, I have all the coordinates from those rectangles in the Figure C saved in an array of the class Figure.
Figure:
public abstract class Figure {
private int left, right, height;
protected Coordinates[] coords;
public Figure() {
}
public Figure(int left, int right, int height, Coordinates[] coords) {
this.left = left;
this.right = right;
this.height = height;
this.coords = coords;
}
public int getRight() {
return right;
}
public int getLeft() {
return left;
}
public int getHeight() {
return height;
}
public Coordinates[] getCoords() {
return coords;
}
public abstract void setCoordinates();
public abstract void showCoordinates();
}
Coordinates:
public class Coordinates {
private float x, y;
public Coordinates() {
}
public Coordinates(float x, float y) {
this.x = x;
this.y = y;
}
public float getX() {
return x;
}
public float getY() {
return y;
}
}
Thing is, I have to find the coordinates of the silhouette from the whole graph the way it is in Figure D (see the image) using the coordinates from the array already mentioned.
Example (See the Image Reference):
1st Rectangle Coordinates are: (1,0)(1,11)(5,11)(5,0)
2nd Rectangle Coordinates are: (2,0)(2,6)(7,6)(7,0)
3rd Rectangle Coordinates are: (3,0)(3,13)(9,13)(9,0)
4th Rectangle Coordinates are: (12,0)(12,7)(16,7)(7,0)
5th Rectangle Coordinates are: (14,0)(14,3)(25,3)(25,0)
6th Rectangle Coordinates are: (19,0)(19,18)(22,18)(22,0)
7th Rectangle Coordinates are: (23,0)(23,13)(29,13)(29,0)
8th Rectangle Coordinates are: (24,0)(24,4)(28,4)(28,0)
The Coordinates of the Silhouettes from all those rectangles should be:
(1,11)(3,13)(9,0)(12,7)(16,3)(19,18)(22,3)(23,13)(29,0)
This is where I'm stuck thinking how I'll get these coordinates.
I'm not asking someone to do it for me or something like that, I just want to think from where to start cause all I've tried failed so far, so any tips or ideas would come in handy! thank you so much in advance! Good nite.
It looks like you are attempting to obtain the union of each cluster of overlapping rectangles. Java's java.awt.geom.Rectangle class has a createUnion(Rectangle2D) method that will 'absorb' a second rectangle into the first (via a 'union'). However, this doesn't solve your clustering problem.
If the the number of rectangles you are trying to process is relatively small and clustering is only needed in one dimension (i.e. horizontally), the most straight-forward way would be to keep a list of rectangles that haven't already been clustered, loop through each unclustered rectangle, remove the first rectangle into its own new 'cluster' and then perform an intersect with all other unclustered rectangles to determine if the pair should be clustered. The java.awt.geom.Rectangle2D.intersects(Rectangle) method is perfectly suitable for this. If they intersect then the rectangle that intersects should be removed from the list of unclustered rectangles and added to the current cluster.
The Rectangle2D class doesn't quite match your storage of coordinates, but a mapping will be reasonably straight forward.
Once you have your sets of clustered rectangles, you still need to find the path of each Polygon that bounds all rectangles in a given cluster. If your sample picture is indicative of all rectangles such that they all have their bottom edge at the same 'height' and none of your rectangles have different rotations, this will be a lot easier.

Break Out Collision Detection

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.

Robot crosses boundary on collision rather than bounce back while implementing particle filter

I have written the following code, where I am trying to create a particle filter. The problem I am facing is that even after using intersects method and other conditions, the robot sometimes overlaps the obstacles. Moreover, it goes out of boundary through upper left corner after wobbling again and again with the corner.
I check for the collisions and then if it seems there is a collision I move the robot by amount x in the reverse direction.
I calculate amount x by the following method, where x means current position.
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);
}
I am using the following code to check the collisions:
private void adjustRobotOrientation(Graphics2D g)
{
int x=robot_x;
int y=robot_y;
if((x<0)&&(y<0))
{
robot_orientation=robot_orientation+randomDouble(160, 180);
}
if((x>620)||((y>395))||((x<1))||((y<1)))
{
robot_orientation=robot_orientation+randomDouble(160, 220);
}
}
private void collisionAvoidanceRobot(int x, int y, int r)
{
boolean collide1=false;
boolean collide2=false;
boolean collide3=false;
boolean collide4=false;
boolean collide5=false;
boolean collide6=false;
x+=unit_moved;
y+=unit_moved;
Shape collisionrobot=new Ellipse2D.Double(x,y,r,r);
collide1=collisionrobot.intersects(obst1);
if(collide1)
{
robot_orientation=robot_orientation+randomDouble(160, 220);
}
collide2=collisionrobot.intersects(obst2);
if(collide2)
{
robot_orientation=robot_orientation+randomDouble(160, 220);
}
collide3=collisionrobot.intersects(obst3);
if(collide3)
{
robot_orientation=robot_orientation+randomDouble(160, 220);
}
collide4=collisionrobot.intersects(obst4);
if(collide4)
{
robot_orientation=robot_orientation+randomDouble(160, 220);
}
collide5=collisionrobot.intersects(obst5);
if(collide5)
{
robot_orientation=robot_orientation+randomDouble(160, 220);
}
collide6=collisionrobot.intersects(obst6);
if(collide6)
{
robot_orientation=robot_orientation+randomDouble(160, 220);
}
}
If you want to see, the complete code is in two files:
1. http://pastebin.com/ZYfSzptc (main class)
2. http://pastebin.com/hqTTyq5n
If a robot's velocity causes it to move past an obstacle between clock ticks, no collision will be detected. You can
Use finer ticks and larger objects to preclude the effect, as shown in the KineticModel cited here.
Anticipate the effect and compensate for it, as shown here.
Both examples use the vector approach cited here.

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