Collision again. Good detection system.

Hi, I’m working on gravity-based logic game. Please, look at this gif:

Lower and upper rectangles detect collision correctly, but as you can see left-right is the problem. I have no idea how to fix it.
My check() method is called from game loop.

	public void check() {
		man_CenterX = (int) game.man.getBounds().getCenterX();
		man_CenterY = (int) game.man.getBounds().getCenterY();
		for (int i = 0; i < game.level1.getX().size(); i++) {
			System.out.println(i + " " + intersects);
			lvl_CenterX = (int) game.level1.getBounds(i).getCenterX();
			lvl_CenterY = (int) game.level1.getBounds(i).getCenterY();
			intersects = game.man.getBounds().intersects(game.level1.getBounds(i));
			if (intersects) {
				if (man_CenterY - lvl_CenterY > 0) {
					game.man.setY(3);
					System.out.println("HEJ1");
				//	break;
				} else if (man_CenterY - lvl_CenterY < 0) {
					game.man.setY(-3);
					System.out.println("HEJ2");
					//break;
				} else if (man_CenterX - lvl_CenterX > 0) {
					game.man.setX(-3);
					System.out.println("HEJ3");
				//	break;
				} else if (man_CenterX - lvl_CenterX < 0) {
					game.man.setX(3);
					System.out.println("HEJ4");
				//	break;
				}
			}
		}
	}

Ah, tell us what’s printing out from your print statements as well next time (They’re giving some important debug data there.)

Further, this code snippet doesn’t tell us everything we need to know:How are you figuring out the center? Is it grid based, something else? What’s the units for it? How does it equate to the number of pixels on the screen.

General advice: If you’re allowing diagonal movement, separate the X intersections from the Y intersections, otherwise, you’re liable to have the Xs become unreachable.

I split (splitted, splote? No idea :emo:) check() method into two:

	public void checkX() {
		System.out.println("X" + intersectsX);
		man_CenterX = (int) game.man.getBounds().getCenterX();
		for (int i = 0; i < game.level1.getX().size(); i++) {
			lvl_CenterX = (int) game.level1.getBounds(i).getCenterX();
			intersectsX = game.man.getBounds().intersects(game.level1.getBounds(i));
			if (intersectsX) {
				if (man_CenterX - lvl_CenterX > 0) {
					game.man.setX(3);
				//	 break;
				} else if (man_CenterX - lvl_CenterX < 0) {
					game.man.setX(-3);
				//	 break;
				}
			}
		}
	}

	public void checkY() {
		System.out.println("Y" + intersectsY);
		man_CenterY = (int) game.man.getBounds().getCenterY();
		for (int i = 0; i < game.level1.getY().size(); i++) {
			lvl_CenterY = (int) game.level1.getBounds(i).getCenterY();
			intersectsY = game.man.getBounds().intersects(game.level1.getBounds(i));
			if (intersectsY) {
				if (man_CenterY - lvl_CenterY > 0) {
					game.man.setY(3);
					//break;
				} else if (man_CenterY - lvl_CenterY < 0) {
					game.man.setY(-3);
					//break;
				}
			}
		}
	}
}

My game is based on the rectangles, not tiles.

Now gif again. This is happening after splitting the check():

It’s “I split” for present and past so you were correct :slight_smile:

So I’m assuming your problem is fixed? That’s usually how you go about checking different axis so you are fine :slight_smile:

Well, I think I need to get rid of this moving when collision detected on Y-axis. In my game player will be able to change the gravity direction, so there shouldn’t be any auto-move while standing on the ground.

What’s the problem? It isn’t obvious what is going on.

Look at the second gif again.
Using WASD I can change the gravity’s direction. When player’s rectangle collides with left or right wall it works well, doesn’t move and stay near (not in) the wall. When gravity is changed on up or down, player’s rectangle stops before wall, but it’s automatically moving to right or left.
You probably still don’t understand me, so here’s the “game”:
http://www.mediafire.com/?adrhfc1uw2vscfo

One think to try out if it is a general collision problem inside one of these methods or another problem is: Try to switch the calls to checkX() and checkY() so you call them in a differnent order.

Also one little thing: please rename some of your methods and variables. I don’t quite understand what lvl_CenterX is, and I don’t think this is the variable for describing the x mid of the whole level :slight_smile:
And I think setX() should be named moveX(). But all this is not a must do. Other then that this is really good code :slight_smile:

