Two overlapping rectangles - java

I'm having a lot of trouble figuring out what is wrong with my code. Actually, I'm having a very difficult time solving the problem of two rectangles overlapping. The following code should, theoretically, work for the following rectangles:
Rect1: (2.5, 4) width = 2.5, height = 43
Rect2: (1.5, 5) width = 0.5, height = 3
Keep in mind I can't use the Rectangle class to solve this problem. What I've done is calculated the x-values for the left and right edges and the y-values for the top and bottom edges of both rectangles.
I'm first considering -- and I know this does not cover all possible cases -- the scenario in which r2 is within r1.
Note that (x1, y1) and (x2, y2) signify the centers of rectangles 1 and 2, respectively.
right1 = x1 + w1/2;
left1 = x1 - w1/2;
bottom1 = y1 - h1/2;
top1 = y1 + h1/2;
right2 = x2 + w2/2;
left2 = x2 - w2/2;
bottom2 = y2 - h2/2;
top2 = y2 + h2/2;
overlap = ( (right2 < right1 && right2 > left1) &&
(bottom2 > bottom1 && bottom2 < top1) &&
(left2 > left1 && left2 < right1) &&
(top2 < top1 && top2 > bottom1) );
Again, I realize this scenario is not all-encompassing. But even at this point with testing if one rectangle is within another using the above Rect1 and Rect2 values for input, overlap evaluates to false...but it shouldn't -- I've done the math and suggests that the code should work. What did I do wrong?

Rectangles will be overlapping if there is some intersection between both their horizontal and vertical sides - so basically it's a case of checking whether two lines overlap for each dimension.
The check whether a line x1 -> x2 overlaps a line x3 -> x4 is whether the first line starts before the end of the second and ends after its start, or in code:
x1 <= x4 && x2 >= x3
To translate this to rectangles, apply the test to both dimensions:
(x1 <= x4 && x2 >= x3) && (y1 <= y4 && y2 >= y3)
..where one rectangle is x1,y1 -> x2,y2 and the other is x3,y3 -> x4,y4 (easily calculated from a start position and a width).

Related

Libgdx Test if line intersects with rectangle

Is there a way I can test if a Rectangle object collides with a line? Thanks!
EDIT :
public boolean overlapsLineNodes(Vector2 point1, Vector2 point2) {
boolean collide = false;
MapObjects mapObjects = play.getWorld().level.getCurrentLevel().getLayers().get("collidable").getObjects();
Tools.shapeRenderer.setAutoShapeType(true);
Tools.shapeRenderer.setProjectionMatrix(play.getCamera().combined);
Tools.shapeRenderer.begin();
for (RectangleMapObject rectangleObject : mapObjects.getByType(RectangleMapObject.class)) {
rectangle.setX(rectangleObject.getRectangle().x * 1/64f);
rectangle.setY(rectangleObject.getRectangle().y * 1/64f);
rectangle.setWidth(rectangleObject.getRectangle().width * 1/64f);
rectangle.setHeight(rectangleObject.getRectangle().height * 1/64f);
float x1 = rectangle.x, y1 = rectangle.y + rectangle.height,
x2 = rectangle.x + rectangle.width, y2 = rectangle.y + rectangle.height,
x3 = rectangle.x + rectangle.width, y3 = rectangle.y,
x4 = rectangle.x, y4 = rectangle.y;
Vector2 start = point1, end = point2;
float[] floatArray = new float[]{x1, y1, x2, y2, x3, y3, x4, y4};
polygon.setVertices(floatArray);
if (Intersector.intersectLinePolygon(start, end, polygon)) {
Tools.shapeRenderer.setColor(Color.GREEN);
collide = true;
}
Tools.shapeRenderer.line(point1.x, point1.y, point2.x, point2.y);
Tools.shapeRenderer.rect(rectangle.x, rectangle.y, rectangle.width, rectangle.height);
Tools.shapeRenderer.setColor(Color.WHITE);
}
I do this, but it seems not to give me correct results. I am rending all of the rectanglemapobjects in white, and if one collides with the line, then I render it in green. It randomly renders some in green and I cant figure out why.
The problem was that intersectLinePolygon is the wrong method! I should have been using intersectSegmentPolygon.
Compute the intersection of the line with the line defining one edge of the rectangle, determine the whether the intersection point lies between the endpoints of the edge. Repeat with the opposite edge. If you get "yes" to either, they intersect.
You do not need to test all 4 edges; just two opposite edges.
If rectangle edges are parallel to the axis ... [x1,y1]-[x2,y1]-[x2,y2]-[x1,y2] ... and your line in question is y = m*x + b, then this becomes simply:
ya = m*x1 + b;
yb = m*x2 + b;
collision = ((ya < y1) ^ (ya < y2)) || ((yb < y1) ^ (yb < y2));
Or, if you order "ya < yb", you can get more precise over whether just touching a corner is considered a collision:
collision = ((ya <= y1) && (y1 <= yb)) || ((ya <= y2) && (y2 <= yb));
Assuming that you know start and end point of your line and also vertices of rectangle (which you must know to be honest :) ) you can use Intersector's intersectLinePolygon() method just like
//definition of variables - of course you can keep your x... y... in float[] array
float x1 = 0, x2 = 0, x3 = 0, x4 = 0, y1 = 0, y2 = 0, y3 = 0, y4 = 0;
Vector2 start = null, end = null;
//...
//updateing vertices and line start/end points
//...
Intersector.intersectLinePolygon(start, end, new Polygon(new float[]{x1, y1, x2, y2, x3, y3, x4, y4}));
If you are using this in render() method it is not good to create new Polygon() instance every time - better keep one instance somewhere
Polygon p = new Polygon();
and then just update it with vertices just before collision checking
p.setVertices(...);

