Platformer Collision

Whether you're a newbie or an experienced programmer, any questions, help, or just talk of any language will be welcomed here.

Moderator: Coders of Rage

Post Reply
User avatar
xiphirx
Chaos Rift Junior
Chaos Rift Junior
Posts: 324
Joined: Mon Mar 22, 2010 3:15 pm
Current Project: ******** (Unkown for the time being)
Favorite Gaming Platforms: PC
Programming Language of Choice: C++
Contact:

Platformer Collision

Post by xiphirx »

I've been working on a platformer for a few weeks now, and it is at the point where I implement collision.

I am currently attempting the bounding box method, and I guess, am successfully detecting the collision, but I am not exactly handling it quite well. I have tried to set the players collision to its previous position, but it creates a bouncing effect. I have also tried setting the players position next to the collision point, but it makes the player stuck pretty much, or it makes it jerky...

I want the collision to behave like cave story's if that helps... any ideas?

if it matters, C++ + SDL
StarCraft II Zerg Strategy, open to all levels of players!

Looking for paid work :< Contact me if you are interested in creating a website, need a web design, or anything else you think I'm capable of :)
User avatar
Bullet Pulse
Chaos Rift Cool Newbie
Chaos Rift Cool Newbie
Posts: 89
Joined: Sun Feb 21, 2010 6:25 pm

Re: Platformer Collision

Post by Bullet Pulse »

I'll let you figure out the rest of the code specifically for your platformer, but this should give you a good start. :)
The function returns a boolean in case you want to play a sound when two things collide, or etc.
Hint: check out the minDist variables.

Code: Select all

bool ExampleClass::IsCollision(SDL_Rect &rectOne, SDL_Rect &rectTwo)
{
    SDL_Rect rect1 = rectOne;
    SDL_Rect rect2 = rectTwo;
    
    //Find the middle point of each rectangle
    rect1.x = (rect1.x * 2 + rect1.w ) / 2;
    rect1.y = (rect1.y * 2 + rect1.h ) / 2;

    rect2.x = (rect2.x * 2 + rect2.w ) / 2;
    rect2.y = (rect2.y * 2 + rect2.h ) / 2;

    //Determine overlap for each axis
    float xDist = abs(rect1.x - rect2.x);
    float yDist = abs(rect1.y - rect2.y);

    //minimal amount of distance that the two can be apart and not collide
    float xMinDist = (rect1.w + rect2.w) / 2;
    float yMinDist = (rect1.h + rect2.h) / 2;

    if(xDist >= xMinDist || yDist >= yMinDist)
        return false; //neither axis is colliding

    float xOverlap = xDist - xMinDist;
    float yOverlap = yDist - yMinDist;
   
    //These are the options you have:

    if(xOverlap < yOverlap)
        //do something
    else if(xOverlap > yOverlap)
        //do something else
    else
        //xOverlap and yOverlap are equal so you may want to do something else
    return true;
}
Image
XianForce
Chaos Rift Devotee
Chaos Rift Devotee
Posts: 767
Joined: Wed Oct 29, 2008 8:36 pm

Re: Platformer Collision

Post by XianForce »

That's pretty much exact code that Falco posted for collision detection. But if your going to simply use that, xiphirx, you might as well use the improved, and tested code that Falco posted after that. You'll have to search around a bit, but it's the code straight from the Elysian Shadows engine ( or so I'm told).
User avatar
Bullet Pulse
Chaos Rift Cool Newbie
Chaos Rift Cool Newbie
Posts: 89
Joined: Sun Feb 21, 2010 6:25 pm

Re: Platformer Collision

Post by Bullet Pulse »

Please post the updated code if you can find it 8-)
Image
XianForce
Chaos Rift Devotee
Chaos Rift Devotee
Posts: 767
Joined: Wed Oct 29, 2008 8:36 pm

Re: Platformer Collision

Post by XianForce »

Bullet Pulse wrote:Please post the updated code if you can find it 8-)
Well I have it saved to my hard drive... But I want to check with Falco first, to see if he wants me to repost it...

But I'll go look for the link and edit it in here.

EDIT: Found it - http://elysianshadows.com/phpBB3/viewto ... art=999999

It's also in the Programmer's Education Index that Falco posted (it's stickied if you haven't seen it!)
User avatar
xiphirx
Chaos Rift Junior
Chaos Rift Junior
Posts: 324
Joined: Mon Mar 22, 2010 3:15 pm
Current Project: ******** (Unkown for the time being)
Favorite Gaming Platforms: PC
Programming Language of Choice: C++
Contact:

