Circle-Rectangle collision side detection in libgdx - java

I have spent hours looking for the solution to this: I am developing a little top-down game with libgdx (maybe it matters what engine i am using). Now i have to implement the collision detection between my character (circle) and the wall (rectangle). I want the character to slide along the wall on collision, if sliding is possible.
Let me explain:
If i am moving 45 degrees right up i can collide with the down, the
left or the corner of a wall.
If i collide with the left i want to stop x-movement and move only up. If i leave the wall then i want to go on moving right up. The same
with the down side (stop y-movement)
If i collide with the Corner i want to stop movement (sliding not possible).
What i am doing actually is to check if the left line of the rectangle intersects my circle. Then i check intersection between the left line of wall and my circle and the bottom line of wall and my circle. Depending on which intersection occuret i set back x/y possition of my circle and set x/y Speed to 0. The Problem is, that most times not a collision bt an overlap occures. So the bottom check returns true, even if in reality the circle would only collide with the right. In this case both intersection test would return true and i would reset both speeds like on the Corner collision.
How can i solve this Problem? Is ther a better way to detect collision and collision side or corner?
I don't Need the exact Point of collision just the side of the rectangle.
Edit:
I have to say, that the rects aren't rotated just parallel to the x-axis.

You can find an explanation for circle/rectangle collision below, but please note that this type of collision might not be necessary for your needs. If, for example, you had a rectangle bounding box for your character the algorithm would be simpler and faster. Even if you are using a circle, it is probable that there is a simpler approach that is good enough for your purposes.
I though about writing the code for this, but it would take too long so here is only an explanation:
Here is a example movement of your character circle, with its last (previous) and current positions. Wall rectangle is displayed above it.
Here is that same movement, dotted lines represent the area the circle sweeps in this move. The sweep area is capsule shaped.
It would be difficult to calculate the collision of these two object, so we need to do this differently. If you look at the capsule on the previous image, you will see that it is simply the movement line extended in every direction by the radius of the circle. We can move that "extension" from the movement line to the wall rectangle. This way we get a rounded rectangle like on the image below.
The movement line will collide with this extended (rounded) rectangle if and only if the capsule collides with the wall rectangle, so they are somehow equivalent and interchangeable.
Since this collision calculation is still non-trivial and relatively expensive, you can first do a fast collision check between the extended wall rectangle (non-rounded this time) and the bounding rectangle of the movement line. You can see these rectangles on the image below - they are both dotted. This is a fast and easy calculation, and while you play the game there will probably NOT be an overlap with a specific wall rectangle >99% of the time and collision calculation will stop here.
If however there is an overlap, there is probably a collision of the character circle with wall rectangle, but it is not certain as will be demonstrated later.
Now you need to calculate the intersection between the movement line itself (not its bounding box) and the extended wall rectangle. You can probably find an algorithm how to do this online, search for line/rectangle intersection, or line/aabb intersection (aabb = Axis Aligned Bounding Box). The rectangle is axis-aligned and this makes the calculation simpler. The algorithm can give you intersection point or points since it is possible that there are two - in this case you choose the closest one to the starting point of the line. Below is an example of this intersection/collision.
When you get an intersection point, it should be easy to calculate on which part of the extended rectangle this intersection is located. You can see these parts on the image above, separated by red lines and marked with one or two letters (l - left, r - right, b - bottom, t - top, tl - top and left etc).
If the intersection is on parts l, r, b or t (the single letter ones, in the middle) then you are done. There is definitely a collision between character circle and wall rectangle, and you know on which side. In the example above, it is on the bottom side. You should probably use 4 variables called something like isLeftCollision, isRightCollision, isBottomCollsion and isTopCollision. In this case you would set isBottomCollision to true, while the other 3 would remain at false.
However, if the intersection is on the corner, on the two-letter sections, additional calculations are needed to determine if there is an actual collision between character circle and wall rectangle. Image below shows 3 such intersections on the corners, but there is an actual circle-rectangle collision on only 2 of them.
To determine if there is a collision, you need to find an intersection between the movement line and the circle centered in the closest corner of the original non-extended wall rectangle. The radius of this circle is equal to the radius of character circle. Again, you can google for line/circle intersection algorithm (maybe even libgdx has one), it isn't complex and shouldn't be hard to find.
There is no line/circle intersection (and no circle/rectangle collision) on bl part, and there are intersections/collisions on br and tr parts.
In the br case you set both isRightCollision, isBottomCollsion to true and in the tr case you set both isRightCollision and isTopCollision to true.
There is also one edge case you need to look out for, and you can see it on the image below.
This can happen if the movement of previous step ends in the corner of the the extended rectangle, but outside the radius of the inner rectangle corner (there was no collision).
To determine if this is the case, simply check if movement staring point is inside the extended rectangle.
If it is, after the initial rectangle overlap test (between extended wall rectangle and bounding rectangle of movement line), you should skip line/rectangle intersection test (because in this case there might not be any intersection AND still be a circle/rectangle collision), and also simply based on movement stating point determine which corner you are in, and then only check for line/circle intersection with that corner's circle. If there is intersection, there is a character circle/wall rectangle collision, otherwise not.
After all of this, the collision code should be simple:
// x, y - character coordinates
// r - character circle radius
// speedX, speedY - character speed
// intersectionX, intersectionY - intersection coordinates
// left, right, bottom, top - wall rect positions
// I strongly recomment using a const "EPSILON" value
// set it to something like 1e-5 or 1e-4
// floats can be tricky and you could find yourself on the inside of the wall
// or something similar if you don't use it :)
if (isLeftCollision) {
x = intersectionX - EPSILON;
if (speedX > 0) {
speedX = 0;
}
} else if (isRightCollision) {
x = intersectionX + EPSILON;
if (speedX < 0) {
speedX = 0;
}
}
if (isBottomCollision) {
y = intersectionY - EPSILON;
if (speedY > 0) {
speedY = 0;
}
} else if (isTopCollision) {
y = intersectionY + EPSILON;
if (speedY < 0) {
speedY = 0;
}
}
[Update]
Here is a simple and I believe efficient implementation of segment-aabb intersection that should be good enough for your purposes. It is a slightly modified Cohen-Sutherland algorithm. Also you can check out the second part of this answer.
public final class SegmentAabbIntersector {
private static final int INSIDE = 0x0000;
private static final int LEFT = 0x0001;
private static final int RIGHT = 0x0010;
private static final int BOTTOM = 0x0100;
private static final int TOP = 0x1000;
// Cohen–Sutherland clipping algorithm (adjusted for our needs)
public static boolean cohenSutherlandIntersection(float x1, float y1, float x2, float y2, Rectangle r, Vector2 intersection) {
int regionCode1 = calculateRegionCode(x1, y1, r);
int regionCode2 = calculateRegionCode(x2, y2, r);
float xMin = r.x;
float xMax = r.x + r.width;
float yMin = r.y;
float yMax = r.y + r.height;
while (true) {
if (regionCode1 == INSIDE) {
intersection.x = x1;
intersection.y = y1;
return true;
} else if ((regionCode1 & regionCode2) != 0) {
return false;
} else {
float x = 0.0f;
float y = 0.0f;
if ((regionCode1 & TOP) != 0) {
x = x1 + (x2 - x1) / (y2 - y1) * (yMax - y1);
y = yMax;
} else if ((regionCode1 & BOTTOM) != 0) {
x = x1 + (x2 - x1) / (y2 - y1) * (yMin - y1);
y = yMin;
} else if ((regionCode1 & RIGHT) != 0) {
y = y1 + (y2 - y1) / (x2 - x1) * (xMax - x1);
x = xMax;
} else if ((regionCode1 & LEFT) != 0) {
y = y1 + (y2 - y1) / (x2 - x1) * (xMin - x1);
x = xMin;
}
x1 = x;
y1 = y;
regionCode1 = calculateRegionCode(x1, y1, r);
}
}
}
private static int calculateRegionCode(double x, double y, Rectangle r) {
int code = INSIDE;
if (x < r.x) {
code |= LEFT;
} else if (x > r.x + r.width) {
code |= RIGHT;
}
if (y < r.y) {
code |= BOTTOM;
} else if (y > r.y + r.height) {
code |= TOP;
}
return code;
}
}
Here is some code example usage:
public final class Program {
public static void main(String[] args) {
float radius = 5.0f;
float x1 = -10.0f;
float y1 = -10.0f;
float x2 = 31.0f;
float y2 = 13.0f;
Rectangle r = new Rectangle(3.0f, 3.0f, 20.0f, 10.0f);
Rectangle expandedR = new Rectangle(r.x - radius, r.y - radius, r.width + 2.0f * radius, r.height + 2.0f * radius);
Vector2 intersection = new Vector2();
boolean isIntersection = SegmentAabbIntersector.cohenSutherlandIntersection(x1, y1, x2, y2, expandedR, intersection);
if (isIntersection) {
boolean isLeft = intersection.x < r.x;
boolean isRight = intersection.x > r.x + r.width;
boolean isBottom = intersection.y < r.y;
boolean isTop = intersection.y > r.y + r.height;
String message = String.format("Intersection point: %s; isLeft: %b; isRight: %b; isBottom: %b, isTop: %b",
intersection, isLeft, isRight, isBottom, isTop);
System.out.println(message);
}
long startTime = System.nanoTime();
int numCalls = 10000000;
for (int i = 0; i < numCalls; i++) {
SegmentAabbIntersector.cohenSutherlandIntersection(x1, y1, x2, y2, expandedR, intersection);
}
long endTime = System.nanoTime();
double durationMs = (endTime - startTime) / 1e6;
System.out.println(String.format("Duration of %d calls: %f ms", numCalls, durationMs));
}
}
This is the result I get from executing this:
Intersection point: [4.26087:-2.0]; isLeft: false; isRight: false; isBottom: true, isTop: false
Duration of 10000000 calls: 279,932343 ms
Please note that this is desktop performance, on an i5-2400 CPU. It will probably be much slower on Android devices, but I believe still more than sufficient.
I only tested this superficially, so if you find any errors, let me know.
If you use this algorithm, I believe you don't need special handling for that case where starting point is in the corner of the extended wall rectangle, since in this case you will get the intersection point at line start, and the collision detection procedure will continue to the next step (line-circle collision).

