Bouncing box issues

I’ve got this code that summons bunches of squares that move around the screen and, when collided with the edges of the screen or another box, they reverse their directions based on what edge got hit
In other words, i’ve got a multiball pong without paddles.

The issue is, sometimes when boxes collide, they reverse BOTH axis. And sometimes, when boxes clearly get hit from Y axis, a X collision is also detected, and vice-versa.

	public void update() {
		updates++;
		
		for (int i = 0; i < Box.boxes.size(); i++) {
			//Screen-edge collision code removed to make it simpler
				

			//When moving in X direction, checks if there is space to move left or right. If not, reverse X direction
			if (!Box.isFree(Box.boxes.get(i).x + Box.boxes.get(i).xsize, Box.boxes.get(i).y, 1, Box.boxes.get(i).ysize) || !Box.isFree(Box.boxes.get(i).x - 1, Box.boxes.get(i).y, 1, Box.boxes.get(i).ysize)) {
				Box.boxes.get(i).xdir = -Box.boxes.get(i).xdir;

				System.out.println("X COLLISION DETECTED ON BOX " + i);
			}

			//When moving in Y direction, checks if there is space to move up or down. If not, reverse Y direction	
			if (!Box.isFree(Box.boxes.get(i).x, Box.boxes.get(i).y + Box.boxes.get(i).ysize, Box.boxes.get(i).xsize, 1) || !Box.isFree(Box.boxes.get(i).x, Box.boxes.get(i).y - 1, Box.boxes.get(i).xsize, 1)) {
				Box.boxes.get(i).ydir = -Box.boxes.get(i).ydir;

				System.out.println("Y COLLISION DETECTED ON BOX " + i);
			}	
			
			//Move the box in both directions			
			Box.boxes.get(i).x+=Box.boxes.get(i).xdir;
			Box.boxes.get(i).y+=Box.boxes.get(i).ydir;
		}
	}

	//This method is on another class, but is used above
	public static boolean isFree(int x, int y, int xsize, int ysize) {
		for (int i = 0; i < boxes.size(); i++) {
			if ((boxes.get(i).x + boxes.get(i).xsize > x && boxes.get(i).y + boxes.get(i).ysize > y) && (x + xsize > boxes.get(i).x && y + ysize > boxes.get(i).y)) {	
				return false;
			}
		}		
		return true;
	}

I’m pretty sure the answer is simple enough to make me feel stupid.
Not that im not feeling stupid already.

Thanks

Could I possibly see the details of your box object? I’ve made something similar to this in the past. I you aren’t already, I would highly recommend adding a Rectangle object to each box instance. Make the rectangle the same size at the box itself, just don’t draw it to the screen. The rectangle object comes with a great intersects() method that makes collision detection much easier. So you would add this to the class definition for your box:

private Rectangle border = new Rectangle(x, y, width, height);

Than, you can do collision detection by simply calling the intersects method in your for-loop:

[b]for(int i = 0; i < boxes.length; i++){

 for(int j = 0; j < boxes.length; j++){
      
      if(j == i)
           continue;     // so a box doesn't collide with itself

      if(boxes[i].intersects(boxes.[j])){
            boxes[i].switchDirection();    // use whatever method to change the movement direction 
      }
 }

}[/b]

If you end up using the rectangle method, just don’t forget to automatically move the rectangle’s x/y position whenever you move a box. This may not be the most efficient way to do collision detection, but it will work for a simple program like this.

Tip: use the


 tag :)

EDIT 2095872366586842857867389: Riven?

Why not 42?

I actually rewrote my awfully bad algorythm into a bit-better-but-still-bad algorythm, but here, have my box class


public class Box extends Entity {
	public int x, y, xsize, ysize, outline, color, outcolor;
	public int xdir, ydir;
	public static List<Box> boxes = new ArrayList<Box>();
		
	public Box(int x, int y, int xsize, int ysize, int color, int outcolor, int dir) {
		this.x = x;
		this.y = y;
		this.xsize = xsize;
		this.ysize = ysize;
		this.color = color;
		this.outline = 1;
		this.outcolor = outcolor;
		this.xdir = dir;
		this.ydir = dir;
		boxes.add(this);
	}
	
	public static boolean intersects(Box box1, Box box2) {	
		if ((box1.x + box1.xsize > box2.x && box1.y + box1.ysize > box2.y) && (box2.x + box2.xsize > box1.x && box2.y + box2.ysize > box1.y)) return true;
		else return false;
	}
	
	public static int getCollisionFactor(Box box1, Box box2) {
		int horizontalFactor = Math.min(box1.x + box1.xsize - box2.x, box2.x + box2.xsize - box1.x);
		int verticalFactor = Math.min(box1.y + box1.ysize - box2.y, box2.y + box2.ysize - box1.y);
		return horizontalFactor - verticalFactor;
	}
	
	public static boolean isFree(int x, int y, int xsize, int ysize) {
		for (int i = 0; i < boxes.size(); i++) {
			if ((boxes.get(i).x + boxes.get(i).xsize > x && boxes.get(i).y + boxes.get(i).ysize > y) && (x + xsize > boxes.get(i).x && y + ysize > boxes.get(i).y)) {	
				return false;
			}
		}		
		return true;
	}

	public void update() {
		...		
	}
	
	public void render() {
		...
	}
}

As you can see, i’ve got my own intersect method, and i am 100% sure it works perfectly. So no need to create pesky rectangles. :smiley:

And i am now using getCollisionFactor() to check the directions. It basically returns an integer based on what direction and how many pixels of the boxes were penetrated. > 0 means it penetrated in the x-axis; < 0 means it penetrated in the y-axis. 0 means it penetrated diagonally. So i just created 2 for loops and brute-force checked intersects() on every box. If it intersects, it checks the direction of the collision and switches axis.

for (int i = 0; i < Box.boxes.size(); i++) {
			//Edge of the screen collision
			
			//Move those *&#$!
			Box.boxes.get(i).x+=Box.boxes.get(i).xdir;	
			Box.boxes.get(i).y+=Box.boxes.get(i).ydir;
				
			for (int j = 0; j < Box.boxes.size(); j++) {
				if (i != j && Box.intersects(Box.boxes.get(i), Box.boxes.get(j))) {			
					System.out.println("INTERSECT " + Box.getCollisionFactor(Box.boxes.get(i), Box.boxes.get(j)) + " ON " + i + " AND " + j);
					if (Box.getCollisionFactor(Box.boxes.get(i), Box.boxes.get(j)) < -1) {
						System.out.println("X COLLISION");
					}
					else if (Box.getCollisionFactor(Box.boxes.get(i), Box.boxes.get(j)) > 1) {
						System.out.println("Y COLLISION");
					}
					else {
						System.out.println("BOTH COLLISION");		
					}
				}
			}
		}

Yet some glitches are still there:
-When two boxes hit another box from the same direction at the same time, one box ignores the collision and starts to do the dance of his people (usually the one that is placed last on the list) (i managed to workaround-fix this)
-Diagonal collisions, depending on direction, also makes the boxes go nuts

Ignore the isFree() method, it is a leftover from the last algorythm.

Thanks :slight_smile:

EDIT: By using some Zo-Master Ninja levels of debugging, i found out that diagonal collision is the root of all evil. Gotta purge it.