Skip to main content
replaced http://gamedev.stackexchange.com/ with https://gamedev.stackexchange.com/
Source Link

The first problem where the collisions were handled wrong, were solved with thisthis solution posted by David. Instead of solving the two axis at the same time, the solution solves each axis individually. So, instead of sum the velocity at the position and handle the collisions, I sum each velocity and handle the direction:

The first problem where the collisions were handled wrong, were solved with this solution posted by David. Instead of solving the two axis at the same time, the solution solves each axis individually. So, instead of sum the velocity at the position and handle the collisions, I sum each velocity and handle the direction:

The first problem where the collisions were handled wrong, were solved with this solution posted by David. Instead of solving the two axis at the same time, the solution solves each axis individually. So, instead of sum the velocity at the position and handle the collisions, I sum each velocity and handle the direction:

added 1676 characters in body
Source Link

Before the end of the method, I set previousBottom = playerBounds.Bottom;, to prepare for the next update loop. The full method:

private void HandleCollisions(Direction direction)
{
    Rectangle playerBounds = BoundingRectangle;
    int leftTile = playerBounds.Left / (int)GameMap.Instance.TileSize.X;
    int topTile = playerBounds.Top / (int)GameMap.Instance.TileSize.Y;
    int rightTile = (int)Math.Ceiling((float)playerBounds.Right / GameMap.Instance.TileSize.X) - 1;
    int bottomTile = (int)Math.Ceiling(((float)playerBounds.Bottom / GameMap.Instance.TileSize.Y)) - 1;

    _isOnGround = false;

    for (int y = topTile; y <= bottomTile; ++y)
    {
        for (int x = leftTile; x <= rightTile; ++x)
        {
            Vector2 depth;
            Rectangle tileBounds = GameMap.Instance.GetTileBounds(x, y);
            GameMap.TileCollision collision = GameMap.Instance.GetCollision(x, y);

            if (collision != GameMap.TileCollision.Passable && GameMap.Instance.TileIntersectsPlayer(playerBounds, GameMap.Instance.GetTileBounds(x, y), direction, out depth))
            {
                if (collision == GameMap.TileCollision.Platform && direction == Direction.Vertical && previousBottom <= tileBounds.Top)
                {
                    _isOnGround = true;
                }

                if (collision == GameMap.TileCollision.Block || (direction == Direction.Vertical && _isOnGround))
                {
                    Position += depth;
                    playerBounds = BoundingRectangle;
                }
            }
        }
    }

    previousBottom = playerBounds.Bottom;
}

Before the end of the method, I set previousBottom = playerBounds.Bottom;, to prepare for the next update loop.

Before the end of the method, I set previousBottom = playerBounds.Bottom;, to prepare for the next update loop. The full method:

private void HandleCollisions(Direction direction)
{
    Rectangle playerBounds = BoundingRectangle;
    int leftTile = playerBounds.Left / (int)GameMap.Instance.TileSize.X;
    int topTile = playerBounds.Top / (int)GameMap.Instance.TileSize.Y;
    int rightTile = (int)Math.Ceiling((float)playerBounds.Right / GameMap.Instance.TileSize.X) - 1;
    int bottomTile = (int)Math.Ceiling(((float)playerBounds.Bottom / GameMap.Instance.TileSize.Y)) - 1;

    _isOnGround = false;

    for (int y = topTile; y <= bottomTile; ++y)
    {
        for (int x = leftTile; x <= rightTile; ++x)
        {
            Vector2 depth;
            Rectangle tileBounds = GameMap.Instance.GetTileBounds(x, y);
            GameMap.TileCollision collision = GameMap.Instance.GetCollision(x, y);

            if (collision != GameMap.TileCollision.Passable && GameMap.Instance.TileIntersectsPlayer(playerBounds, GameMap.Instance.GetTileBounds(x, y), direction, out depth))
            {
                if (collision == GameMap.TileCollision.Platform && direction == Direction.Vertical && previousBottom <= tileBounds.Top)
                {
                    _isOnGround = true;
                }

                if (collision == GameMap.TileCollision.Block || (direction == Direction.Vertical && _isOnGround))
                {
                    Position += depth;
                    playerBounds = BoundingRectangle;
                }
            }
        }
    }

    previousBottom = playerBounds.Bottom;
}
Source Link

The first problem where the collisions were handled wrong, were solved with this solution posted by David. Instead of solving the two axis at the same time, the solution solves each axis individually. So, instead of sum the velocity at the position and handle the collisions, I sum each velocity and handle the direction:

if (_velocity.Y != 0f)
{
    Position += _velocity.Y * Vector2.UnitY * elapsed;
    Position = new Vector2(Position.X, (float)Math.Round(Position.Y));
    HandleCollisions(Direction.Vertical);
}

if (_velocity.X != 0f)
{
    Position += _velocity.X * Vector2.UnitX * elapsed;
    Position = new Vector2((float)Math.Round(Position.X), Position.Y);
    HandleCollisions(Direction.Horizontal);
}

To solve the second problem, I need manage a way to make the one-way platformers (the ones where you can jump from bottom but stop if falls from top). To resolve this, I made just like the XNA Platformer Demo. On the begin of HandleCollisions(), I reseted the _isOnGround variable to false, so at the beggin of verification the player is not on the ground.

If the tile collision that is being verified through the loop is not passable and the player is intersecting it, verify if the tile collision is a Platform, if the movement is vertical (because the one-way platforms ignores the x axis), and if the previous bottom of the player is less or equal of the tile top:

if (collision == TileCollision.Platform && direction == Direction.Vertical && previousBottom <= tileBounds.Top)
{
    _isOnGround = true;
}

If so, the player is on the ground, setting _isOnGround to true. After that, I check if the tile collision is a block, if is, the player needs be pushed out from the tile, but I also verify if the player is on the ground, that means he landed on a platform, so he also need be pushed out.

if (collision == TileCollision.Block || (direction == Direction.Vertical && _isOnGround))
{
    Position += depth;
    playerBounds = BoundingRectangle;
}

Before the end of the method, I set previousBottom = playerBounds.Bottom;, to prepare for the next update loop.