Java method to find the rectangle that is the intersection of two rectangles using only left bottom point, width and height?

I have found the solution but wanted to ensure my logic is the most efficient. I feel that there is a better way. I have the (x,y) coordinate of the bottom left corner, height and width of 2 rectangles, and i need to return a third rectangle that is their intersection. I do not want to post the code as i feel it is cheating.
I figure out which is furthest left and highest on the graph.
I check if one completely overlaps the other, and reverse to see if the other completely overlaps the first on the X axis.
I check for partial intersection on the X axis.
I basically repeat steps 2 and 3 for the Y axis.
I do some math and get the points of the rectangle based on those conditions.
I may be over thinking this and writing inefficient code. I already turned in a working program but would like to find the best way for my own knowledge. If someone could either agree or point me in the right direction, that would be great!
Why not use JDK API to do this for you?
Rectangle rect1 = new Rectangle(100, 100, 200, 240);
Rectangle rect2 = new Rectangle(120, 80, 80, 120);
Rectangle intersection = rect1.intersection(rect2);
To use java.awt.Rectangle class, the parameters of the constructor are: x, y, width, height, in which x, y are the top-left corner of the rectangle. You can easily convert the bottom-left point to top-left.
I recommend the above, but if you really want to do it yourself, you can follow the steps below:
say (x1, y1), (x2, y2) are bottom-left and bottom-right corners of Rect1 respectively,
(x3, y3), (x4, y4) are those of Rect2.
find the larger one of x1, x3 and the smaller one of x2, x4, say xL,
xR respectively
if xL >= xR, then return no intersection else
find the larger one of y1, y3 and the smaller one of y2, y4, say yT,
yB respectively
if yT >= yB, then return no intersection else
return (xL, yB, xR-xL, yB-yT).
A more Java-like pseudo code:
// Two rectangles, assume the class name is `Rect`
Rect r1 = new Rect(x1, y2, w1, h1);
Rect r2 = new Rect(x3, y4, w2, h2);
// get the coordinates of other points needed later:
int x2 = x1 + w1;
int x4 = x3 + w2;
int y1 = y2 - h1;
int y3 = y4 - h2;
// find intersection:
int xL = Math.max(x1, x3);
int xR = Math.min(x2, x4);
if (xR <= xL)
return null;
else {
int yT = Math.max(y1, y3);
int yB = Math.min(y2, y4);
if (yB <= yT)
return null;
else
return new Rect(xL, yB, xR-xL, yB-yT);
}
As you see, if your rectangle was originally defined by two diagonal corners, it will be easier, you only need to do the // find intersection part.
My variation of determining intersection of two rectangles in a small utility function.
//returns true when intersection is found, false otherwise.
//when returning true, rectangle 'out' holds the intersection of r1 and r2.
private static boolean intersection2(Rectangle r1, Rectangle r2,
Rectangle out) {
float xmin = Math.max(r1.x, r2.x);
float xmax1 = r1.x + r1.width;
float xmax2 = r2.x + r2.width;
float xmax = Math.min(xmax1, xmax2);
if (xmax > xmin) {
float ymin = Math.max(r1.y, r2.y);
float ymax1 = r1.y + r1.height;
float ymax2 = r2.y + r2.height;
float ymax = Math.min(ymax1, ymax2);
if (ymax > ymin) {
out.x = xmin;
out.y = ymin;
out.width = xmax - xmin;
out.height = ymax - ymin;
return true;
}
}
return false;
}
You can also use the Rectangle source code to compare with your own algorithm:
/**
* Computes the intersection of this <code>Rectangle</code> with the
* specified <code>Rectangle</code>. Returns a new <code>Rectangle</code>
* that represents the intersection of the two rectangles.
* If the two rectangles do not intersect, the result will be
* an empty rectangle.
*
* #param r the specified <code>Rectangle</code>
* #return the largest <code>Rectangle</code> contained in both the
* specified <code>Rectangle</code> and in
* this <code>Rectangle</code>; or if the rectangles
* do not intersect, an empty rectangle.
*/
public Rectangle intersection(Rectangle r) {
int tx1 = this.x;
int ty1 = this.y;
int rx1 = r.x;
int ry1 = r.y;
long tx2 = tx1; tx2 += this.width;
long ty2 = ty1; ty2 += this.height;
long rx2 = rx1; rx2 += r.width;
long ry2 = ry1; ry2 += r.height;
if (tx1 < rx1) tx1 = rx1;
if (ty1 < ry1) ty1 = ry1;
if (tx2 > rx2) tx2 = rx2;
if (ty2 > ry2) ty2 = ry2;
tx2 -= tx1;
ty2 -= ty1;
// tx2,ty2 will never overflow (they will never be
// larger than the smallest of the two source w,h)
// they might underflow, though...
if (tx2 < Integer.MIN_VALUE) tx2 = Integer.MIN_VALUE;
if (ty2 < Integer.MIN_VALUE) ty2 = Integer.MIN_VALUE;
return new Rectangle(tx1, ty1, (int) tx2, (int) ty2);
}

