How to detect Wall Collision and Rotate Robot by 90 degrees? - java

so recently, we've been assigned to code multiple circles that act like robots in a GUI interface. Basically, a robot simulator.
I've got the code to spawn in multiple circles that can act like robots.
This is my current code for detecting wall collision between the robot and the end of the square:
private void checkCollisions(double maxX, double maxY) {
for (ListIterator<Ball> slowIt = balls.listIterator(); slowIt.hasNext();) {
Ball b1 = slowIt.next();
// check wall collisions:
double xVel = b1.getXVelocity();
double yVel = b1.getYVelocity();
if ((b1.getCenterX() - b1.getRadius() <= 0 && xVel < 0)
|| (b1.getCenterX() + b1.getRadius() >= maxX && xVel > 0)) {
b1.setXVelocity(-xVel);
}
if ((b1.getCenterY() - b1.getRadius() <= 0 && yVel < 0)
|| (b1.getCenterY() + b1.getRadius() >= maxY && yVel > 0)) {
b1.setYVelocity(-yVel);
}
for (ListIterator<Ball> fastIt = balls.listIterator(slowIt.nextIndex()); fastIt.hasNext();) {
Ball b2 = fastIt.next();
final double deltaX = b2.getCenterX() - b1.getCenterX() ;
final double deltaY = b2.getCenterY() - b1.getCenterY() ;
if (colliding(b1, b2, deltaX, deltaY)) {
bounce(b1, b2, deltaX, deltaY);
}
}
}
}
The
b1.setXVelocity(-xVel);
b1.setYVelocity(-yVel);
are the main bits that make the circle bounce back from the wall. However, instead of this, I want the ball to detect the wall and rotate 90 degrees rather than bounce back form the wall like a bouncing ball.
Any help will be fully appreciated or a working piece of code that ca do this for me. I have an AraryList of all the balls called 'balls'.
If needed, I can give source code.
This is what I have so far. But I need each ball to have a sensor attached to them detecting if there a wall ahead.
https://i.stack.imgur.com/XsQvX.png

Assuming you have just square walls:
If the ball hits the right wall for example, you want to remove all x velocity, and then add either positive or negative velocity.
The issue with this is that the robot will end up just going around the outside edges of the map.

Related

Collision detection - avoid box