I suppose you determine the collision by calculating the distance of the circles center with the lines.
We can simplify the case and tell that the circle colliding with the corner if both distances are equal and smaller than the radius. The equality should have a tolerance of course.
More - may be not necessary- realistic approach would be to consider x,y speed and factor it in the equality check.

Related

How to fix circle and rectangle overlap in collision response?

Since in the digital world a real collision almost never happens, we will always have a situation where the "colliding" circle overlaps the rectangle.
How to put back the circle in the situation where it collides perfectly with the rectangle without overlap?
Suppose that the rectangle is stopped (null velocity) and axis-aligned.
I would solve this problem with a posteriori approach (in two dimensions).
In short I have to solve this equation for t:
Where:
is a number that answers to the question: how many frames ago did the
collision happen perfectly?
is the radius of the circle.
is the center of the circle
is its velocity.
and are functions that return the x and y coordinates of
the point where the circle and the rectangle collide (when the circle is
at position, that is in the position in which perfectly collide with the rectangle).
Recently I solved a similar problem for collisions between circles, but now I don't know the law of the functions A and B.
After years of staring at this problem, and never coming up with a perfect solution, I've finally done it!
It's pretty much a straight forward algorithm, no need for looping and approximations.
This is how it works at a higher level:
Calculate intersection times with each side's plane IF the path from current point to future point crosses that plane.
Check each side's quadrant for single-side intersection, return the intersection.
Determine the corner that the circle is colliding with.
Solve the triangle between the current point, the corner, and the intersecting center (radius away from the corner).
Calculate time, normal, and intersection center.
And now to the gory details!
The input to the function is bounds (which has a left, top, right, bottom) and a current point (start) and a future point (end).
The output is a class called Intersection which has x, y, time, nx, and ny.
{x, y} is the center of the circle at intersection time.
time is a value from 0 to 1 where 0 is at start and 1 is at end
{nx, ny} is the normal, used for reflecting the velocity to determine the new velocity of the circle
We start off with caching variables we use often:
float L = bounds.left;
float T = bounds.top;
float R = bounds.right;
float B = bounds.bottom;
float dx = end.x - start.x;
float dy = end.y - start.y;
And calculating intersection times with each side's plane (if the vector between start and end pass over that plane):
float ltime = Float.MAX_VALUE;
float rtime = Float.MAX_VALUE;
float ttime = Float.MAX_VALUE;
float btime = Float.MAX_VALUE;
if (start.x - radius < L && end.x + radius > L) {
ltime = ((L - radius) - start.x) / dx;
}
if (start.x + radius > R && end.x - radius < R) {
rtime = (start.x - (R + radius)) / -dx;
}
if (start.y - radius < T && end.y + radius > T) {
ttime = ((T - radius) - start.y) / dy;
}
if (start.y + radius > B && end.y - radius < B) {
btime = (start.y - (B + radius)) / -dy;
}
Now we try to see if it's strictly a side intersection (and not corner). If the point of collision lies on the side then return the intersection:
if (ltime >= 0.0f && ltime <= 1.0f) {
float ly = dy * ltime + start.y;
if (ly >= T && ly <= B) {
return new Intersection( dx * ltime + start.x, ly, ltime, -1, 0 );
}
}
else if (rtime >= 0.0f && rtime <= 1.0f) {
float ry = dy * rtime + start.y;
if (ry >= T && ry <= B) {
return new Intersection( dx * rtime + start.x, ry, rtime, 1, 0 );
}
}
if (ttime >= 0.0f && ttime <= 1.0f) {
float tx = dx * ttime + start.x;
if (tx >= L && tx <= R) {
return new Intersection( tx, dy * ttime + start.y, ttime, 0, -1 );
}
}
else if (btime >= 0.0f && btime <= 1.0f) {
float bx = dx * btime + start.x;
if (bx >= L && bx <= R) {
return new Intersection( bx, dy * btime + start.y, btime, 0, 1 );
}
}
We've gotten this far so we know either there's no intersection, or it's collided with a corner. We need to determine the corner:
float cornerX = Float.MAX_VALUE;
float cornerY = Float.MAX_VALUE;
if (ltime != Float.MAX_VALUE) {
cornerX = L;
} else if (rtime != Float.MAX_VALUE) {
cornerX = R;
}
if (ttime != Float.MAX_VALUE) {
cornerY = T;
} else if (btime != Float.MAX_VALUE) {
cornerY = B;
}
// Account for the times where we don't pass over a side but we do hit it's corner
if (cornerX != Float.MAX_VALUE && cornerY == Float.MAX_VALUE) {
cornerY = (dy > 0.0f ? B : T);
}
if (cornerY != Float.MAX_VALUE && cornerX == Float.MAX_VALUE) {
cornerX = (dx > 0.0f ? R : L);
}
Now we have enough information to solve for the triangle. This uses the distance formula, finding the angle between two vectors, and the law of sines (twice):
double inverseRadius = 1.0 / radius;
double lineLength = Math.sqrt( dx * dx + dy * dy );
double cornerdx = cornerX - start.x;
double cornerdy = cornerY - start.y;
double cornerdist = Math.sqrt( cornerdx * cornerdx + cornerdy * cornerdy );
double innerAngle = Math.acos( (cornerdx * dx + cornerdy * dy) / (lineLength * cornerdist) );
double innerAngleSin = Math.sin( innerAngle );
double angle1Sin = innerAngleSin * cornerdist * inverseRadius;
// The angle is too large, there cannot be an intersection
if (Math.abs( angle1Sin ) > 1.0f) {
return null;
}
double angle1 = Math.PI - Math.asin( angle1Sin );
double angle2 = Math.PI - innerAngle - angle1;
double intersectionDistance = radius * Math.sin( angle2 ) / innerAngleSin;
Now that we solved for all sides and angles, we can determine time and everything else:
// Solve for time
float time = (float)(intersectionDistance / lineLength);
// If time is outside the boundaries, return null. This algorithm can
// return a negative time which indicates the previous intersection.
if (time > 1.0f || time < 0.0f) {
return null;
}
// Solve the intersection and normal
float ix = time * dx + start.x;
float iy = time * dy + start.y;
float nx = (float)((ix - cornerX) * inverseRadius);
float ny = (float)((iy - cornerY) * inverseRadius);
return new Intersection( ix, iy, time, nx, ny );
Woo! That was fun... this has plenty of room for improvements as far as efficiency goes. You could reorder the side intersection checking to escape as early as possible while making as few calculations as possible.
I was hoping there would be a way to do it without trigonometric functions, but I had to give in!
Here's an example of me calling it and using it to calculate the new position of the circle using the normal to reflect and the intersection time to calculate the magnitude of reflection:
Intersection inter = handleIntersection( bounds, start, end, radius );
if (inter != null)
{
// Project Future Position
float remainingTime = 1.0f - inter.time;
float dx = end.x - start.x;
float dy = end.y - start.y;
float dot = dx * inter.nx + dy * inter.ny;
float ndx = dx - 2 * dot * inter.nx;
float ndy = dy - 2 * dot * inter.ny;
float newx = inter.x + ndx * remainingTime;
float newy = inter.y + ndy * remainingTime;
// new circle position = {newx, newy}
}
And I've posted the full code on pastebin with a completely interactive example where you can plot the starting and ending points and it shows you the time and resulting bounce off of the rectangle.
If you want to get it running right away you'll have to download code from my blog, otherwise stick it in your own Java2D application.
EDIT:
I've modified the code in pastebin to also include the collision point, and also made some speed improvements.
EDIT:
You can modify this for a rotating rectangle by using that rectangle's angle to un-rotate the rectangle with the circle start and end points. You'll perform the intersection check and then rotate the resulting points and normals.
EDIT:
I modified the code on pastebin to exit early if the bounding volume of the path of the circle does not intersect with the rectangle.
Finding the moment of contact isn't too hard:
You need the position of the circle and rectangle at the timestep before the collision (B) and the timestep after (A). Calculate the distance from the center of the circle to the line of the rectangle it collides with at times A and B (ie, a common formula for a distance from a point to a line), and then the time of collision is:
tC = dt*(dB-R)/(dA+dB),
where tC is the time of collision, dt is the timestep, dB is the distance to line before the collision, dA is the distance after the collision, and R is the radius of the circle.
This assumes everything is locally linear, that is, that your timesteps are reasonably small, and so that the velocity, etc, don't change much in the timestep where you calculate the collision. This is, after all, the point of timesteps: in that with a small enough timestep, non-linear problems are locally linear. In the equation above I take advantage of that: dB-R is the distance from the circle to the line, and dA+dB is the total distance moved, so this question just equates the distance ratio to the time ratio assuming everything is approximately linear within the timestep. (Of course, at the moment of collision the linear approximation isn't its best, but to find the moment of collision, the question is whether it's linear within a timestep up to to moment of collision.)
It's a non-linear problem, right?
You take a time step and move the ball by its displacement calculated using velocity at the start of the step. If you find overlap, reduce the step size and recalculate til convergence.
Are you assuming that the balls and rectangles are both rigid, no deformation? Frictionless contact? How will you handle the motion of the ball after contact is made? Are you transforming to a coordinate system of the contact (normal + tangential), calculating, then transforming back?
It's not a trivial problem.
Maybe you should look into a physics engine, like Box2D, rather than coding it yourself.