Java Game - moving an object in a straight line to another point

Here is what I have so far:
int vx = (playerx - x);
int vy = (playery - y);
double distance = Math.sqrt((vx * vx) + (vy * vy));
double doublex = ((vx / distance));
double doubley = ((vy / distance));
dx = (int) Math.floor(doublex + 0.5);
dy = (int) Math.floor(doubley + 0.5);
x += dx;
y += dy;
I just want x and y to move straight towards playerx and playery but it moves only at a slope of 0, 1, or undefined.
I suspect it because you x and y are int and you have moving such a short distance that you will only be (1, 1), (1, 0) or (0, 1).
You need to allow it to move further that 1, or use a type which more resolution. e.g. double.
BTW: Instead of using Math.floor I believe a better choice is
dx = (int) Math.round(doublex);
You are dividing horizontal distance and vertical distance by total distance, this will always result in a number between 1 and -1 so each time it moves it will move by either nothing or by 1 in a direction. I guess this is in pixels?
Each time the move happens you should keep track of the actual distance moved and the desired distance moved because, for example, you may be trying to move 0.4 along the y axes in every loop, and it will never move because that will always round down. So if in the second loop you know you should have moved by 0.8 in total, you can round up to one, and leave the desired set to -0.2 and keep looping.
A solution similar to Bresanham's Line Algorithm can be implemented. IE:
function line(x0, y0, x1, y1)
real deltax := x1 - x0
real deltay := y1 - y0
real deltaerr := abs(deltay / deltax) // Assume deltax != 0 (line is not vertical),
// note that this division needs to be done in a way that preserves the fractional part
real error := deltaerr - 0.5
int y := y0
for x from x0 to x1
plot(x,y)
error := error + deltaerr
if error ≥ 0.5 then
y := y + 1
error := error - 1.0
Source: Bresanham's Line Algoithm

Java 2d Shooting direction with mouse