I'm making a racing car game where my racing course is similar to a rectangular donut. In the middle of the rectangle I have another smaller rectangle which acts as a wall. I'm trying to add collision detection to my inside wall so that my cars will collide with the inside walls. Below are some basic measurements of the inside wall as well as a picture showing a concept of the track:
-Translated x from 14 to 18 units is the width of the rectangle.
-Translate y from -60 to 60 units is the total length of the rectangle.
My problem currently is if I try making the cars collide when the x position hits the wall at 14 units from the origin (or with y), it creates collision for the entire x or y line. So for example, once I hit the wall that's located 14 units in the x direction it doesn't let me pass if I were to reach that location at one of the turning points in the race course. I'm trying the following at the moment.
void checkColl(){
if (posX < -14){
velocityX *= -1 //bounce off the wall on the far left side of the picture
}
if (posX > 48){
velocityX *= -1 //bounce off wall on far right
}
if ((posY > 60 || posY < -60) && (posX > 14 && posX < 18)){ //bounce off the rectangle in middle of race course
velocityY = velocityY * -1;
velocityX = velocityX * -1;
}
}
The check for the y coordinate is broken. Try this:
if ((posY > -60 && posY < 60) && (posX > 14 && posX < 18)){
//bounce off the rectangle in middle of race course
This defines points within the black rectangle - the hole of the "doughnut".

Make ball bounce in canvas

I have written code that should form the basis for a simple Pong game. It works, but I don't understand why. It should not work. I'm hoping somebody can give me the insight I'm missing as to why it does work.
I have the following concept in my canvas (which has (0,0) on the top left):
A ball always bounces in an angle between 0 and 180 degrees. I have taken the bottom of my canvas as the basis. Left is 0 degrees, right is 180 degrees. If it bounces on a wall the ball's angle (ball_angle) changes to 180 - ball_angle degrees. A ball's trajectory is defined by 2 more variables (x_traj and y_traj) indicating the direction on each axis.
The part I don't get is the ballHits() method. If the ball is hitting the cealing, coming from the right with a degree of e.g. 100, then it should bounce off at a degree of 80. The ball is coming from the right so the x_traj is negative. We are bouncing on the cealing so the ball drops instead of lifts, ergo we change the y_traj from negative (lifting) to positive (dropping). The ball will still be going to the right, so we leave that direction in tact.
Second scenario is when the ball hits the left wall. The ball is coming from the right again, so we know that traj_x is negative. We bounce off so the ball goes back to the right, ergo traj_x should be multiplied by -1 to make it positive again (move to the right). Wether we hit the wall coming from above or below, we are still going that same direction after bouncing of the wall. We don't change the traj_y variable.
However, below is the working code. I do not have to change any variable when I hit the left or right wall. Could somebody explain to me why?
If needed, the full compiling project can be found on GitHub.
Code to move the ball to new coordinates:
private void updateBall()
{
// http://gamedev.stackexchange.com/questions/73593/calculating-ball-trajectory-in-pong
// If the ball is not hitting anything, we simply move it.
// http://en.wikipedia.org/wiki/Polar_coordinate_system
if (ballHits())
{
// Bounce the ball off the wall.
ball_angle = 180 - ball_angle;
}
// http://en.wikipedia.org/wiki/Polar_coordinate_system
// Convert the angle to radians.
double angle = (ball_angle * Math.PI) / 180;
// Calculate the next point using polar coordinates.
ball_x = ball_x + (int) (x_traj * BALL_STEPSIZE * Math.cos(angle));
ball_y = ball_y + (int) (y_traj * BALL_STEPSIZE * Math.sin(angle));
System.out.printf("Ball: (%d,%d) # %d\n", ball_x, ball_y, ball_angle);
}
Code that determines if we have hit a wall:
private boolean ballHits()
{
// If we came out of bounds just reset it.
ball_y = Math.max(0, ball_y);
ball_x = Math.max(0, ball_x);
// Check to see if it hits any walls.
// Top
if(ball_y <= 0)
{
System.out.println("Collision on top");
y_traj *= -1;
x_traj *= -1;
return true;
}
// Left
if(ball_x <= 0)
{
System.out.println("Collision on left");
//y_traj *= -1;
//x_traj *= -1;
return true;
}
// Right
if(ball_x >= B_WIDTH)
{
System.out.println("Collision on right");
//y_traj *= -1;
//x_traj *= -1;
return true;
}
// Bottom
if(ball_y >= B_HEIGHT)
{
System.out.println("Collision on bottom");
y_traj *= -1;
x_traj *= -1;
return true;
}
return false;
}
Well it's working in a tricky way because cosine goes negative when your angle is > 90°.
Making him start with a different initial trajectory and angle should not work if the ball hits the bottom or top first.
Edit : I thought it would do that but doing it on paper proves me wrong, well it's a weird way to do it but it's working as intended. I'll investigate to find if there's a way it doesn't work.
Edit 2 : Does a start angle in range of [88-92] work ?

How to do collision detection with many walls (maze)?

In my game, the player navigates a maze. I can't figure out how to do proper collision detection with the walls. It is easy to do collision detection for staying in a certain area:
if (x > rightWallX - playerWidth) x = rightWallX - playerWidth;
if (x < leftWallX) x = leftWallX;
//...
But how would I do collision detection for many walls?
I can do plain collision detection without correction (like if (intersecting) return true;), but I can't correct this correctly. If I just store the old x and y and reset them, then
The object never actually touches the wall
If the object can go up but is blocked to the right, it won't go up, it will just not move.
How is collision detection in a maze done?
The easiest way, once you have solved collision detection, to fix the collision is to move the actor to the closest valid position to where the actor would be were it not for the object it collides with. This assumes no inertia, but it is sufficient for maze-like games or top-down map-crawling games.
If you want to simplify your calculations further, you can limit yourself to detecting if changing the actor's x or y coordinate would be better. If your actor has an axis-aligned rectangular hit-box and all obstacles are axis-aligned rectangular as well (the simplest case), this assumption is indeed correct. However, the results might not be satisfactory in some other cases (potential artifact: speed boost from gliding diagonal walls - not the case in most maze games).
Keep in mind multiple collisions could happen concurrently (pushing against two walls). If there are no sharp angles between two walls that an actor could both intersect (say, if all your obstacles are axis aligned and sufficiently spaced), fixing each collision in turn will suffice - just don't stop after the first collision.
You can use Rectangle.intersects() method:
public Rectangle Player(){
return new Rectangle(PlayerX,PlayerY,PlayerWidth,PlayerHeight);
//we do this for getting players x and y values every tick
}
if(Player().intersects(new Rectangle(0,0,100,50)))//if(player touching wall)
new Rectangle(0,0,100,50) is just an example you can change it.
Ok so i'm currently making a 2D top down view game and I'm not sure how you created your maze. However, in my game my Level is created from a Tile[][] tiles = new Tile[levelWidth][levelHeight]; array. The way i handled collision detection was by checking the surrounding tiles to see if they were solid.
This is my getTile method.
public Tile[][] getTile(int x, int y) {
if (x < 0 || x >= getWidth() || y < 0 || y >= getHeight()) {
return new VoidTile();
} else {
return tiles[x][y];
}
}
In my Tile.java class i have a isSolid() method which returns whether the tile is solid or not. All of my tiles extend my Tile.java so they inherit this method and I override it in their constructor. As i said previously, I am not sure whether or not you use the same style of level implementation as i do. However, It is good practice to do it this way :)
Personally, I am not a big fan of using the .intersects() and .contains() methods for Sprite collision detection. I mainly use them for buttons and alike.
Ok so,
In my player.java class i have a checkBlockedDirection(int x, int y) method and it looks like this.
public void checkBlockedDirection(int x, int y) {
boolean u = map.getTile(x, y - 1).isSolid();
boolean d = map.getTile(x, y + 1).isSolid();
boolean l = map.getTile(x - 1, y).isSolid();
boolean r = map.getTile(x + 1, y).isSolid();
if (u) {
uBlocked = true;
System.out.println("up tile blocked");
} else {
uBlocked = false;
}
if (d) {
dBlocked = true;
System.out.println("down tile blocked");
} else {
dBlocked = false;
}
if (l) {
lBlocked = true;
System.out.println("left tile blocked");
} else {
lBlocked = false;
}
if (r) {
rBlocked = true;
System.out.println("right tile blocked");
} else {
rBlocked = false;
}
}
Then in my player update method i have this
public void tick() {
float dx = 0;
float dy = 0;
if (input.up.isPressed()) {
direction = 0;
} else if (input.down.isPressed()) {
direction = 2;
} else if (input.left.isPressed()) {
direction = 3;
} else if (input.right.isPressed()) {
direction = 1;
} else {
direction = 4; // standing
}
checkBlockedDirection((int)x, (int)y);
if (input.up.isPressed() && y > 0 && !uBlocked) {
dy += -speed;
} else if (input.down.isPressed() && y < map.getHeight() - 1 && !dBlocked) {
dy += speed;
} else if (input.left.isPressed() && x > 0 && !lBlocked) {
dx += -speed;
} else if (input.right.isPressed() && x < map.getWidth() - 1 && !rBlocked) {
dx += speed;
}
x += dx;
y += dy;
}
Basically it just checks whether or not the blocks up, down, left, or right are solid. If they are solid then it wont move and if they arent solid then you can move in the desired direction.
Not sure if this helps or not but it's just my take on this kind of grid collision detection :)
Hope this helps :)
Enjoy

Issue with 2D collision bitmaps

The bitmap A has a position which is its X/Y position is static, bitmap B is moving bitmap which moves from the bottom of the screen to where ever the user touches on screen. When the moving bitmap reaches the static bitmap however it is not recognized as a collision, the moving bitmap uses float which i round off and the static bitmap uses int. Below is a snippet of code, I want to figure out what is needed to be changed for my bitmaps crossing paths to be considered a collision
canvas.drawBitmap(rock2, 70, 32, null);
//this is where it checks to see if the moving bitmaps y coordinate is matched to the Y coordinate of the static bitmap
if(canvas.getHeight() - Math.round(animY*-1) == (canvas.getHeight() - (canvas.getHeight()-32))){
Log.d("ALERT", "COLLIDE");
}
//the Y value is *-1 because the moving bitmap is starting from the bottom of the screen so this converts the value to positive value
I wonder if my calculations are off, or I am going about this collision the wrong way. Below is my movement code snippet
//UP Y ANIMATION
if(animY*-1 < canvas.getHeight() && !bumpY){
animY += speedY;
//IF ROCK IS NOT AT EXTREME LEFT OR EXTREME RIGHT KEEP ON TRACK
if(animX < (canvas.getWidth()/2) || animX*-1 < (canvas.getWidth()/2) && !bumpX){
animX += speedX;
//IF ROCK HITS EDGE LEFT/RIGHT RETURN TO SENDER (INDICATE BUMP)
if(animX*-1 > (canvas.getWidth()/2) - rock.getWidth()/2 || animX > (canvas.getWidth()/2) - rock.getWidth()/2){
bumpX = true;
bumpY = true;
}
}
//IF Y HITS TOP OF SCREEN
if(animY*-1 > canvas.getHeight()){
bumpY = true;
}
}
//DOWN Y ANIMATION
if(animY < 0 && bumpY){
//REVERSE DIRECTION OF Y
animY -= speedY;
//IF ROCK HITS TOP OR SIDE REVERSE X DIRECTION
if(bumpX || bumpY)
animX -= speedX;
//IF AT STARTING POINT
if(animY > 0){
bumpY = false;
bumpX = false;
}
}
//in an ontouch method where the X and Y values are calculated
case MotionEvent.ACTION_UP:
finalX = event.getX() - (cross.getWidth() / 2);
finalY = event.getY() - (cross.getHeight() / 2);
moveToX = finalX - startX;
moveToY = finalY - startY;
speedX = moveToX / 50;
speedY = moveToY / 50;
break;
Any tips would be appreciated, thank you.
sorry if this is a dumb answer, but should your check be:
if(canvas.getHeight() - Math.round(animY*-1) >= (canvas.getHeight() - (canvas.getHeight()-32))){
instead? (change the "==" to ">=" ) otherwise you are only checking for when the rock lands EXACTLY on (canvas.getheight -32), rather than checking past it

boolean flag not read in while loop (java)

I've written a program to bounce a ball around a screen. The program as written below does not work (the ball just moves off screen).
However if I declare the boolean variables atHorizontalEdge and atVerticalEdge inside the while loop, it seems to work. Why is that the case? As the booleans are defined for the entire run() method, shouldn't it be callable by the while loop even though its outside the while loop?
import acm.program.*;
import acm.graphics.*;
import java.awt.*;
public class BouncingBallv3 extends GraphicsProgram {
public void run() {
double x = (getWidth() - BALL_SIZE)/2 ; //sets the starting position of ball at center
double y = (getHeight() - BALL_SIZE)/2 ;
GOval ball = new GOval (x, y, BALL_SIZE, BALL_SIZE ); // creates a red ball at center of screen
ball.setFilled(true);
ball.setColor(Color.red);
add (ball);
double dx = 1; //increments by which the ball moves
double dy = 1;
//declares boolean variables to test if ball position is at an edge
boolean atHorizontalEdge = (ball.getX() == getWidth() - BALL_SIZE) || ball.getX() == 0 ;
boolean atVerticalEdge = (ball.getY() == getHeight() - BALL_SIZE) || ball.getY() == 0 ;
/* while loop keeps the ball moving in direction dx,dy
* if ball reaches a position at any edge, the direction dx or dy changes
*/
while (true) {
if (atHorizontalEdge) { //changes direction of ball if it hits a left/right wall
dx = -dx;
} else if (atVerticalEdge) { //changes direction of ball if it hits a top/bottom wall
dy = -dy;
}
ball.move(dx,dy);
pause (PAUSE_TIME);
}
}
private static final double BALL_SIZE = 50;
private static final int PAUSE_TIME = 5;
}
The issue is not that the declaration of the booleans is outside the while loop. It is that you are checking for your boundraies outside the while loop. Because of this, your condition is never updated and it only checks for the original state of the ball.
You should update the atHorizontalEdge and atVerticalEdge in the loop body after each iteration, I think.
UPDATE:
The while-loop body should be like this,
`
//declares boolean variables to test if ball position is at an edge
boolean atHorizontalEdge = false;
boolean atVerticalEdge = false;
/* while loop keeps the ball moving in direction dx,dy
* if ball reaches a position at any edge, the direction dx or dy changes
*/
while (true) {
atHorizontalEdge = (ball.getX() == getWidth() - BALL_SIZE) || ball.getX() == 0;
atVerticalEdge = (ball.getY() == getHeight() - BALL_SIZE) || ball.getY() == 0;
if (atHorizontalEdge) { //changes direction of ball if it hits a left/right wall
dx = -dx;
} else if (atVerticalEdge) { //changes direction of ball if it hits a top/bottom wall
dy = -dy;
}
ball.move(dx,dy);
pause (PAUSE_TIME);
}`
The reason why it works if you define atHorizontalEdge and atVerticalEdge inside loop is because each iteration these two variables are re-computed (i.e. updated).
atHorizontalEdge and atVerticalEdge can be declared inside or outside the while loop, that's not important.
The important thing is, the following is calculated only once, before the loop starts:
atHorizontalEdge = (ball.getX() == getWidth() - BALL_SIZE) || ball.getX() == 0 ;
atVerticalEdge = (ball.getY() == getHeight() - BALL_SIZE) || ball.getY() == 0 ;
Therefore atHorizontalEdge and atVerticalEdge will each have the same value from the start to the end of your run method (which is forever).
You obviously want the above two lines to be executed at every iteration in your loop, since they're not going to update by themselves...
while (true) {
atHorizontalEdge = (ball.getX() == getWidth() - BALL_SIZE) || ball.getX() == 0 ;
atVerticalEdge = (ball.getY() == getHeight() - BALL_SIZE) || ball.getY() == 0 ;
...
}
EDIT: Also, it'd be a better idea to check if the x and y were greater than or equal to the width/height, and less than or equal to 0 for 2 reasons:
If you decide to change the increment from 1 you could skip that exact value and cause a bug, but more importantly:
You're using a double and the floating-point representation of the number might not be exactly what you're comparing it to, so == can cause bugs, and the ball might go past the edge and keep going.
ie. ball.getX() >= getWidth() ... ball.getX() <= 0
What Every Computer Scientist Should Know About Floating-Point Arithmetic

Categories

Resources