Jump to content
  • Advertisement
Sign in to follow this  
ChronoDK

2D collision troubles

This topic is 3941 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

I'm creating a 2D top-down RPG-type game, and the collision is giving me some troubles. My collision map is a list of rectangles, and I check the player character's collision box against this list of rectangles. It works rather well, with the player character sliding along the rectangles except when I hit a corner. Easier to explain with code: void CActor::Update( std::vector<CRect> &collisionBoxes ) { //Calculate velocity m_velocity = CVector2D( m_targetX - m_position.GetX(), m_targetY - m_position.GetY() ); m_velocity.Normalize(); m_velocity *= m_maxSpeed; //Move to new position m_position.SetX( m_position.GetX() + (int)m_velocity.GetX() ); m_position.SetY( m_position.GetY() + (int)m_velocity.GetY() ); //Cancel movement if there is a collision bool v = false; bool h = false; if( GetCollision().RectCollideV( collisionBoxes ) ) v = true; if( GetCollision().RectCollideH( collisionBoxes ) ) h = true; if (v) m_position.SetY( m_position.GetY() - (int)m_velocity.GetY() ); if (h) m_position.SetX( m_position.GetX() - (int)m_velocity.GetX() ); } The actor has a target and moves there in a straight line. If he encounters a vertical collision the Y part of his movement is canceled, and if he encounters a horizontal collision the X part of his movement is canceled. Naturally, when he hits the corner of a collision box both X and Y movement will be canceled causing him to freeze. How do I solve this problem?

Share this post


Link to post
Share on other sites
Advertisement
But sometimes he hits a corner and therefore both sides at the same time. I tried making him remember which side(s) he hit in the previous frame, and that almost solved the problem. But adding another collision box adjacent to the first one, will enable the player to slide through one of them :(

See the code, and suggest me a new solution:

void CActor::Update( std::vector<CRect> &collisionBoxes ) {
//Calculate velocity
CVector2D velocityOld = m_velocity;
m_velocity = CVector2D( m_targetX - m_position.GetX(), m_targetY - m_position.GetY() );
m_velocity.Normalize();
m_velocity *= m_maxSpeed;

//Move to new position
m_position.SetX( m_position.GetX() + (int)m_velocity.GetX() );
m_position.SetY( m_position.GetY() + (int)m_velocity.GetY() );

//Cancel movement if there is a collision
bool v = GetCollision().RectCollideV( collisionBoxes );
bool h = GetCollision().RectCollideH( collisionBoxes );

if (v && !h) {
m_position.SetY( m_position.GetY() - (int)m_velocity.GetY() );
m_colV = true;
m_colH = false;
}
else if (h && !v) {
m_position.SetX( m_position.GetX() - (int)m_velocity.GetX() );
m_colH = true;
m_colV = false;
}
else if (h && v) {
if (m_colV && !m_colH) {
m_position.SetY( m_position.GetY() - (int)m_velocity.GetY() );
}
if (m_colH && !m_colV) {
m_position.SetX( m_position.GetX() - (int)m_velocity.GetX() );
}
if (!m_colV && !m_colH) {
m_position.SetY( m_position.GetY() - (int)m_velocity.GetY() );
m_position.SetX( m_position.GetX() - (int)m_velocity.GetX() );
}
}
else if (!h && !v) {
m_colV = false;
m_colH = false;
}

//Update the animation
HandleAnimation();
}

Share this post


Link to post
Share on other sites
I solved it by doing an extra collision check after all the above. Would still like to hear about better solutions though :)

Share this post


Link to post
Share on other sites
I had this exact same problem when I first started my side scroller :)

Someone here gave me some very helpful advice which was a different approach to the problem, and I am happy I can help someone else out who was in the same predicament! Here is what he told me to do (which worked perfectly). Try calculating the distance from the edges of the player to the edges of the rectangle. Or more specifically, the the top edge of the player needs the distance checked with the bottom edge of the rectangle, the bottom edge of the player needs the distance checked with the top edge of the rectangle, left edge of the player needs distance checked with the right edge of the rectangle, and the right edge of the player needs distance checked with the left edge of the rectangle.

One you have all four of these distances calculated, you will be able to see which one is the smallest. the smallest one is the side of the tile which you need to hold the player at. Give it a try, and if you are confused or run into problems, I'll be happy to further clarify!

Share this post


Link to post
Share on other sites
I was having the same problem as you, and started learning www.box2d.org. There are three steps:
1. Store the edges of all collisions
2. Assign a corrective velocity for each collision edge
3. Update the system with the new velocities.

For boxes they are rotated to be AABB (Axis Aligned Bounding Boxes), then the edge with the most penetration is stored as the collision edge. Friction is calculated, so the collision edges are chopped to size.

If you find a simple solution I'd love to see it.

- valles

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement
×

Important Information

By using GameDev.net, you agree to our community Guidelines, Terms of Use, and Privacy Policy.

We are the game development community.

Whether you are an indie, hobbyist, AAA developer, or just trying to learn, GameDev.net is the place for you to learn, share, and connect with the games industry. Learn more About Us or sign up!

Sign me up!