1
\$\begingroup\$

I have difficulties with the rectangle collision. My character can go through the right side and through the bottom of each platform rectangle. I guess their is a mathematical problem with the collision, but I don't know what is wrong.

What should I change? I want to do a little platformer, something like the old Mario games.

Backgrounds.LevelTilesList is a list of type RectangleF. Every tile in the level is saved in this list.

Vector2 Player_Gravity = new Vector2(0, 4.5f);
Vector2 Player_Movement = new Vector2();
Vector2 Player_Size = new Vector2(29, 80);
System.Drawing.RectangleF Player_RectF = new System.Drawing.RectangleF(100, 100, 29, 80);
System.Drawing.RectangleF Player_NewRect;
bool collisionTop, collisionBottom, collisionRight, collisionLeft;


    protected override void Update(GameTime gameTime)
    {
        KeyboardState currentkeyState = Keyboard.GetState();

        if (currentkeyState.IsKeyDown(Keys.Left))
            Player_Movement.X -= 5;
        if (currentkeyState.IsKeyDown(Keys.Right))
            Player_Movement.X += 5;
        if (currentkeyState.IsKeyDown(Keys.Up))
            Player_Movement.Y -= 10;
        if (currentkeyState.IsKeyDown(Keys.Down))
            Player_Movement.Y += 10;

        Player_Movement += Player_Gravity;
        // Calculate new position
        Player_NewRect = Player_RectF;
        Player_NewRect.X += Player_Movement.X;
        Player_NewRect.Y += Player_Movement.Y;

        // check for collision
        for (int j = 0; j <= Backgrounds.LevelTilesList.Count - 1; j++)
        {
            if (Player_NewRect.IntersectsWith(Backgrounds.LevelTilesList[j]))
            {
                float halfBoxWidth = Backgrounds.LevelTilesList[j].Width * 0.5f;
                float halfBoxHeight = Backgrounds.LevelTilesList[j].Height * 0.5f;
                float halfBoxPlayerWidth = Player_NewRect.Width * 0.5f;
                float halfBoxPlayerHeight = Player_NewRect.Height * 0.5f;

                Vector2 posDiff = new Vector2((int)((Backgrounds.LevelTilesList[j].X + halfBoxWidth) - (Player_NewRect.X + halfBoxPlayerWidth)), (int)((Backgrounds.LevelTilesList[j].Y + halfBoxHeight) - (Player_NewRect.Y + halfBoxPlayerHeight)));
                float maxDiffX = halfBoxWidth + halfBoxPlayerWidth;
                float maxDiffY = halfBoxHeight + halfBoxPlayerHeight;

                collisionTop = posDiff.Y < -halfBoxHeight &&
                                        posDiff.Y > (maxDiffY) * -1
                                        &&
                                        !collisionRight && !collisionLeft;

                collisionBottom = posDiff.Y > halfBoxHeight &&
                                        posDiff.Y < maxDiffY
                                        &&
                                        !collisionRight && !collisionLeft;

                collisionLeft = posDiff.X < -halfBoxWidth &&
                                    posDiff.X > maxDiffX * -1 &&
                                    !collisionBottom && !collisionTop;

                collisionRight = posDiff.X > halfBoxWidth &&
                                        posDiff.X < maxDiffX &&
                                        !collisionBottom && !collisionTop;

                if (collisionTop || collisionBottom)
                    Player_Movement.Y *= -0.5f;
                if (collisionLeft || collisionRight)
                    Player_Movement.X *= -0.5f;


                // Adjust the position
                if (collisionBottom)
                {
                    Player_NewRect.Y -= Player_NewRect.Bottom - Backgrounds.LevelTilesList[j].Top;
                }

                if (collisionTop)
                {
                    Player_NewRect.Y += Player_NewRect.Top - Backgrounds.LevelTilesList[j].Bottom;
                }

                if (collisionLeft)
                {
                    Player_NewRect.X += Player_NewRect.Left - Backgrounds.LevelTilesList[j].Right;
                }

                if (collisionRight)
                {
                    Player_NewRect.X -= Player_NewRect.Right - Backgrounds.LevelTilesList[j].Left;
                }
            }
        }

        Player_RectF = Player_NewRect;
        Player_Movement = new Vector2(0, 0);  
        base.Update(gameTime);
    }
\$\endgroup\$
2
1
\$\begingroup\$

Just to be clear: Per the convention of System.Drawing.RectangleF, rect.Top is a smaller value than rect.Bottom and so "up" is negative y.

Let's consider the case where the intersecting tile's center is above new player rect's center:

posDiff.y is negative.

collisionTop is true.

new player rect's Top is above tile's Bottom, otherwise there'd be no intersection

So, this expression is negative:

Player_NewRect.Top - Backgrounds.LevelTilesList[j].Bottom

So, this code block moves the player up, further into the tile, which is wrong.

if (collisionTop)
{
    Player_NewRect.Y += Player_NewRect.Top - Backgrounds.LevelTilesList[j].Bottom;
}

So try flipping the sign on that last line of code. Also, step through the code in the debugger to see if everything I described is correct.

\$\endgroup\$

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