1
\$\begingroup\$

I have implemented a simple rectangle based collsion detection where you can "slide" around the edges on diagonal movement. Works fine but the thing is, it is somehow possible that e.g. the player (rectangle) glitches into the one of a collision object. It seems, that it appears only when the player "slides" around the corners. I suspect that if the player walks around the corners that the movement direction (Vector2) cuts off the corner and at some point glitches into the collision rectangle.

I hope I've explained the problem somehow understandable?

The code looks like this:

The UpdateCall recieves the playerMovement from the keyboard input

public void UpdatePlayer(GameTime gameTime, Vector2 playerMovement)
{
    //...
    playerMovement = CalculatePlayerMovement(Vector2.Normalize(playerMovement) * movementspeed);
    if (playerMovement.Length() != 0)
        MoveBy(playerMovement);
    //...
}

The CalculatePlayerMovement-Method checks world bounds, collision objects and so on. Depending on what side the collsion happens, the x- or y-movement will be zeroed.

private Vector2 CalculatePlayerMovement(Vector2 movement)
{
    Rectangle destRect = new Rectangle(BoundingBox.X + (int)movement.X, BoundingBox.Y + (int)movement.Y, Width, Height);
    Vector2 returnValue = movement;
    //...
    foreach (Rectangle r in TileMap.collisionObjects)
    {
         if (destRect.Intersects(r))
         {
             string collsionSide = GetCollisionSide(destRect, r);
             if (collsionSide == "top" || collsionSide == "bottom")
                 returnValue.Y = 0;
             if (collsionSide == "left" || collsionSide == "right")
                 returnValue.X = 0;
         }
     }
    //...
}

Finally the check itself. I took this part from HERE since I was not sure what the best way would be.

private string GetCollisionSide(Rectangle destRect, Rectangle r)
{
    float w = (destRect.Width + r.Width) / 2;
    float h = (destRect.Height + r.Height) / 2;
    float dx = destRect.Center.X - r.Center.X;
    float dy = destRect.Center.Y - r.Center.Y;

    if (Math.Abs(dx) <= w && Math.Abs(dy) <= h)
    {
        float wy = w * dy;
        float hx = h * dx;

        if (wy > hx)
        {
           if (wy > -hx)
                return "top";
            else
                return "right";
        }
        else if (wy < hx)
        {
            if (wy > -hx)
                return "left";
            else
                return "bottom";
        }
    }
    return "";
}

I am not sure where the problem is, but it is probably something I don't see myself.

\$\endgroup\$
1
\$\begingroup\$

I believe you should consider these 2 cases separately:

1 - The objects are colliding and are moving towards each other.

2 - The objects are colliding and are moving away from each other.

In the second case, you should not restrict the movement. You can still apply a position correction, in order to eliminate the overlapping. But you should allow velocity.

| improve this answer | |
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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