Bounding box collision in a platformer game

Started by
10 comments, last by BeerNutts 10 years, 2 months ago

Hello devs,

I am making a prototype for my first game (when I say "first" I mean that I camed up with the ideea myself, not games like pong or tic-tac-toe, which by the way, you can see here and here).

I had some problems with gravity but fixed it after a while. Next problem that I faced was bounding box collision detection...

[attachment=19567:Capture.PNG]

With red are drawn the bounding boxes.

I can stay on the top the ground. But like in any other platformer, you will hit the platform from down, left and right too.

I don't really know how to code collision when player hit the platform from other sides.

Here is the code to stay above the platform.


if(player.bbox.Intersect(&platform1.bbox))
{
      player.y = platform1.y1 - player.width; //platform1.y1 - top-left corner Y coordinate
}

My bounding box class give me acces just to: x1, y1, x2, y2 coordinates of the bounding box, Intersect function (that checks if 2 bounding boxes intersects) and TestPoint function(that checks if a point is inside a bounding box).

How I can do the collision with the other sides of the platform not only the top of it?

"Don't gain the world and lose your soul. Wisdom is better than silver or gold." - Bob Marley

Advertisement

I cover the topic in detail in this tutorial

Here is the code to detect a collision from any direction:


return (this.x <= rect.x + rect.width &&
                rect.x <= this.x + this.width &&
                this.y <= rect.y + rect.height &&
                rect.y <= this.y + this.height);

The explanation of why it works is in the tutorial. I actually did a whole series of gamdev math tutorials that you may find useful.

Let me know if you have any questions.

The logic is just the same, you could just swap X and Y for that matter...

Using the same approach you used on your own function:
if(player.bbox.Intersect(&platform1.bbox))
{
	//Y axis
	if (player.y1 <= platform1.y1) //assuming y1 to be the "bigger-y coordinate"
		player.y1 = platform1.y1 - player.height; //To place it on top of the platform.
	else
		player.y1 = platform1.y2 + 1; //To place it under the platform when hit from below.
	//X axis
	if (player.x1 >= platform1.x1) //assuming x1 to be the "smaller-x coordinate"
		player.x1 = platform1.x2 + 1;
	else
		player.x1 = platform1.x1 - player.width; //To move it aside from the intersected platform.
}
This could probably work on general situations, with moderate speeds and all that.
I am assuming that (y1, x1) is the top-left coordinate, and (x2, y2) is the bottom-right one.
You'll probably have to adjust the code.

I guess I've been using Box2D for too long, getting lazy.

The logic is just the same, you could just swap X and Y for that matter...

Using the same approach you used on your own function:


if(player.bbox.Intersect(&platform1.bbox))
{
	//Y axis
	if (player.y1 >= platform1.y1) //assuming y1 to be the "bigger-y coordinate"
		player.y1 = platform1.y1 - player.height; //To place it on top of the platform.
	else
		player.y1 = platform1.y2 + 1; //To place it under the platform when hit from below.
	//X axis
	if (player.x2 >= platform1.x1) //assuming x1 to be the "smaller-x coordinate"
		player.x1 = platform1.x1 - player.width; //To move it aside from the intersected platform.
	else
		player.x1 = platform1.x2 + 1;
}

This could probably work on general situations, with moderate speeds and all that.

I am assuming that (y1, x1) is the top-left coordinate, and (x2, y2) is the bottom-right one.

You'll probably have to adjust the code.

Remember to reset the speeds and all that when it hit an immovable object!

I guess I've been using Box2D for too long, getting lazy.

You are assuming everything right. I am getting lazy too... I should think of another checking in that if statement..

I will try it to see if it works.

"Don't gain the world and lose your soul. Wisdom is better than silver or gold." - Bob Marley

I cover the topic in detail in this tutorial

Here is the code to detect a collision from any direction:


return (this.x <= rect.x + rect.width &&
                rect.x <= this.x + this.width &&
                this.y <= rect.y + rect.height &&
                rect.y <= this.y + this.height);

The explanation of why it works is in the tutorial. I actually did a whole series of gamdev math tutorials that you may find useful.

Let me know if you have any questions.