Java: Object moving on a path, ignores certain coordinates. How to fix?

I have a circle that moves from point A to a random point B. When the object nears point B, a new random target location gets chosen. If the circle is moving parallel to the X-axis or Y-axis the object goes through all the pixels in the way and leaves a solid trace. But if the circle moves diagonally, it skips pixels and shakes slightly, making the animation not smooth and leaves a trace with unpainted pixels.
My algorithm is:
calculate the X and Y distances
check if the circle is near
if so, choose the new destination
if 2. is true, find the real distance using Pythagoras' theorem
if 2. is true, calculate the X and Y speed (the change of the coordinates)
set the new coordinates (no matter if 2. is true or not)
And here is the code:
public void move ()//движение
{
//finds the X and Y distance to the destination
int triangleX = nextLocationX - coorX;
int triangleY = nextLocationY - coorY;
//if too near the coordinates of the destination changes
if (Math.abs(triangleX) <= Math.abs(speedX) || Math.abs(triangleY) <= Math.abs(speedY))//setting the new target
{
//setting the new destinatio
int randInt;
for (;;)//I don't want the the new destination to be that same spot
{
randInt= randGen.nextInt(appletX);
if (randInt != nextLocationX)
{
nextLocationX = randInt + radius;
break;
}
}
for (;;)
{
randInt = randGen.nextInt(appletY);
if (randInt != nextLocationY)
{
nextLocationY = randInt + radius;
break;
}
}
//calculating the change of the circle's X and Y coordinates
triangleX = nextLocationX - coorX;
triangleY = nextLocationY - coorY;
speedX = ((double)(speed * triangleX) / (Math.sqrt (Math.pow(triangleX, 2) + Math.pow(triangleY, 2))));
speedY = ((double)(speed * triangleY) / (Math.sqrt (Math.pow(triangleX, 2) + Math.pow(triangleY, 2))));
}
//the realCoor variables are from type double
//they are the exact coordinates of the circle
//If I only use integers, the circle almost
//never reaches it's destination
//unless the change of the coordinates gets calculated
//after every time they change
realCoorX = realCoorX + speedX;
realCoorY = realCoorY + speedY;
coorX = (int)Math.round(realCoorX);
coorY = (int)Math.round(realCoorY);
}
I suspect that the problem is in the calculation of the change of the coordinates.
For me this sounds like a Aliasing problem. You would have the same problem if you draw(!) a line that is not aligned with the coordinate axis. As you know, i.e. diagonal lines need "half filled" pixels to look smooth.
Solution for you would be (depending on the technology for rendering) to use floating point position calculation.

