Take the 2-minute tour ×
Game Development Stack Exchange is a question and answer site for professional and independent game developers. It's 100% free, no registration required.

The example provided by Microsoft seems as if the collision detection (from what I can see) will have a small error. When the user collides with an Unpassable tile, the depth of the intersection is calculated. The smaller of the depth values X and Y is used to fix the position of the user so it no longer collides with the tile. But if the user was travelling diagonally could this result in the user not ending up in precisely the point where the character would first collide with the tile?

I'm probably wrong but that's just the way I see it.

   private void HandleCollisions()
        {
            // Get the player's bounding rectangle and find neighboring tiles.
            Rectangle bounds = BoundingRectangle;
            int leftTile = (int)Math.Floor((float)bounds.Left / Tile.Width);
            int rightTile = (int)Math.Ceiling(((float)bounds.Right / Tile.Width)) - 1;
            int topTile = (int)Math.Floor((float)bounds.Top / Tile.Height);
            int bottomTile = (int)Math.Ceiling(((float)bounds.Bottom / Tile.Height)) - 1;

            // Reset flag to search for ground collision.
            isOnGround = false;

            // For each potentially colliding tile,
            for (int y = topTile; y <= bottomTile; ++y)
            {
                for (int x = leftTile; x <= rightTile; ++x)
                {
                    // If this tile is collidable,
                    TileCollision collision = Level.GetCollision(x, y);
                    if (collision != TileCollision.Passable)
                    {
                        // Determine collision depth (with direction) and magnitude.
                        Rectangle tileBounds = Level.GetBounds(x, y);
                        Vector2 depth = RectangleExtensions.GetIntersectionDepth(bounds, tileBounds);
                        if (depth != Vector2.Zero)
                        {
                            float absDepthX = Math.Abs(depth.X);
                            float absDepthY = Math.Abs(depth.Y);

                            // Resolve the collision along the shallow axis.
                            if (absDepthY < absDepthX || collision == TileCollision.Platform)
                            {
                                // If we crossed the top of a tile, we are on the ground.
                                if (previousBottom <= tileBounds.Top)
                                    isOnGround = true;

                                // Ignore platforms, unless we are on the ground.
                                if (collision == TileCollision.Impassable || IsOnGround)
                                {
                                    // Resolve the collision along the Y axis.
                                    Position = new Vector2(Position.X, Position.Y + depth.Y);

                                    // Perform further collisions with the new bounds.
                                    bounds = BoundingRectangle;
                                }
                            }
                            else if (collision == TileCollision.Impassable) // Ignore platforms.
                            {
                                // Resolve the collision along the X axis.
                                Position = new Vector2(Position.X + depth.X, Position.Y);

                                // Perform further collisions with the new bounds.
                                bounds = BoundingRectangle;
                            }
                        }
                    }
                }
            }

            // Save the new bounds bottom.
            previousBottom = bounds.Bottom;
        }
share|improve this question
3  
Why the minus 1, ppl? The question is valid for me. But here's a short answer: The platformer demo that comes with XNA is just an example, anyway. Not to be followed strictly as a model for your games. It is to show you that a game CAN be done. You shouldn't bother if it's implementation isn't the best at all. –  Gustavo Maciel Mar 6 '12 at 2:35
    
Thanks, I just assumed with the example that what they had done was the best way to do and that I was missing something. Thanks for clearing it up for me. –  PriestVallon Mar 6 '12 at 2:42

1 Answer 1

up vote 11 down vote accepted

You are absolutely right. I've had my share of problems with the collision routines on the XNA platformer sample. But I've managed to start from the code as provided in the sample, and modified it a bit until I achieved consistent results in every test scenario I could throw at it.

In particular, the sort of problem I was having was when trying to slide along a wall by moving diagonally against it. Because of the assumption the sample makes in order to resolve collisions based on the smallest axis of displacement, this resulted in the character not being able to move when pushing against a wall in some direction. For instance, using one sign, I would get stuck when hugging the ceiling and trying to move against it from left to right (can't remember the specifics). Switching the sign would solve that situation but a problem would appear in the opposite scenario. Bottom line is that with the provided implementation I couldn't get it to work correctly in all sides and from every direction - it would always fail on at least one case.

So the core of the changes I did were all about starting to handle movement on the X axis independently from movement on the Y axis, on two separate steps. I've written about it before in this answer so head there for the details.

And if I remember correctly, the actual reason for it was something like this:

enter image description here

share|improve this answer
1  
David always pwning on XNA! –  Gustavo Maciel Mar 6 '12 at 3:15
1  
@Gustavo-Gtoknu I kinda felt it still needed a drawing of the problem :P –  David Gouveia Mar 6 '12 at 3:24
1  
This answer seriously made my day. Thank you. –  Brett Chalupa Mar 28 '12 at 20:59
1  
Just came across this answer - great work! Thanks David. –  Austin Brunkhorst Jan 16 '13 at 5:38

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.