I will check your tutorials. Thank you:)

"Don't gain the world and lose your soul. Wisdom is better than silver or gold." - Bob Marley

You are assuming everything right. I am getting lazy too... I should think of another checking in that if statement..
I will try it to see if it works.

My last code is wrong, the horizontal part, I have just fixed it, please take another look.

Its not working.. the condition for y axis and x axis are true at the same time.. so when I jump on the platform I stay on top of it but because x axis conditions are true I am stucked.

"Don't gain the world and lose your soul. Wisdom is better than silver or gold." - Bob Marley

Yes, it needs another test level... Be back in a jiffy.


if(player.bbox.Intersect(&platform1.bbox))
{
	//Y axis
	if (player.y1 <= platform1.y1) {//assuming y1 to be the "bigger-y coordinate"
		player.y1 = platform1.y1 - player.height; //To place it on top of the platform.
	}
	else if (player.y1 >= platform1.y2) {
		player.y1 = platform1.y2 + 1; //To place it under the platform when hit from below.
	}
	//X axis
	else {
		if (player.x1 >= platform1.x1) //assuming x1 to be the "smaller-x coordinate"
			player.x1 = platform1.x2 + 1;
		else
			player.x1 = platform1.x1 - player.width; //To move it aside from the intersected platform.
	}
}


This should prevent it from updating both at the same time... It could also be something like this:

if(player.bbox.Intersect(&platform1.bbox))
{
	//Y axis
	if (/*vertical collision*/) {
		if (player.y1 <= platform1.y1) {//assuming y1 to be the "bigger-y coordinate"
			player.y1 = platform1.y1 - player.height; //To place it on top of the platform.
		}
		else {
			player.y1 = platform1.y2 + 1; //To place it under the platform when hit from below.
		}
	//X axis
	if (/*horizontal collision*/) {
		if (player.x1 >= platform1.x1) //assuming x1 to be the "smaller-x coordinate"
			player.x1 = platform1.x2 + 1;
		else
			player.x1 = platform1.x1 - player.width; //To move it aside from the intersected platform.
	}
}
Sorry for anything wrong, I'm just not used to code without obsessively testing every added code block. I guess I am not used to think ahead...

Can I ask why you don't use a really simple 2D physics system like this one? Something like that is more robust and re-usable than what it looks like you're doing.

Inspiration from my tea:

"Never wish life were easier. Wish that you were better" -Jim Rohn

soundcloud.com/herwrathmustbedragons

Something I used in a project is checking collisions between the front sides of a moving box against the back sides of the others.

After you calculate all the forces influencing your character, you have the resultant force as a 2D vector.

mj0lcn.jpg

You can verify the numerical signs of the components of this force to know which sides of the box are the front sides, which are the sides facing towards the direction of movement.
The sign of the X component of the force indicates whether a frontal side of the box will be the left or right one, and the sign of the Y component of the force indicates if the other frontal side is up or down. When the force is completely horizontal or vertical so one of the components of the force has a sign of "zero," you will have a single frontal side.

It is these front sides that will collide against the back sides of the other boxes - the front sides of a box can only collide against the back sides of another box, you will never have back-back or front-front side collision.

1gcut.jpg

This helps avoiding a common issue where your character can skip obstacles if it moves more than the width or the height of its collision box on a single frame.
You can use the old frame position for the back sides of the character's box and use the new position for the front sides of the character's box (the position of the front sides after they are moved). This way you don't have a box anymore, but an extruded "shape" that represents the full motion of the character for that frame, and it is something that always seems pass tests no matter the speed of the character.
You can still use rectangle intersections with this. You would supply the coordinates of the top-left corner and the bottom-right corner of the screen area (or bounding box) occupied by this shape as a rectangle to be tested against the others. While this is an approximation, it seems to convey the illusion to great effect.
When a collision is detected, instead of simply stopping the character, you need to move it as much as it is possible to move both horizontally and vertically until it reaches the obstacle. This is simple to calculate based on the position and boundaries of the character and the position and boundaries of the obstacle. This makes the character gently touch a wall instead of keeping a distance from it, in case the character moves farther than its width or height.

This topic is closed to new replies.

Advertisement