how to save values of variables and prevent them from changing when doing recursion? also recursion assistance?

import gpdraw.*;
public class Y2K {
// Attributes
SketchPad pad;
DrawingTool pen;
// Constructor
public Y2K() {
pad = new SketchPad(600, 600, 50);
pen = new DrawingTool(pad);
// Back the pen up so the Y is drawn in the middle of the screen
pen.up();
pen.setDirection(270);
pen.forward(150);
pen.down();
pen.setDirection(90);
}
public void drawY(int level, double length) {
// Base case: Draw an Y
if (level == 0) {
//pen.setDirection(90);
pen.forward(length);
pen.turnRight(60);
pen.forward(length);
pen.backward(length);
pen.turnLeft(120);
pen.forward(length);
pen.backward(length);
}
// Recursive case: Draw an L at each midpoint
// of the current L's segments
else {
//Drawing the bottom "leg" of our Y shape
pen.forward(length / 2);
double xpos1 = pen.getXPos();
double ypos1 = pen.getYPos();
double direction1 = pen.getDirection();
pen.turnRight(90);
drawY(level - 1, length / 2.0);
pen.up();
pen.move(xpos1, ypos1);
pen.setDirection(direction1);
pen.down();
pen.forward(length / 2);
double xpos2 = pen.getXPos();
double ypos2 = pen.getYPos();
double direction2 = pen.getDirection();
//Drawing upper Right Leg
pen.turnRight(60);
pen.forward(length / 2); //going to the midpoint
double xpos3 = pen.getXPos();
double ypos3 = pen.getYPos();
double direction3 = pen.getDirection();
pen.turnLeft(90);
drawY(level - 1, length / 2.0);
pen.up();
pen.move(xpos3, ypos3);
pen.setDirection(direction3);
pen.down();
pen.forward(length / 2);
//drawing upper left leg
pen.up();
pen.move(xpos1, ypos1);
pen.setDirection(direction1);
pen.down();
pen.forward(length / 2);
pen.turnLeft(60);
pen.forward(length / 2);
double xpos4 = pen.getXPos();
double ypos4 = pen.getYPos();
double direction4 = pen.getDirection();
pen.turnLeft(90);
drawY(level - 1, length / 2.0);
pen.up();
pen.move(xpos4, ypos4);
pen.setDirection(direction4);
pen.down();
pen.forward(length / 2);
pen.forward(length / 2);
}
}
public static void main(String[] args) {
Y2K fractal = new Y2K();
// Draw Y with given level and side length
fractal.drawY(8, 200);
}
}
output:
one certain leg of the triangle is too long, and that makes the output slightly off. maybe its because the code went (length/2) too far? lets debug this.
otherwise it is completely fine, the recursion is great, and its exactly what i wanted to do
As you're constantly drawing Y's, I'd recommend you create a method that draws a Y given certain parameters (e.g. length, angle of separation between the two branches of the Y, rotation, etc.). This will make your code much more readable and easier to understand.
As for moving to the center, just think of the Y on a coordinate plane. Based upon the rotation of the Y, and its starting point you can calculate the center point.
Just break it up into its x and y components.
Given this information, we can solve for a and for b.
a = length * sin(θ)
b = length * cos(θ)
Then add this to your x and y to calculate the center point of the Y.
As for keeping the constant length, you know the level. At the first level, level == 1. But the length of this next level should be length * (2^level). In this case, length/2 (as length would be -1).
In pseudo code terms:
public void drawY(int level, double length)
{
//Drawing the bottom "leg" of our Y shape
Move Forward length/2
Save our position
Save our direction
Turn to the right 90 degrees
Recursion (call drawY())
revert to original location
revert to original direction
move forward length/2 (to go to center point of Y)
save our new position
save our new direction
//Drawing upper Right Leg
Turn 60 to the right
Move Forward length/2 //going to the midpoint
save our new position (don't forget the center point)
save our new direction (don't forget the center point direction)
Turn 90 to the left
Recursion (call drawY())
return to our saved position (not center one)
return to our saved direction (not center one)
move forward length/2
//drawing upper left leg
return to center point
return to center direction
turn left 60
move forward length/2
save position (you can overwrite the center one now
save direction (you can overwrite)
turn left 90
Recursion (call drawY())
return to position
return to direction
move forward length/2
}

draw an angled square using sine and cosine

this is my first time posting on a forum. But I guess I will just jump in and ask.. I am trying to draw a rectangle with x, y, width, height, and angle. I do not want to create a graphics 2D object and use transforms. I'm thinking that's an inefficient way to go about it. I am trying to draw a square with rotation using a for loop to iterate to the squares width, drawing lines each iteration at the squares height. My understanding of trig is really lacking so... My current code draws a funky triangle. If there is another question like this with an answer sorry about the duplicate. If you have got any pointers on my coding I would love some corrections or pointers.
/Edit: Sorry about the lack of a question. I was needing to know how to use sine and cosine to draw a square or rectangle with a rotation centered at the top left of the square or rectangle. By using sin and cos with the angle to get the coordinates (x1,y1) then using the sin and cos functions with the angle plus 90 degrees to get the coordinates for (x2,y2). Using the counter variable to go from left to right drawing lines from top to bottom changing with the angle.
for (int s = 0; s < objWidth; s++){
int x1 = (int)(s*Math.cos(Math.toRadians(objAngle)));
int y1 = (int)(s*Math.sin(Math.toRadians(objAngle)));
int x2 = (int)((objWidth-s)*Math.cos(Math.toRadians(objAngle+90)));
int y2 = (int)((objHeight+s)*Math.sin(Math.toRadians(objAngle+90)));
b.setColor(new Color((int)gArray[s]));
b.drawLine(objX+x1, objY+y1, objX+x2, objY+y2);
}
It is called the Rotation matrix.
If your lines has the following coordinates before rotation:
line 1: (0, 0) - (0, height)
line 2: (1, 0) - (1, height)
...
line width: (width, 0) - (width, height)
Then applying the rotation matrix transform will help you:
for (int s = 0; s < objWidth; s++){
int x1 = cos(angle)*s
int y1 = sin(angle)*s
int x2 = s * cos(angle) - objHeight * sin(angle)
int y2 = s * sin(angle) + objHeight * cos(angle)
//the rest of code
}
Hope I didn't make a mistakes.
Do you mean like a "rhombus"? http://en.wikipedia.org/wiki/Rhombus (only standing, so to speak)
If so, you can just draw four lines, the horizontal ones differing in x by an amount of xdiff = height*tan(objAngle).
So that your rhombus will be made up by lines with points as
p1 = (objX,objY) (lower left corner)
p2 = (objX+xdiff,objY+height) (upper left corner)
p3 = (objX+xdiff+width,objY+height) (upper right corner)
p4 = (objX+xdiff+width,objY) (lower right corner)
and you will draw lines from p1 to p2 to p3 to p4 and back again to p1.
Or did you have some other shape in mind?

Collision system for an object?

I am making a small game, 2D, and I have a player.
EDIT:
This is what I have right now:
int oldX = player.x;
int oldY = player.y;
int newX = oldX - player.getSpeedX();
int newY = oldY - player.getSpeedY();
if(player.getBounds().intersects(brush1.getBounds())){
player.x = newX;
player.y = newY;
}else{
player.x = oldX;
player.y = oldY;
}
But, it is acting really weird, it changes speed when I go in from one side, etc.
For a formula and code that checks the intersection of a line segment and a circle, have a look at this SO answer.
The rest of the code should be quite clear, before you make a move, check if a collision occurs, if it would, don't move.
Depending on the behaviour you prefer, you could also move as close to the wall as possible and then move parallel to it to let the circle "slide" along the wall. This can be done by projecting the movement vector on a line with the same direction as the wall.
EDIT: Some comments on how to use the code from the answer to check for collisions:
The code uses a Dot function that computes the dot product of two vectors. You can either create a Vector class (a good exercise and it is useful for such projects) or compute just the dot product directly using the formulas here.
A vector class will make some of the code easier to read, but you can also operate on floats directly. For example, let's have a look at the computation of d (Direction vector of ray) and f (Vector from center sphere to ray start) as described at the start of the answer. With a vector class, this will be as easy as the formulas used there:
// L, E, C, d and f are of some vector type
d = L - E;
f = E - C;
Without a vector class, you'll have seperate x/y coordinates for all of the variables, bloating the code a bit but doing just the same:
// Twice as much variables, but all of them are usual floats.
dx = Lx - Ex;
dy = Ly - Ey;
fx = Ex - Cx;
fy = Ey - Cy;
I think your code snippet has a few bugs. Suggested fixes:
int oldX = player.x;
int oldY = player.y;
// *add* speed to old pos to get new pos
int newX = oldX + player.getSpeedX();
int newY = oldY + player.getSpeedY();
if(player.getBounds().intersects(brush1.getBounds())){
// Collision! Keep old position.
// Reverse speed (just a suggestion).
player.setSpeedX(-player.getSpeedX());
player.setSpeedY(-player.getSpeedY());
}else{
// No collision. Set position to *new* pos, not old pos.
player.x = newX;
player.y = newY;
}

Categories