C++ tile map collision detection

Started by
9 comments, last by Shaarigan 6 years, 7 months ago

Hi! I'm trying to implement collision for my 2d platformer game.I understand basic meanings of how to detect it. I don't know how to implement it correctly though.

That's how I render my map : 


void MapScreen::Draw(SDL_Renderer*renderer)
{
  	for (int y = 0; y <= map.size(); ++y)
	{
		for (int x = 0; x < map[y].size(); ++x)
		{
			if(map[y][x] != 0)
			{
				SDL_Rect DestRect = {x * 64, y * 64, 64, 64 };
				SDL_Rect sourceRect = {map[y][x] * 64, 0, 64, 64 };
              
				tileSet[0]->Draw(renderer, sourceRect, DestRect);
       		}
      	}
	}
}

And that's how I would like to detect a collision. GetBlockID returns where on a map the block is set.

Getter::getFM() returns instance for fileManager class ->getH() returns window height value.

Int x, int y, int hitboxX, int hitboxX - these are player coordinates and width and height of the sprite.


Vector2* GameplayScreen::getBlockID(int x, int y)
{
	return new Vector2(x < 0 ? 0 : x / 64, y > Getter::getFM()->getH() ? 0 : (y + 64) / 64);
}

bool GameplayScreen::checkCollision(Vector2* v2)
{

}

bool GameplayScreen::checkCollisionRB(int x, int y, int hitBoxX, int hitBoxY)
{
	return checkCollision(getBlockID(x + hitBoxX, y + hitBoxY));
}
bool GameplayScreen::checkCollisionLB(int x, int y, int hitBoxY)
{
	return checkCollision(getBlockID(x, y + hitBoxY));
}
bool GameplayScreen::checkCollisionRT(int x, int y, int hitBoxX)
{
	return checkCollision(getBlockID(x + hitBoxX, y));
}
bool GameplayScreen::checkCollisionLT(int x, int y)
{
	return checkCollision(getBlockID(x, y));
}
bool GameplayScreen::checkCollisionRC(int x, int y,int hitBoxX, int hitBoxY)
{
	return checkCollision(getBlockID(x + hitBoxX, y + hitBoxY));
}
bool GameplayScreen::checkCollisionLC(int x, int y,int hitBoxY)
{
	return checkCollision(getBlockID(x, y + hitBoxY));
}

 

In player class movement method, I want to say : "if not collision you can move, if there is, you can't". Like :

if(!Getter::getMap()->checkCollisionLC){

movement things

}

Advertisement

I would start by checking the basic function of the collision code, which is getBlockID.

If you feed it an x & y, does it give you the right block id?

 

Given that you render in multiples of 64 and blockID seems to work in multiples of 32, this would be worth checking, ihmo.

 

18 minutes ago, DonPedro said:

In player class movement method, I want to say : "if not collision you can move, if there is, you can't". Like :

So what happens if you do?

 

Em, there should be /64. My mistake. Code in a IDE is good. I'll fix it in a post. 

In player I want it to works like this : 


	bool rightBot = Getter::getMap()->checkCollisionRB(posX - Getter::getMap()->getPosX() + moveSpeed, posY - Getter::getMap()->getPosY(), getHitBoxX(), getHitBoxY());
	bool rightCenter = Getter::getMap()->checkCollisionRC(posX - Getter::getMap()->getPosX() + moveSpeed, posY - Getter::getMap()->getPosY(), getHitBoxX(), getHitBoxY()/2);
	bool rightTop = Getter::getMap()->checkCollisionRT(posX - Getter::getMap()->getPosX() + moveSpeed, posY - Getter::getMap()->getPosY(), getHitBoxX());

	if (velX > 0)
	{
		if(!rightCenter && !rightTop && !rightBot)
		{
			if (posX >= (Getter::getFM()->getW() / 2) - getHitBoxX() && Getter::getMap()->getMoveMap())
			{
				Getter::getMap()->MoveMap(-velX, 0);
			}
			else posX += velX;

			moveAnim = true;
		}
	}


Right now, it doesn't do nothing bout the move right, because bool checkCollision() is empty. 

1 hour ago, DonPedro said:

Right now, it doesn't do nothing bout the move right, because bool checkCollision() is empty. 

So that would be something you'll want to fix ;)

To be clear on this, I won't be giving ready-to-paste solutions, and I don't expect anyone else to do that either. We have a simple rule, everybody solves his/her own problems.

 

So it seems to me you're somewhat stuck with this collision thing I guess?

A useful strategy in many cases is to simplify the problem, then solve the simpler problem, then use that knowledge to solve the bigger problem. (Your'e stuck doing it in 1 step as it looks too difficult, so take 3 smaller simpler steps instead.)

 

In this case solve only one of the 3 tests. You may also want to consider first only the case that your player is a single pixel (width and height are both 1). Then the question becomes "when does the pixel collide?", ie what test must be done?

If you can solve that, consider how the solution changes if the height is still 1, but width is, say 10. If you can solve that generalize to any width, then change height (reverting width to 1 if you don't see the solution), etc

Solve the elementary test (when do I have a collision with a pixel at (x,y)), and then solve several close related problems with changing width and height, and soon enough you will see a pattern what to do.

Once you have that, extend back to 3 tests instead of 1.

That's right. I'm not even looking for ready-to-paste. I'm looking for some, you know, advices, maybe examples, for that what can help me, to understand what I should change in my thinking. I don't exactly understand what do you mean about these 3 smallser simpler steps.

For anything you can't solve, your problem is too big. Too many different things play a role all at the same time, interacting and what not.

The general strategy is

  1. simplify the problem,
  2. solve the simpler problem, and
  3. find out how the solution changes when you "unsimplify" it (ie use the knowledge you gained to solve the original problem)

That's 3 steps :P

If you get stuck at step 2, "for anything you can't solve, your problem is too big ....."

That is, you can often simplify several times before you hit rock-bottom. In your case, it's rock-bottom is "Is pixel (x,y) a collision?", some sort of expression that decides whether the (x,y) position represents a collision or not.

It's not entirely rock-bottom though, you can simplify further to eg "Is pixel (251, 749) a collision?" (Instead of variables first try to decide given specific values for your variables.)

 

 

 

 

I think I know what you are about. I should create a new project with minimalistic player physics. In this case, create basic map class and try to collide. 

Not entirely.

You can only program things that you know how to solve. If you don't know the solution, you can't code it. A new project won't make it simpler, as the rock-bottom case is still the rock-bottom case that needs to be solved.

 

At such a time, stop coding, turn off the computer, grab a pencil and paper (or take a walk, or do the dishes, or whatever works for you to get that grey stuff in your head working), and try to solve the problem on paper (or in your head).

 

This might be a useful reference for you, if you've not come across it. I'm tinkering with a 2D platformer at the moment, and it's been a good read. 

http://higherorderfun.com/blog/2012/05/20/the-guide-to-implementing-2d-platformers/

They provide some detailed (and experienced) tips on how to consider tilemap collision from a platformers perspective. 

 

There was a similar post/problem some time ago you might think usefull to read. Physics in 2D-Games can/should be as simple as comparing 2 rectnagles to each other and go ahead from there

https://www.gamedev.net/forums/topic/691635-trouble-with-collision-detection-response-in-monogame/?tab=comments#comment-5354926

This topic is closed to new replies.

Advertisement