box2d checking for multiple collisions simultaneously

Started by
5 comments, last by Strewya 10 years, 1 month ago

i am currently working on a 2d endless runner using sfml and box 2d in which my player body comprises of 2 fixtures one for the main body and one sensor for checking if it is grounded . also the game consisits of obstacles on which the player can stand and jump ..what want to do is to kill the player if the main body fixture touches the obstacle but not the other ground fixture because that happens when the player is standing on the obstacle .. is there a way to implement such a condition or is there any workaround on how to kill the player when he collides with an obstacle ?? all the fixtures have seperate int tags as the user data ex- every obstacle has int tag of 5 and the player ground sensor has the int tag of 4 .

Advertisement

Yes, you can give the world a contact listener with which you check if the bodies of the collided fixtures are the player and an obstacle.

There are basically two ways about this, either you set up the contact listener, or you manually iterate over all contact after every step and manually check if the player and an obstacle are colliding. The contact listener is the superior way, because you don't have to do any kind of iteration, Box2D will provide you with the two fixtures that are colliding.

Some sample code from my Pong clone:


void PongGame::speedUpBall(b2Contact* contact)
{
	auto fA = contact->GetFixtureA();
	auto fB = contact->GetFixtureB();
	
	auto bA = fA->GetBody();
	auto bB = fB->GetBody();
	b2Body* paddle = nullptr;
	b2Body* ball = nullptr;
	if(bA->GetUserData() == &m_ball)
	{
		ball = bA;
		paddle = bB;
	}
	else if(bB->GetUserData() == &m_ball)
	{
		ball = bB;
		paddle = bA;
	}
	else
	{
		DEBUG_INFO("No ball in collision, leaving");
		return;
	}
		
	if(paddle->GetUserData() != &m_leftPaddle && paddle->GetUserData() != &m_rightPaddle)
	{
		DEBUG_INFO("No paddle in collision, leaving");
		return;
	}
}

devstropo.blogspot.com - Random stuff about my gamedev hobby

Just remember to never modify any of your physics bodies in response directly to one of these callbacks. Box2D doesn't like that at all. You need to cache the contacts in some kind of structure and process them after the update() call if you want to do that.

i have done something like that the problem is the contact callback is called even when the player is standing on top of an obstacle . i want to to tackle that problem like i want to check if the player is colliding with the obstacle but not standing on it so thta i can kll my player when he collides with an obstacle from the sides and not when he is standing on it.. any ideas on how i can do that ??

Can you not check if a) the player intersects the object and b) the ground sensor doesn't intersect the object?

Stuff like this can be tricky. The other approach is to consider the player velocity when the collision occurs - if within a certain tolerance of straight down, consider him standing, if not, consider it a side collision.

thats the thing i cant figure out that how do i check both a) and b) conditions simultaneously because the begin contact returns only one pair of fixtures at at a time .. any ideas about that ? .. i will try with the other approach .. but the first one will be more precise

Don't do that inside your contact listener, instead, when the contact listener is called mark that the player is colliding with the obstacle inside your Player struct/class. Same thing with the ground sensor.

Then, after world.step() returns, check your boolean(s) to determine if you have to kill the player or not.

Example (pseudo code for the most part):


void killCheck(b2Contact* contact)
{
   auto fa = contact->getFixtureA();
   auto fb = contact->getFixtureB();

   auto ba = fa->getBody();
   auto bb = fb->getBody();

   if(ba->getUserData() == ENUM_PLAYER_TYPE && bb->getUserData() == ENUM_OBSTACLE_TYPE)
   {
      //the vice versa should also be checked, if bb is player and ba is obstacle
      m_player.isPlayerColliding = true;
   }

   if(ba->getUserData() == ENUM_GROUND_SENSOR_TYPE && bb->getUserData() == ENUM_OBSTACLE_TYPE)
   {
      //the vice versa should also be checked, if bb is sensor and ba is obstacle
      m_player.isSensorColliding = true;
   }
}


///after world.step() returns

if(m_player.isPlayerColliding == true && m_player.isSensorColliding == false)
{
   //kill player
}
...

devstropo.blogspot.com - Random stuff about my gamedev hobby

This topic is closed to new replies.

Advertisement