My problem might be simple. I've spent most of today thinking of an algorithm(That will pretty probably be a couple if statements) that will determine the direction the mouse is pointing and shoot a bullet in that direction. I already tested the bullets to make sure they shoot by shooting in a defined direction.
how would i go about calculating if the mouse is on the left side of the player, the right side,top side, bottom side, or if it's on the corners of the player ?
Solved: Thanks for all your help but after a day of thinking I came up with a way my self. What I did is use the if statements to determine when I press the mouse down, is it going to be colliding with the top part of the player,bottom,right,left,or corners. Anyway, here is my code. P.S. I used the variable x1 as the mousex, y1 as mousey, x as playerx, and y as player y. The only other variable I have is dx and dy but you should know what those do.
//top
if (x1 > x && x1 < x + 40 && y1 > y - 250 && y1 < y){
dy = -1;
dx = 0;
}
//right
if (x1 > x + 40 && x1 < x + 250 && y1 > y && y1 < y + 40){
dx = 1;
dy = 0;
}
//bottom
if (x1 > x && x1 < x + 40 && y1 > y+40 && y1 < y+250){
dy = 1;
dx = 0;
}
//left
if (x1 < x && x1 > x - 250 && y1 > y && y1 < y + 40){
dx = -1;
dy = 0;
}
//top right corner
if (x1 > x + 40 && x1 < x + 250 && y1 > y - 250 && y1 < y){
dx = 1;
dy = -1;
}
//top left corner
if (x1 < x && x1 > x - 250 && y1 > y - 250 && y1 < y){
dx = -1;
dy = -1;
}
//bottom right corner
if (x1 > x + 40 && x1 < x + 250 && y1 > y + 40 && y1 < y + 250){
dx = 1;
dy = 1;
}
//bottom left corner
if (x1 < x && x1 > x - 250 && y1 > y + 40 && y1 < y + 250){
dx = -1;
dy = 1;
}
You have to implement Mouse move actionlistener if you want to implement shooting while the mouse button is pressed.
Simple equation of line will do it.
Solution: Get the initial point (x0,y0) when button is pressed. While mouse moves when pressed, get (x1,y1) point where the mouse is moving (this constantly changes) - get the line equation - (you have 2 points so find slope and then use one point to get the equation of the line).
Now the direction the bullet fires is the perpendicular to this line through (x1,y1). So you can find the equation of this perpendicular line when the other equation is known. Now to know whether it has to be fired up or down is relative to finding out which side the gun is pointed (direction be stored in a variable)
After all this, when mouse still moves, old point will now be (x1,y1) and new point will be (x2,y2) and you keep implementing these changes.

Algorithm to move mouse from one point to another in a straight line

I am trying to make a small program that will move the mouse from the current position to the given position. Here is a method that i can use which will move the mouse from one point to another but without animation:
moveMouse(int x, int y);
This will move the mouse from the current coordinates to x,y on screen without animation. Now my job is to move the mouse to that coordinate, but it should also show the mouse moving one pixel at a time. I need to create a loop which moves the mouse cursor few pixels x and y at a time so that Here is what i have been thinking:
public void moveMouseAnimation(x,y){
//Integers x2 and y2 will be the current position of the mouse cursor
boolean isRunning = true;
while(isRunning){
delay(10); // <- 10 Milliseconds pause so that people can see the animation
x2 -= 1;
y2 -= 1;
moveMouse(x2,y2);
if(x2 == x && y2 == y) isRunning = false; //Ends loop
}
}
Now i need to find correct x2 and y2 values so that the mouse moves in a straight line and reaches x and y at last. Could someone help me.
You want the Bresenham's line algorithm. It is commonly used to draw a line between two points, but you, instead of drawing a line, will move the mouse along it.
Below is the code to do that. This code uses Bresenham Line Algo. For more ref on soln try http://en.wikipedia.org/wiki/Bresenham's_line_algorithm if you are looking not to have jagged lines
boolean steep = Math.abs(y1 - y0) > Math.abs(x1 - x0);
if (steep) {
int t;
// swap(x0, y0);
t = x0;
x0 = y0;
y0 = t;
// swap(x1, y1);
t = x1;
x1 = y1;
y1 = t;
}
if (x0 > x1) {
int t;
// swap(x0, x1);
t = x0;
x0 = x1;
x1 = t;
// swap(y0, y1);
t = y0;
y0 = y1;
y1 = t;
}
int deltax = x1 - x0;
int deltay = Math.abs(y1 - y0);
int error = deltax / 2;
int ystep;
int y = y0;
if (y0 < y1)
ystep = 1;
else
ystep = -1;
for (int x = x0; x < x1; x++) {
if (steep)
moveMouse(y, x);
else
moveMouse(x, y);
error = error - deltay;
if (error < 0) {
y = y + ystep;
error = error + deltax;
}
}
The problem that you are attempting to solve is that of linear interpolation, in that you have a linear function, that of a line between the starting point (x0, y0) and the ending point (x1, y1).
Luckily the solution is simple. The Wikipedia article gives examples almost exactly what you're trying to do.
http://en.wikipedia.org/wiki/Linear_interpolation
You could interpolate a straight line....basically fitting y=mx+b to the given points.

Categories

Resources