Box collision handling - no detection

I had this work a week ago, but then I finished it. I can't get it to work again. I have 2D sprites, they are just rectangles. No twist. I’m not looking for a way to detect a collision between them, I have it, and there are thousands of articles about it. What I cannot find is any resource on what to do when you see a collision. All I want is that sprites should not overlap. No bouncing or anything else. They just stop. In particular, right now I have a player and some level tiles that he stumbles upon.

It sounds simple, but it is not. It must be very accurate or strange things. I tried to fix this all day with weird mixed results. Sometimes my player gets stuck in the floor and cannot move left or right. When I fix this, it can go through the blocks on the left or right.

So, my current setup thinks this way: try moving the player where he wants to go. Then ask for a map if its tile collides with anything. If so, the map indicates how many pixels overlap in each of the four directions. Now the difficult role is how the player should react to these numbers. When it is on the ground, there is 1 pixel overlapping with the floor so that it knows that it is on the ground (otherwise it vibrates between falling and landing on the ground, because without overlapping it does not see anything below it). This one pixel overlap means that the left and right edges are also embedded in the floor and therefore it cannot move.

Is there a good way for everything to be taken apart using one bounding box for a player? Would it be better to have a separate bounding box for each of its four sides?

+3
source share
5 answers

I think I have it. Mostly inspired by the stone-metal response. My last mistake was that the player was able to “cling” to the walls because his bounding box would be placed one pixel into the wall, and then he would land on the edge of the tile below, stopping him.

, x y. - , x . , , , . , . , (, , , Y, , X). , !

0

; .

, " " true ( , , , ) y . "", .

, , 4 ; , , , , 4 ; , 16x16px, 4 1x16px . , .

; , , , , , : , x y. , x , (, x , /). y. ; / 0, . , .

+2

, , Chipmunk Dynamics, 2D- , , , , .

http://code.google.com/p/chipmunk-physics/

0

, .

, ?

, . , , .

, x, - x . , , , xoverlap . Y , , , 1 .

0

. , , , , !

//! (collision detection)
inline BOOL Sprite::TestCollision(Sprite* pTestSprite)
{
  //! Get the collision box.
  RECT& rcTest = pTestSprite->GetCollision();

  //! box collision check.
  return m_rcCollision.left <= rcTest.right && rcTest.left <= m_rcCollision.right &&
         m_rcCollision.top <= rcTest.bottom && rcTest.top <= m_rcCollision.bottom;
}

, , - , : (: , ). , , , - . , . . , .

In this example, I do test variables with an updated position, and then run a collision test, then follow the procedure below or just set a new position if there is no collision. Therefore, we actually fix it before the collision occurs.

// Update the position
POINT ptNewPosition, ptSpriteSize, ptBoundsSize;
ptNewPosition.x = m_rcPosition.left + m_ptVelocity.x;
ptNewPosition.y = m_rcPosition.top + m_ptVelocity.y;
ptSpriteSize.x = m_rcPosition.right - m_rcPosition.left;
ptSpriteSize.y = m_rcPosition.bottom - m_rcPosition.top;
ptBoundsSize.x = m_rcBounds.right - m_rcBounds.left;
ptBoundsSize.y = m_rcBounds.bottom - m_rcBounds.top;

// Check the bounds
// Wrap?
if (m_baBoundsAction == BA_WRAP)
{
  if ((ptNewPosition.x + ptSpriteSize.x) < m_rcBounds.left)
   ptNewPosition.x = m_rcBounds.right;
  else if (ptNewPosition.x > m_rcBounds.right)
   ptNewPosition.x = m_rcBounds.left - ptSpriteSize.x;
  if ((ptNewPosition.y + ptSpriteSize.y) < m_rcBounds.top)
   ptNewPosition.y = m_rcBounds.bottom;
  else if (ptNewPosition.y > m_rcBounds.bottom)
   ptNewPosition.y = m_rcBounds.top - ptSpriteSize.y;
}
// Bounce?
else if (m_baBoundsAction == BA_BOUNCE)
{
  BOOL bBounce = FALSE;
  POINT ptNewVelocity = m_ptVelocity;
  if (ptNewPosition.x < m_rcBounds.left)
  {
   bBounce = TRUE;
   ptNewPosition.x = m_rcBounds.left;
   ptNewVelocity.x = -ptNewVelocity.x;
  }
  else if ((ptNewPosition.x + ptSpriteSize.x) > m_rcBounds.right)
  {
   bBounce = TRUE;
   ptNewPosition.x = m_rcBounds.right - ptSpriteSize.x;
   ptNewVelocity.x = -ptNewVelocity.x;
  }
  if (ptNewPosition.y < m_rcBounds.top)
  {
   bBounce = TRUE;
   ptNewPosition.y = m_rcBounds.top;
   ptNewVelocity.y = -ptNewVelocity.y;
  }
  else if ((ptNewPosition.y + ptSpriteSize.y) > m_rcBounds.bottom)
  {
   bBounce = TRUE;
   ptNewPosition.y = m_rcBounds.bottom - ptSpriteSize.y;
   ptNewVelocity.y = -ptNewVelocity.y;
  }
  if (bBounce)
   SetVelocity(ptNewVelocity);
}
// v0.1.1 (collision detection)
// Die?
else if (m_baBoundsAction == BA_DIE)
{
  if ((ptNewPosition.x + ptSpriteSize.x) < m_rcBounds.left || ptNewPosition.x > m_rcBounds.right
   || (ptNewPosition.y + ptSpriteSize.y) < m_rcBounds.top || ptNewPosition.y > m_rcBounds.bottom)
   return SA_KILL;
}
// v0.1.1 ----------------------
// Stop (default)
else
{
  if (ptNewPosition.x  < m_rcBounds.left || ptNewPosition.x > (m_rcBounds.right - ptSpriteSize.x))
  {
   ptNewPosition.x = max(m_rcBounds.left, min(ptNewPosition.x, m_rcBounds.right - ptSpriteSize.x));
   SetVelocity(0, 0);
  }
  if (ptNewPosition.y  < m_rcBounds.top || ptNewPosition.y > (m_rcBounds.bottom - ptSpriteSize.y))
  {
   ptNewPosition.y = max(m_rcBounds.top, min(ptNewPosition.y, m_rcBounds.bottom - ptSpriteSize.y));
   SetVelocity(0, 0);
  }
}
0
source

Source: https://habr.com/ru/post/1716454/


All Articles