Need help with Collision Detection and 2D player movement


#1

Hello, I am quite new to these forums but I have been trying for over a week and a half to find a working, optimized physics based collision detection system for a 2D plat-former game I am making right now in SDL. Everything anyone has suggested has not worked and is not what I am looking for.

At the moment I have created a custom bounding box (yes I know there is SDL_Rect) that has a custom Vector2 point, a width and a height and checking if two bounding boxes overlap. This is kindof working however I need a way to see the difference between hitting a wall or the floor/roof or at least be able to correctly collide off of a given surface.

I need a way to physically interact with surfaces so that I can walk along the floor, not walk through walls and jump around with physically based calculations. (Walls/Floors/Roofs are all the same class with the same data)

My current code for detecting if I hit a wall at all is:

    //Iterate through all walls
	vector<Walls*>::iterator wallIter;
	for (wallIter = walls.begin(); wallIter != walls.end(); ++wallIter) {

		//If entity went too far to the left or right or has collided with wall
		if ((character->GetCollisionBox()->X() < 0) ||
			(character->GetCollisionBox()->X() + character->GetCollisionBox()->W() > screenWidth) ||
			(character->GetCollisionBox()->CheckCollision((*wallIter)->GetCollisionBox()))) {

			//Move back
			character->GetCollisionBox()->X() -= xVelocity * deltaTime;
		}

		//If entity went too far up or down or has collided with the wall
		if ((character->GetCollisionBox()->Y() < 0) ||
			(character->GetCollisionBox()->Y() + character->GetCollisionBox()->H() > screenHeight) ||
			(character->GetCollisionBox()->CheckCollision((*wallIter)->GetCollisionBox()))) {

			//Move back
			character->GetCollisionBox()->Y() -= yVelocity * deltaTime;
		}
	}

bool
Rectangle::CheckCollision(Rectangle* other) {
	//The sides of the rectangles
	int leftA, leftB;
	int rightA, rightB;
	int topA, topB;
	int bottomA, bottomB;

	//Calculate the sides of rectangle A
	leftA   = static_cast<int>(this->X());
	rightA  = static_cast<int>(this->X() + this->W());
	topA    = static_cast<int>(this->Y());
	bottomA = static_cast<int>(this->Y() + this->H());

	//Calculate the sides of rectangle B
	leftB   = static_cast<int>(other->X());
	rightB  = static_cast<int>(other->X() + other->W());
	topB    = static_cast<int>(other->Y());
	bottomB = static_cast<int>(other->Y() + other->H());

	//If any of the sides from rectangle A are outside of B
	//Then there is no possible way the two boxes are colliding
	if (bottomA <= topB) {
		return false;
	}
	if (topA >= bottomB) {
		return false;
	}
	if (rightA <= leftB) {
		return false;
	}
	if (leftA >= rightB) {
		return false;
	}

	//If none of the sides of the primary rectangle are outside of other
	//Then there must be a collision of some sort
	return true;
}

However this has the issue that the character can’t tell if he’s hitting a wall or the floor/roof meaning as soon as he collides with anything, he can no longer jump, or move left and right. This same issue would occur if he’s colliding with the walls. Also, there’s a weird issue with movement where the velocity will keep ticking up and at a certain point the velocity gets so high that the collision detection fails and the character flys off into the thousands of X, Y.

And my current movement code which I can’t seem to get working realistically is bellow. The current code kindof works and makes the character realistically drop with gravity, move with velocity and friction and acceleration, but there’s a lot of issues with jumping and moving left and right.

