Player can pass through wall corners

I’ve been having this problem for quite a while now. Collision seems to be smooth sailing except for this one thing. The player can go into any corner and pass through the wall.

I’ve tried tinkering with some code and I can’t get anything to fix it.

Here’s the source code:

Player.cs

 hitbox = new Rectangle((int)Position.X, (int)Position.Y + (Height / 2), Width, Height / 2); //this rectangle is the bottom half of the player

 if (able) { 
             if (k.IsKeyDown(up) && cantmoveup == false)
        {
            Position.Y += -speed;
        }
        if (k.IsKeyDown(rightt) && cantmoveright == false)
        {
            left = false;
            right = true;
            Position.X += speed;
        }     
        if (k.IsKeyDown(leftt) && cantmoveleft == false)
        {
            right = false;
            left = true;
            Position.X += -speed;
        }
        if (k.IsKeyDown(down) && cantmovedown == false)
        {
            Position.Y += speed;
        }
            if (k.IsKeyDown(Keys.X))
            {
                speed = 8f;
            }
            else
            {
                speed = 4f;
            }
            }

Game1.cs

public void Update(GameTime gameTime){
 foreach (Wall wall in Walls)
            {
                if (player.hitbox.isOnLeft(wall.hitbox))
                {
                    player.cantmoveright = true;
                    break;
                }else
                {
                    player.cantmoveright = false;
                }
                if (player.hitbox.TouchRightOf(wall.hitbox))
                {
                    player.cantmoveleft = true;
                    break;
                }
                else
                {
                    player.cantmoveleft = false;
                }
                if (player.hitbox.isOnBottom(wall.hitbox))
                {
                    player.cantmoveup = true;
                    break;
                }
                else
                {
                    player.cantmoveup = false;
                }
                if (player.hitbox.isOnTop(wall.hitbox))
                {
                    player.cantmovedown = true;
                    break;
                }
                else
                {
                    player.cantmovedown = false;
                }
            }
          }

public static class HamburgerHelper

{
const int penetrationMargin = 5;
public static bool isOnTop(this Rectangle r1, Rectangle r2)
{
return (r1.Bottom >= r2.Top - penetrationMargin &&
r1.Bottom <= r2.Top + (r2.Height / 2) &&
r1.Right >= r2.Left + 5 &&
r1.Left <= r2.Right - 5);
}
public static bool isOnLeft(this Rectangle r1, Rectangle r2)
{
return (r1.Right >= r2.Left - penetrationMargin &&
r1.Right <= r2.Left + (r2.Width / 2) &&
r1.Top <= r2.Bottom - 5 &&
r1.Bottom >= r2.Top + 5);
}
public static bool TouchRightOf(this Rectangle r1, Rectangle r2)
{
return (r1.Left <= r2.Right + penetrationMargin &&
r1.Left >= r2.Right - (r2.Width / 2) &&
r1.Top <= r2.Bottom - 5 &&
r1.Bottom >= r2.Top + 5);
}
public static bool isOnBottom(this Rectangle r1, Rectangle r2)
{
return (r1.Top <= r2.Bottom + penetrationMargin && r1.Top >= r2.Bottom - (r2.Height / 2) &&
r1.Right >= r2.Left + 5 &&
r1.Left <= r2.Right - 5);
}
public static bool isTouching(this Rectangle r1, Rectangle r2)
{
return (r1.TouchRightOf(r2) || r1.isOnLeft(r2) || r1.isOnBottom(r2) || r1.isOnTop(r2));
}

}

If you could examine it to see what’s causing this, it would be greatly appreciated. Thanks for your time.

I can’t check the code but I can tell you what I’d do. Actually it’s probably better than telling you the error straigth ahead, as you can apply the method in future similar problems.

First, it’s obvious that the problem reside in the “cantmove” variables, because they’re the ones which effectively change the position.

  1. I’d print the values cantmoveup,cantmovedown,cantmoveleft and cantmoveright to the screen to see if there’s an obvious pattern where those values change.

With that, you’d probably see when cantmoveright is not being properly set and maybe deduct where is the reason cantmoveright is wronly set to false. You can (actually, you SHOULD) also check with this the values in other corners or as many weird combinations as possible.

Double check that cantmoveright is wrong in the situation we’re debugging.

  1. If you can’t deduce the problem from the data, let’s use the debugger to check the exact place where cantmoveright should be set to true. And this should be inside the foreach, when checking every wall.

First of all, put (again) the controlled player in a place where cantmoveright must be true. In example, in the middle of the problematic wall. You have to indentify this block somehow. Probably has a position (let’s say 4,1).

You can either put a breakpoint in the first line of the foreach and keep pressing F5 until you reach the offending wall (put it in the watch, press F5 until the checked block position is 4,1). However this won’t work if you have 262144 walls…

So put a condition in the first line of the foreach:

if (wall.pos.X==4 && wall.pos.Y==1)
player=player;

player=player is a dummy instruccion which actually does nothing (you’ll probably get a warning), but you can (and have to) put a breakpoint there. Any “dummy instruction” would work. So, when you press F5, the debugger will be stopped when the offending block is being checked.

Not that you have the debugger right at the place the problem is being originated, it’s just a matter of stepping in and checking while the condition is not being set. At the end I’m sure you’ll find it’s a “>=” that should be a “>” or a crappy reason like this :slight_smile:

(side note: maybe it’s me that I’m growing old or that I’m used to write code easy to understand, but usually booleans with “cant” produce harder code to understand than booleans with “can”. You have to look at the code and think “ok, this is negated” while seeing a “can” you don’t have to think at all. Same with enabled/disabled bools)

(side note 2: when checking block position I’m assuming that values are integers. If values are floats, remember that comparing floats with floats may lead to problems due to rounding errors. The idea is identifying the block where the debugger must break in order to step in through the problematic loop. How you identify that block is up to you.)

When 2 keys are pressed you should also check both directions, for ex up right check isontop and isonright.
One more point is in the istouching() method, you check only one direction which i think is missing the case when touching 2 sides at a time ie: isontop && isonright ||…
It should work the way you did it but further tests can not be a bad thing