0
\$\begingroup\$

The problem is as follows:

Think 2D Zelda (Links Awakening, A Link to the Past) style movement where you can run into walls from any of the four cardinal directions, or basically up, down, left, and right. The difference between my movement and these games is I want to allow for diagonal movement as well. When the player collides with a wall on the left, for example, if he is pushing left and up I want him to stop moving left but continue moving up. The problem I am having is my code currently detects the collision as both an upwards and a left collision so the player simply stops. What is the approach I should take to remedy this?

        bool canCollideLeft = false;
        bool canCollideRight = false;
        bool canCollideUp = false;
        bool canCollideDown = false;

        if (HeroRect.Left > OldHeroRect.Left)
        {
            canCollideLeft = false;
            canCollideRight = true;
        }

        if (HeroRect.Left < OldHeroRect.Left)
        {
            canCollideLeft = true;
            canCollideRight = false;
        }

        if (HeroRect.Bottom > OldHeroRect.Bottom)
        {
            canCollideUp = false;
            canCollideDown = true;
        }

        if (HeroRect.Bottom < OldHeroRect.Bottom)
        {
            canCollideUp = true;
            canCollideDown = false;
        }


        foreach (RectangleItemProperties rectangle in CollisionRectangles)
        {
            Rectangle CollisionRect = new Rectangle((int)rectangle.Position.X, (int)rectangle.Position.Y, (int)Math.Abs(rectangle.Width), (int)Math.Abs(rectangle.Height));

            if (HeroRect.Intersects(CollisionRect))
            {
                if (canCollideDown && HeroRect.Bottom >= CollisionRect.Top && HeroRect.Bottom <= CollisionRect.Bottom)
                {
                    hero.position.Y = OldHeroRect.Location.Y;
                }

                if (canCollideUp && HeroRect.Top >= CollisionRect.Top && HeroRect.Top <= CollisionRect.Bottom)
                {
                    hero.position.Y = OldHeroRect.Location.Y;
                }

                if (canCollideLeft && HeroRect.Left <= CollisionRect.Right && HeroRect.Left >= CollisionRect.Left)
                {
                    hero.position.X = OldHeroRect.Location.X ; ;
                }

                if (canCollideRight && HeroRect.Right >= CollisionRect.Left && HeroRect.Right <= CollisionRect.Right )
                {
                    hero.position.X = OldHeroRect.Location.X;
                }
            }
        }

In summary the code compares the old position with the new position to see which direction we have moved and checks for a potential collision there. So if we move up and to the left, canCollideLeft and canCollideUp will be true. I am pretty sure this is where my problem lies and I need to better check which direction I am colliding from.

Any thoughts or insight?

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

From your code it seems you're checking both directions at the same time, but for proper movement it's better to check each direction individually. You can google around for Axis Aligned Bounding Boxes to find various methods of doing rectangle collision.

\$\endgroup\$
1
  • \$\begingroup\$ This was exactly the trouble. I've now implemented a (mostly) working solution with the advice you gave. There are a few bugs I need to work out but this is definitely the direction I needed to go in. Thanks! \$\endgroup\$ Jan 31, 2012 at 3:42

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .