Character jittering with this tile based collision code

I have been trying to get my collision code working for hours now but with every resource I have tried my character still jitters. First I tried using the platformer sample but my character still jittered up and down really quickly, even when standing still. Then I took to these forums and found this post and I used his code and eventually found out that in order for his to work you have to:

1. Move the character's position along the x-axis only.
2. Check if the character collided with something along the x-axis

Then do the same thing for the y axis. In other words, the character could only move one direction at a time and with my game there are a lot of different forces, velocities, accelerations, et cetera. all pulling on the target at once and this kind of solution didn't really work.

I heavily simplified the code in the sample and ended up with this:

``````Rectangle playerBounds = GetPlayerBounds(motion.Position.X, motion.Position.Y, characterWidth, characterHeight);

// Get the player's bounding rectangle and find neighboring tiles.
Rectangle bounds = playerBounds;
int leftTile = (int)Math.Floor((float)bounds.Left / TileSize);
int rightTile = (int)Math.Ceiling(((float)bounds.Right / TileSize)) - 1;
int topTile = (int)Math.Floor((float)bounds.Top / TileSize);
int bottomTile = (int)Math.Ceiling(((float)bounds.Bottom / TileSize)) - 1;

for (int y = topTile; y <= bottomTile; ++y) // For each potentially colliding tile,
{
for (int x = leftTile; x <= rightTile; ++x)
{
Tile collision = stage.CustomLayer.GetTile(x, y);

if (collision.Value == Tile.CollisionTile)
{
Vector2 depth = Extensions.GetIntersectionDepth(bounds, collision.Bounds); // Determine collision depth (with direction) and magnitude.

if (depth != Vector2.Zero)
{
if (Math.Abs(depth.Y) < Math.Abs(depth.X)) // Resolve the collision along the shallow axis.
{
motion.Position = new Vector2(motion.Position.X, motion.Position.Y + depth.Y); // Resolve the collision along the Y axis.
}
else // Ignore platforms.
{
motion.Position = new Vector2(motion.Position.X + depth.X, motion.Position.Y); // Resolve the collision along the X axis.
}

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

The code produces the jittering effect as well. I have debugged it for hours and I think I found the cause but I do not know how to fix it.

For example, if the character's `Y position is 500` and is found to be colliding with a tile with a depth of `5 pixels`, he will be pushed to `Y position 495`. At this time, though, the loop will continue based off of old `topTile and bottomTile` values and he may still be found to be colliding with those tiles, and will be pushed up to `Y position of 490`. Next time this function is called though when the character has moved back down to `Y position of 495` due to gravity, he won't be colliding because of different initial `topTile and bottomTile` values and will continue moving downwards.

I believe this is what causes the jittering effect but I do not understand why it is happening to me. As far as I know, I am using the same algorithm as everyone else and their code doesn't produce any jittering. All my tiles are of equal size (32x32) and I am using the same `GetIntersectionDepth` method found in the platformer sample.

Thanks to anyone who can help me solve this problem.

-
Switching `bounds = playerBounds;` to `bounds = GetPlayerBounds(motion.Position.X, motion.Position.Y, characterWidth, characterHeight);` solved the problem. Thank you. – Frank Scott Mar 13 '12 at 19:55
That's good. I'll copy the comments to the answer section and delete them. – David Gouveia Mar 13 '12 at 19:57
Also, I am still interested in your solution. I see the disadvantages of the one I have posted now. However, I have performance concerns with your solution. Wouldn't the checking collision method have to be called twice for all objects in the game? Seems like that could be an issue. – Frank Scott Mar 13 '12 at 19:57
Indeed it's slower, but unfortunately I have yet to find another way to handle tile based collisions that doesn't start giving problems in some cases. I'd be happy to learn about a more proper solution! But it has to work in every direction and against every wall - think oldschool Zelda type of collision, not platformer. – David Gouveia Mar 13 '12 at 20:05
Hmm, alright. Well I definitely prefer a proper working solution that's somewhat slower to one that is buggy and faster! I'm going to go and try your solution once more. I doubt collision testing is really going to be the bottleneck regardless. Thanks for all your help. – Frank Scott Mar 13 '12 at 20:11

As for the jittering problem, I remember I had it too and the solution for me was by doing `Math.Round` on the player position after applying velocity (I did it before handling collisions, but I'm not sure if order matters). You can see that on my example, line 66, and if I remember correctly it was also present in the original sample in the `Update` method or something. From your code snippet I can't see if you're already doing it or not, but I recommend it to prevent jittering at certain speeds.
Other than that suggestion, there's something wrong with your code. In particular, since `Rectangle` is a value type, not a reference type, when you do `bounds=playerBounds` after moving the player, you're not really pointing to the new bounds of the player. It's still the old value. You need to call `GetPlayerBounds()` again to recalculate the new bounds for the player.