I have been trying out code samples on Windows Phone. The platformer game sample moves a player left and right by tilting the phone in the direction to travel. The sample code as published on 10/4/2011 has a problem where the player gets stuck when you tilt to move left until you tilt a lot and he flys over left. This happens because the collision code detects a collision with the ground tile at low speeds. Here is my update for the HandleCollisions() method which avoids the problem.
/// <summary> /// Detects and resolves all collisions between the player and his neighboring /// tiles. When a collision is detected, the player is pushed away along one /// axis to prevent overlapping. There is some special logic for the Y axis to /// handle platforms which behave differently depending on direction of movement. /// </summary> private void HandleCollisions() { // Get the player's bounding rectangle and find neighboring tiles. Rectangle bounds = BoundingRectangle; int leftTile = (int)Math.Floor((float)bounds.Left / Tile.Width); int rightTile = (int)Math.Ceiling(((float)bounds.Right / Tile.Width)) - 1; int topTile = (int)Math.Floor((float)bounds.Top / Tile.Height); int bottomTile = (int)Math.Ceiling(((float)bounds.Bottom / Tile.Height)) - 1; // Reset flag to search for ground collision. isOnGround = false; // For each potentially colliding tile, for (int y = topTile; y <= bottomTile; ++y) { // // The y loop checks all tile rows that the player intersects with from top to bottom. The x loop checks // each tile that the player intersects with on that row depending on the players direction of travel. // The collision tests are required to go in the direction of travel so as to avoid detecting collisions // with the platform that the player is running on in the horizontal direction. Instead a ground // collision will be detected and corrected first in the vertical direction and since the player position // is moved back up and is no longer in line with the platform when the horizontal collision check occurs. // This direction of travel identification is only required because the collision correction assumes that // the axis to bounce the player back is the axis with the smallest overlap. This isn't always 100% true. // if (velocity.X < 0) for (int x = rightTile; x >= leftTile; --x) HandleTileCollisions(ref bounds, x, y); else for (int x = leftTile; x <= rightTile; ++x) HandleTileCollisions(ref bounds, x, y); } // Save the new bounds bottom. previousBottom = bounds.Bottom; } /// <summary> /// Calcualtes and corrects collisions of the player position with items on the level map. This method identifies the depth of the /// collision in the x and y axis and moves the player position back to a location that would not overlap with the object it /// collided with. It does this in the axis with the smallest collision as a guess as to the direction the player should bounce /// off the object being collided with. This method does a nice job of having common code for collisions regardless of the /// direction of travel on the axis as one way is +ve and the other is -ve. /// </summary> /// <param name="bounds">the bounding rectabgle in pixels for the player sprite as calculated by the GetBoundingRectangle property</param> /// <param name="x">the x location of the tile on the map in the range 0 - 19</param> /// <param name="y">the y location of the tile on the map in the range 0 - 14</param> void HandleTileCollisions(ref Rectangle bounds, int x, int y) { // put the code in here from within the for loop in the original HandleCollisions() method }
/// <summary> /// Detects and resolves all collisions between the player and his neighboring /// tiles. When a collision is detected, the player is pushed away along one /// axis to prevent overlapping. There is some special logic for the Y axis to /// handle platforms which behave differently depending on direction of movement. /// </summary> private void HandleCollisions() { // Get the player's bounding rectangle and find neighboring tiles. Rectangle bounds = BoundingRectangle; int leftTile = (int)Math.Floor((float)bounds.Left / Tile.Width); int rightTile = (int)Math.Ceiling(((float)bounds.Right / Tile.Width)) - 1; int topTile = (int)Math.Floor((float)bounds.Top / Tile.Height); int bottomTile = (int)Math.Ceiling(((float)bounds.Bottom / Tile.Height)) - 1; // Reset flag to search for ground collision. isOnGround = false; // For each potentially colliding tile, for (int y = topTile; y <= bottomTile; ++y) { // // The y loop checks all tile rows that the player intersects with from top to bottom. The x loop checks // each tile that the player intersects with on that row depending on the players direction of travel. // The collision tests are required to go in the direction of travel so as to avoid detecting collisions // with the platform that the player is running on in the horizontal direction. Instead a ground // collision will be detected and corrected first in the vertical direction and since the player position // is moved back up and is no longer in line with the platform when the horizontal collision check occurs. // This direction of travel identification is only required because the collision correction assumes that // the axis to bounce the player back is the axis with the smallest overlap. This isn't always 100% true. // if (velocity.X < 0) for (int x = rightTile; x >= leftTile; --x) HandleTileCollisions(ref bounds, x, y); else for (int x = leftTile; x <= rightTile; ++x) HandleTileCollisions(ref bounds, x, y); } // Save the new bounds bottom. previousBottom = bounds.Bottom; } /// <summary> /// Calcualtes and corrects collisions of the player position with items on the level map. This method identifies the depth of the /// collision in the x and y axis and moves the player position back to a location that would not overlap with the object it /// collided with. It does this in the axis with the smallest collision as a guess as to the direction the player should bounce /// off the object being collided with. This method does a nice job of having common code for collisions regardless of the /// direction of travel on the axis as one way is +ve and the other is -ve. /// </summary> /// <param name="bounds">the bounding rectabgle in pixels for the player sprite as calculated by the GetBoundingRectangle property</param> /// <param name="x">the x location of the tile on the map in the range 0 - 19</param> /// <param name="y">the y location of the tile on the map in the range 0 - 14</param> void HandleTileCollisions(ref Rectangle bounds, int x, int y) {
// put the code in here from within the for loop in the original HandleCollisions() method
}