lvl_CenterX (and Y) is a center X of every rectangle on the map. When we’ll get rid of the problem I should do some refactoring.

Now I’m calling checkY() before checkX() and this is happening:

Upper and lower platform collision works well, but left-right makes player’s rectangle… you see, it shouldn’t be like that.

Sorry… I really have no Idea why this is happening… could you maybe post the code for the key handling? maybe there is somewhere a bug… any maybe also post where you do the checkX() and checkY().

gameLoop() is called from initialize():

	private void gameLoop() {
		timer = new Timer();
		timer.schedule(game, 0, 1000 / 60);
	}

	TimerTask game = new TimerTask() {
		public void run() {
			gravity.pulling();
			collision.checkY();
			collision.checkX();
			repaint();
		}
	};

keyTyped() and pulling() in Gravity:

public void keyTyped(KeyEvent kevt) {
		char c = kevt.getKeyChar();
		if (!game.man.isFalling) {
			if (c == 'w') {
				vspeed = 0;
				gUp = true;
				gDown = false;
				gLeft = false;
				gRight = false;
			} else if (c == 's') {
				vspeed = 0;
				gDown = true;
				gUp = false;
				gLeft = false;
				gRight = false;
			} else if (c == 'a') {
				vspeed = 0;
				gLeft = true;
				gUp = false;
				gDown = false;
				gRight = false;
			} else if (c == 'd') {
				vspeed = 0;
				gRight = true;
				gUp = false;
				gDown = false;
				gLeft = false;
			}
		} else {

		}
	}
	public void pulling() {
		if (gUp) {
			//vspeed += gravity / 2;
			game.man.setY(-3);
		} else if (gDown) {
			//vspeed += gravity / 2;
			game.man.setY(3);
		} else if (gRight) {
			//vspeed += gravity / 2;
			game.man.setX(3);
		} else if (gLeft) {
			//vspeed += gravity / 2;
			game.man.setX(-3);
		}
	}

It might work better if you determine the amount of overlap in both directions. Then you can use that data to move the player back the proper amount (instead of always ±3).

Some sample code adapted from my own collision detection scheme:

edit: you can also just remember the old player position and put it back if there was a collision


    // find overlapping box
    int ix1 = Math.max(bx11, bx12);
    int iy1 = Math.max(by11, by12);
    int ix2 = Math.min(bx21, bx22);
    int iy2 = Math.min(by21, by22);

    int swap;

    if(ix2 < ix1)
    {
      swap = ix1;
      ix1 = ix2;
      ix2 = swap;
    }

    if(iy2 < iy1)
    {
      swap = iy1;
      iy1 = iy2;
      iy2 = swap;
    }

    // return if no overlap
    if(ix2 < ix1 && iy2 < iy1)
      return false;

    // width and height of overlapping area
    int iw = ix2 - ix1;
    int ih = iy2 - iy1;

You would benefit from having more debugging information on screen. You should use drawString to print the current direction of the gravity and maybe a few other variables or statistics like x velocity, y velocity, etc.

I downloaded your game and gave it a run.

So, when the ‘man’ collides with the box-border on the right, the movement that follows (man starts to move towards bottom) indicates two things:

  1. x movement stops, because gravity and the pushback caused by the horizontal border collision code cancel each other out.
  2. y movement starts, AS IF the pushback from the vertical border collision code is giving the man a +y movement.

I’m guessing (2) happens again and again because with (1), the collision is triggered over and over each frame.

This is based on the assumption that during the demo action:
(a) you NEVER change the gravity
(b) the only things which move the man are gravity and the pushback when colliding with a wall.

I also observe that the movement, upon collision, is either up or down based on whether the man collides with the right wall above or below its midpoint, which adds to the evidence that the vertical movement is caused by the repeatedly triggered y-checks.

Looking at your “intersection” test: you seem to be using the same test for xIntersects and yIntersects:

game.man.getBounds().intersects(game.level1.getBounds(i));

The only way you might not be getting BOTH an x & y intersect = true each time would be if there were two lists of “bounding rectangles” – one that can only result from a vertical and one that can only result a horizontal collision, and the segregated collision tests only test for intersection with the appropriate list of boundary boxes.

Hope this analysis helps.