Collision has major problems

Ah, no worries, I get you.

Yes, that would work for horizontal collisions. It’s slightly inefficient since you’re testing three tiles when you only need to test two, but that won’t affect the gameplay result.

So to raise the efficiency to only test the two needed, what should I do?

For an efficient solution, you have two options:

  1. Detect if the center point is closer to the left or right of the tile it’s in, then examine the tile on the opposite side. This is what reiti.net was suggesting above.

image

(EDIT) In math terms:

centerX = (X+Width/2)
centerTile = (int)(centerX/64)
if(centerX/64 - centerTile <= 0.5)
    leftTile = centerTile - 1
else
    rightTile = centerTile + 1
  1. Instead of testing tiles relative to the players center point, test them relative to the left and right bounds of the player. This is essentially what my example code above does, although it tests all the bounds and not just the left and right.

image

(EDIT) In math terms:

leftX = X;
rightX = X+Width;
leftTile = (int)(leftX/64)
rightTile = (int)(rightX/64)

I used your code (it was allowed as long as you were credited for it, which I did.)
It immediately threw an error for looking for a tile outside the tilemap (it was trying to look for a tile with y < 0)
I pasted it exactly as used here and made sure to check that my top part was correct for what was happening in the collision method, which it was. Any pointers??

Yeah, I did mention the code was untested. You’re right, it’ll look for tiles outside of the tilemap when your player’s bounds are on the borders.

Luckily, it should be an easy fix. Just clamp the tiles minTile and maxTile coordinates to allowable values.

            [snip]
            int maxTileCoodY = (int)((bounds.Y + bounds.Width) / tileGridHeight);

            minTileCoodX = MathHelper.Max(minTileCoodX, 0);
            maxTileCoodX = MathHelper.Min(maxTileCoodX, tileGridWidth-1);
            minTileCoodY = MathHelper.Max(minTileCoodY, 0);
            maxTileCoodY = MathHelper.Min(maxTileCoodY, tileGridHeight-1);

            //Loop through all the tiles between the Rectangle's minimum and
            [snip]

Can’t promise there won’t be other issues, though. I’d highly recommend trying to understand what it’s actually doing in there so you can debug it yourself.

The strange thing is that my player was never on the borders. I specifically made a second map on the tilemap to keep them away from the borders. Why would it still try to look at tiles outside the map if it’s nowhere near the borders?

After setting some breakpoints, the program runs everything perfectly as long as the player doesn’t move. But the moment I pressed a key, the bounds value jumped to a value outside of the tilemap for some bizzare reason. I am not editing the value of the rectangle that is the input bounds, so why would this happen?

Hard to say what the solution is without seeing the whole context. All I can do is analyze the problem based on the symptoms you described:

  1. FuturePlayerBounds” is getting some extreme value it shouldn’t.
  2. FuturePlayerBounds” is a combination of player.Size and player.Position + Fool.PlayerVelocity; which…

[facepalm] Okay, that’s wrong. I thought I’d removed the “Fool” object from this code. that should be player.Position + player.Velocity, which is the value I’m setting above that.

My bad there. This is why we test.

Let’s be safe and assume that doesn’t fix it. That means one of those three variables, (Position, Velocity or Size) is something extreme. Your breakpoint can probably show you which.

Usually, an error like this would immediately have me questioning my co-ordinate systems. If I’m testing in screen space (0-1,0-1) but my Position is in pixels (0-1920,0-1080), the bounds will be well outside of the test space. In this case, though, everything should be in pixels.

Alternatively, I might look for a cumulative error. If we weren’t resetting player.Velocity to zero every frame, it would increase rapidly as you added 8 to it every frame (8-16-24-32) and your character would very quickly accelerate off the screen.

When tested the player never even moved. And despite this, pressing the D key to move right set the x tile to 104, which is outside my 100x100 tilemap

TileX 104 means that player.Position + player.Velocity + player.Size adds up to something greater than 6656 (104*64). One of those three variables is a value it should not be.

As I noted above, the code I provided was accidentally still referencing your original Fool.PlayerVelocity variable instead of player.Velocity. Maybe that was the problem?

Fool is the player, though. And I made sure to always reset the velocity because I originally had a big problem with the Fool accelerating when it shouldn’t, too. So there’s no way that Fool.PlayerVelocity could cause such effects. Size hasn’t changed whatsoever during the use of the program, the player is always 64x128 pixels, or 1x2 tiles. Position also gets reset every time, so that couldn’t cause the adverse effects observed either.