void 
PhysicsEngine::ProcessEntity(float deltaTime, 
							 Entity* character, vector<Walls*> walls,
							 double screenWidth, double screenHeight)
{
	//Set initial velocities
	//xVelocity = character->GetXVelocity();
	//yVelocity = character->GetYVelocity();

	//Get Accelerations
	xAccel = character->GetMaxMovementSpeed() / deltaTime;
	xAccel *= character->GetMovementState(); //Change in acceleration when player moves
	yAccel = gravity / deltaTime;			 //Constant acceleration downwards due to gravity

	//Set velocity
	xVelocity += xAccel - mx_d_currentFrictionCoe * xVelocity;
	yVelocity += yAccel * deltaTime;

	//Displace the entity left or right
	character->GetCollisionBox()->Y() += yVelocity * deltaTime;
	character->GetCollisionBox()->X() += xVelocity * deltaTime;

Can someone please help me with this. I want to be able to walk along the surface of any floor positioned at any height within the window, bump my head and fall down along any roof within the window, and collide with walls left and right of the character correctly and be able to move away from the wall but not walk through it.


#2

just to make sure, in this description you cannot cross a wall in any direction, and you cannot cross a floor/roof in any direction. So what is the difference between floor and wall?


#3

Sorry, I wasn’t clear about that.
Roofs and walls are the same. They’re the exact same class with the same data, it’s just that from everything i’ve tried, people seem to describe the collision detection as needing separate algorithms between walls and floors.

But to be super clear: Yes, they are the same. There is no difference.


#4

cool, then it should be easy. In some games, roofs can be crossed from below when you jump, and become like floors when you land onto them. In your case, everything is blocking in any direction, so it should be much easier.

The first program you have to make, is just a character walking on a floor. You need to test that a floor is below your character. A collision test can be used, but it’s not enough, you need to decide that walking is possible only when you are 0,1,2 pixels above the floor (or 1,2… pixel below, you choose). Let’s call this the walking height

  • if your character is at walking height, don’t activate the “falling down”; instead, activate the “walking” by reacting to left/right arrow

  • if your character is falling down and hits a floor (collision test) then put it back at walking height

  • when walking, always check the walking height, because if the floor disappears, you need to activate the “falling down”.

  • when falling down, you may or may not activate left/right arrow, this depends on your game.


#5

What would be the best and fastest way to find that out? Previously I was using struct made from 4 bools that checked for left, right, up and downwards collisions by looking at the X and Y positions of the surfaces, however this had issues with walls when the X and Y where above the character but the wall was supposed to be testing positive for a left or right collision.

Also, I had issues where the character would get stuck inside walls/floors. Although with a walking height value this might fix it. So what you’re saying is:

If(collision)
Check collision direction
If(bellow)
Set player height = surfaceX + walking height //Maintain walking height

Then only process downwards movement when the player is NOT colliding with the floor and instead process player left and right input.
And then when player stops colliding with ground, continue processing downwards movement.

I’ll definitely try your solution but what about left and right input movement into walls? What I really need is a consistent, algorithmic way of testing if a collision is left, right, down or up.


#6

it’s the same technique as the “walking height”. If you bump onto a wall, then put the character back just at the “correct” colliding distance from the wall. (say, 1 or 2 pixels away from the wall), and set your speed to 0 (in case you are using a speed variable).


#7

Alright, I’ll give this a go.
And what would be the best way to test for direction of collision to a wall?


#8

you mean: either from the left or from the right?
I think you can figure this out by yourself :wink:


#9

it really depends how you encode your data. For simple platformers, everythings is actually located on a (fairly) large grid: each grid cell is either: wall, floor, or free space. Everything is stored in an array[i,j], and it’s easy to check what is in the cell ‘below’ the character. (the character occupies exactly one grid cell)

More sophisitcated games have floors and wall at arbitrary positions. There are two standard techniques for collisions: 1. either you have the list of all walls (meaning, their position and size) and you check for collision with all elements of the list. 2. or you maintain a “pixel map”, which is a copy of your screen, where walls and floors are drawn in a specific color, and when you move, you pick up the colors entering the box of your character.


#10

#11

This would be perfect actually…
Thanks for all the help. I’m not sure how to mark a post as answered or if we have to, but this solves my problems.


#12

great, and good luck with your project!


#13

If you make 2d-platformer game on SDL, look at box2d c++ engine.


#14

Or Chipmunk2D, which I’ve used successfully in games before. It can do full physics simulations, or just collision detection if that’s all you want.