Re: Platformer Collision

Post by xiphirx »

I'll see how implementing this will turn out...
StarCraft II Zerg Strategy, open to all levels of players!

Looking for paid work :< Contact me if you are interested in creating a website, need a web design, or anything else you think I'm capable of :)
XianForce
Chaos Rift Devotee
Chaos Rift Devotee
Posts: 767
Joined: Wed Oct 29, 2008 8:36 pm

Re: Platformer Collision

Post by XianForce »

xiphirx wrote:I'll see how implementing this will turn out...
Haha, if you need any help on explaining the code, ask me and I'll do my best to explain it.
User avatar
xiphirx
Chaos Rift Junior
Chaos Rift Junior
Posts: 324
Joined: Mon Mar 22, 2010 3:15 pm
Current Project: ******** (Unkown for the time being)
Favorite Gaming Platforms: PC
Programming Language of Choice: C++
Contact:

Re: Platformer Collision

Post by xiphirx »

*sight*, nothing went well, as usual.

I am faced with vectors now. I know a bit about them from a beginning physics course I took 1 years ago now. Vectors have a magnitude and direction, where as a scalar just has magnitude.

So, here is my plan:
- create a vec2d class

Code: Select all

class vec2d
{
public:
int mag;
int dirx, diry; //I like slopes more than angels :P
};
- make a function that will get one SDL_Rect (player's bounding box), and generate the second SDL_Rect from the collision map. The function will then determine if they overlap, if they do, create a vector and set its values accordingly. It will return a vector. If the vector has a 0 magnitude, then there was no collision, otherwise, modify the player's coordinates based on the vector.

...

Seems like I'm bound to fail, but it seems like it should work... Here goes..
StarCraft II Zerg Strategy, open to all levels of players!

Looking for paid work :< Contact me if you are interested in creating a website, need a web design, or anything else you think I'm capable of :)
User avatar
xiphirx
Chaos Rift Junior
Chaos Rift Junior
Posts: 324
Joined: Mon Mar 22, 2010 3:15 pm
Current Project: ******** (Unkown for the time being)
Favorite Gaming Platforms: PC
Programming Language of Choice: C++
Contact:

Re: Platformer Collision

Post by xiphirx »

Double Post :O!

Ok, here is what I came up with, it doesn't work quite yet :/

Code: Select all

vec2d Map::checkCollision(SDL_Rect obj)
{
	vec2d vector;

	vector.dirX = vector.dirY = 0;
	vector.mag = 0;

	if ( (obj.y/16) >= 0 &&
		 ((obj.y+obj.h)/16) >=0 &&
		 (obj.x/16) >= 0 &&
		 ((obj.x+obj.w)/16) >=0 &&
		 (obj.y/16) < data1.numrows() &&
		 ((obj.y+obj.h)/16) < data.numrows() &&
		 (obj.x/16) < data1.numcols() &&
		 ((obj.x+obj.w)/16) < data.numcols() &&
		 (
			data1[(obj.y/16)][(obj.x/16)] != 0 ||
			data1[(obj.y/16)][((obj.x+obj.w)/16)] != 0 ||
			data1[((obj.y+obj.h)/16)][(obj.x/16)] != 0 ||
			data1[((obj.y+obj.h)/16)][((obj.x+obj.w)/16)] != 0
		 )
	   )
	{

		SDL_Rect tile;

		tile.x = (obj.x/16)*16;
		tile.y = (obj.y/16)*16;
		tile.w = tile.h = 16;

		if (
				obj.x > tile.x &&
				obj.x < (tile.x+tile.w)
		   )
		{
			vector.dirX = (tile.x+tile.w)-obj.x;
			vector.mag = 1;
		}

		if (
				(obj.x+obj.w) > tile.x &&
				(obj.x+obj.w) < (tile.x+tile.w)
		   )
		{
			vector.dirX = (obj.x+obj.w) - tile.x;
			vector.mag = -1;
		}

		if (
				(obj.y+obj.h) > tile.y &&
				(obj.y+obj.h) < (tile.y+tile.h)
		   )
		{
			vector.dirY = (obj.y+obj.h) - tile.y;
			vector.mag = -1;
		}

		if (
				obj.y < (tile.y+tile.h) &&
				obj.y > tile.y
		   )
		{
			vector.dirY = (tile.y+tile.h) - obj.y;
			vector.mag = 1;
		}
	}
	return vector;
}
vec2d is a class made by me

Code: Select all

#ifndef VEC2D
#define VEC2D

class vec2d 
{
public:
	int mag;
	int dirX, dirY;
};

#endif
Maybe someone can help me sort this out? am I supposed to calculate the center of the boxes or something? looking at my algorithm theoretically, it should work right?
StarCraft II Zerg Strategy, open to all levels of players!

Looking for paid work :< Contact me if you are interested in creating a website, need a web design, or anything else you think I'm capable of :)
XianForce
Chaos Rift Devotee
Chaos Rift Devotee
Posts: 767
Joined: Wed Oct 29, 2008 8:36 pm

Re: Platformer Collision

Post by XianForce »

Alright, a quick suggestion:

Code: Select all

class Vector2D
{
   float x;
   float y;

   float Magnitude();
   void Reverse();
   void Normalize();
   void Reflect(Vector2D& norm);
};
So this is a basic representation of a vector. I noticed you had a magnitude and two integers to represent direction. Also, I'm going to suggest that you use floats or doubles over integers. The numbers won't always be pretty, so you may be losing accuracy with using integers.

Anyways, the x and y represent one end of the vector. The other end is assumed to be (0, 0). So by using the distance formula you can find the distance between (0, 0) and (x, y) - which actually simplifies down to: sqrt(x^2 + y^2). This distance represents the magnitude. The direction of your vector can be found as well by assuming each component to represent the sides of a triangle, and using some geometry.

If you have any questions about that, just let me know =p, hope this post helped haha
User avatar
xiphirx
Chaos Rift Junior
Chaos Rift Junior
Posts: 324
Joined: Mon Mar 22, 2010 3:15 pm
Current Project: ******** (Unkown for the time being)
Favorite Gaming Platforms: PC
Programming Language of Choice: C++
Contact:

Re: Platformer Collision

Post by xiphirx »

Code: Select all

vec2d Map::checkCollision(SDL_Rect obj)
{
	vec2d vector;

	vector.dirX = vector.dirY = 0;
	vector.mag = 0;

	if ( (obj.y/16) >= 0 &&
		 ((obj.y+obj.h)/16) >=0 &&
		 (obj.x/16) >= 0 &&
		 ((obj.x+obj.w)/16) >=0 &&
		 (obj.y/16) < data1.numrows() &&
		 ((obj.y+obj.h)/16) < data.numrows() &&
		 (obj.x/16) < data1.numcols() &&
		 ((obj.x+obj.w)/16) < data.numcols() 
	   )
	{
		SDL_Rect tile;
		tile.x=tile.y=0;
		tile.w = tile.h = 16;
		if (data1[(obj.y/16)][(obj.x/16)] != 0)
		{
			tile.x = (obj.x/16)*16;
			tile.y = (obj.y/16)*16;
		}
		else if (data1[(obj.y/16)][((obj.x+obj.w)/16)] != 0)
		{
			tile.x = ((obj.x+obj.w)/16)*16;
			tile.y = (obj.y/16)*16;
		}
		else if (data1[((obj.y+obj.h)/16)][(obj.x/16)] != 0)
		{
			tile.x = (obj.x/16)*16;
			tile.y = ((obj.y+obj.h)/16)*16;
		}
		else if (data1[((obj.y+obj.h)/16)][((obj.x+obj.w)/16)] != 0)
		{
			tile.x = ((obj.x+obj.w)/16)*16;
			tile.y = ((obj.y+obj.h)/16)*16;
		}

		 
		if (
				obj.x >= tile.x &&
				obj.x <= (tile.x+tile.w)
		   )
		{
			vector.dirX = (tile.x+tile.w)-obj.x;
			vector.mag = 1;
		}

		if (
				(obj.x+obj.w) >= tile.x &&
				(obj.x+obj.w) <= (tile.x+tile.w)
		   )
		{
			vector.dirX = (obj.x+obj.w) - tile.x;
			vector.mag = -1;
		}

		if (
				(obj.y+obj.h) >= tile.y &&
				(obj.y+obj.h) <= (tile.y+tile.h)
		   )
		{
			vector.dirY = (obj.y+obj.h) - tile.y;
			vector.mag = -1;
		}

		if (
				obj.y <= (tile.y+tile.h) &&
				obj.y >= tile.y
		   )
		{
			vector.dirY = (tile.y+tile.h) - obj.y;
			vector.mag = 1;
		}
		
	}
	return vector;
}
Getting there... top and bottom collision work, but the sides dont...
StarCraft II Zerg Strategy, open to all levels of players!

Looking for paid work :< Contact me if you are interested in creating a website, need a web design, or anything else you think I'm capable of :)
User avatar
xiphirx
Chaos Rift Junior
Chaos Rift Junior
Posts: 324
Joined: Mon Mar 22, 2010 3:15 pm
Current Project: ******** (Unkown for the time being)
Favorite Gaming Platforms: PC
Programming Language of Choice: C++
Contact:

Re: Platformer Collision

Post by xiphirx »

Still going at it... :/'

Here is the function

Code: Select all

vec2d Map::checkCollision(SDL_Rect obj)
{
	vec2d vector;

	vector.dirX = vector.dirY = 0;
	vector.xMag = 0;
	vector.yMag = 0;

	if ( (obj.y/16) >= 0 &&
		 ((obj.y+obj.h)/16) >=0 &&
		 (obj.x/16) >= 0 &&
		 ((obj.x+obj.w)/16) >=0 &&
		 (obj.y/16) < data1.numrows() &&
		 ((obj.y+obj.h)/16) < data.numrows() &&
		 (obj.x/16) < data1.numcols() &&
		 ((obj.x+obj.w)/16) < data.numcols() 
	   )
	{
		SDL_Rect tile;
		tile.x=tile.y=0;
		tile.w = tile.h = 16;
		int numy, numx;
		char dir;
		dir = 'N';
		numy = obj.y/16;
		numx = obj.x/16;
		// TOP LEFT = A
		// TOP RIGHT = B
		// BOTTOM LEFT = C
		// BOTTOM RIGHT = D
		// NULL = N
		
		if (data1[numy][numx] != 0)
		{
			tile.x = numx*16;
			tile.y = numy*16;
			dir = 'A';
		}
		 if (data1[numy][numx+1] != 0)
		{
			tile.x = (numx+1)*16;
			tile.y = numy*16;
			dir = 'B';
		}
		 if (data1[numy+1][numx+1] != 0)
		{
			tile.x = (numx+1)*16;
			tile.y = (numy+1)*16;
			dir = 'D';
		}
		 if (data1[numy+1][numx] != 0)
		{
			tile.x = numx*16;
			tile.y = (numy+1)*16;
			dir = 'C';
		}
		if (dir == 'N')
		{
			return vector; //no collision
		}

		switch (dir)
		{
		case 'A': // TOP LEFT
			vector.dirX = ((numx*16) + tile.w) - obj.x;
			vector.dirY = ((numy*16) + tile.h) - obj.y;
			vector.xMag = 1;
			vector.yMag = 1;
			break;
		case 'B': // TOP RIGHT
			vector.dirX = (obj.x+obj.w) - tile.x;
			vector.dirY = ((numy*16) + tile.h) - obj.y;
			vector.xMag = -1;
			vector.yMag = 1;
			break;
		case 'C': // BOTTOM LEFT
			vector.dirX = ((numx*16) + tile.w) - obj.x;
			vector.dirY = (obj.y+obj.h) - tile.y;
			vector.xMag = 1;
			vector.yMag = -1;
			break;
		case 'D': // BOTTOM RIGHT
			vector.dirX = (obj.x+obj.w) - tile.x;
			vector.dirY = (obj.y+obj.h) - tile.y;
			vector.xMag = -1;
			vector.yMag = -1;
			break;
		default:
			return vector; // no collision
			break;
		}
	}
	return vector;
}

and here is handling the result...

Code: Select all

motion = curMap.checkCollision(boundingBox); 
	if (motion.xMag != 0 || motion.yMag != 0)
	{
		switch ( motion.dirX < motion.dirY )
		{
		case true:
			x += motion.dirX * motion.xMag;
			xVel=0;
			break;
		case false:
			y += motion.dirY * motion.yMag;
			yVel=0;
			jumping = false;
			break;
		default:
			break;
		}
	}
I've read the function over about 4 times now... it should work perfectly right? That means the way I'm handling it is wrong... :'/
StarCraft II Zerg Strategy, open to all levels of players!

Looking for paid work :< Contact me if you are interested in creating a website, need a web design, or anything else you think I'm capable of :)
Post Reply