jr999
jr999

Reputation: 13

2d tilemap collision for SFML

I am currently working on a 2D rpg game with SFML and I am trying to make the player collide with certain tiles. I have gotten to the point where the player can collide with the tiles that I want as well as slide along a wall with the following code:

sf::Vector2f movement(0.f, 0.f);
if (isMovingUp)
    movement.y -= 1.f;
if (isMovingDown)
    movement.y += 1.f;
if (isMovingLeft)
    movement.x -= 1.f;
if (isMovingRight)
    movement.x += 1.f;

sf::Vector2f oldpos = Player.getPosition();
sf::Vector2f newpos = Player.getPosition() + movement*speed*dt.asSeconds();
Player.setPosition(newpos); // the player is an sf::sprite that is 16*24px

for (int i = 0; i < tiler.solids.size(); i++) // each solid is an sf::FloatRect that is 16*16px
{
    if (Player.getPosition().x + 16 >= tiler.solids[i].left && Player.getPosition().x <= tiler.solids[i].left + tiler.solids[i].width && Player.getPosition().y + 24 >= tiler.solids[i].top && Player.getPosition().y <= tiler.solids[i].top + tiler.solids[i].height) // if the player is touching the tile
    {
        Player.setPosition(oldpos);
    }
}

What it basically does is iterate over every solid and test if the player is intersecting any of them. If there is an intersection, the player will return to their previous position when there was no collision.

The main problem that I have is that when I press two directions at once (for example colliding with a wall to the right while moving right and up) the player gets stuck because it is resetting both the x and y coordinates. Most of the code is based off of This question. The person who asked the question had the same problem. The last comment to an answer suggested that they try separating the vertical from the horizontal movement. I tried that in my code but that didn't work because it then it was basically testing if there was x-collision OR y-collision and would reset the player's position even if the player was in line with a solid.

So I guess my main question is: How can I separate the vertical from the horizontal collision in a better way OR Is there another way of doing tile collisions that allows the player to slide along a wall while holding two directions?

Upvotes: 1

Views: 1175

Answers (1)

Paul
Paul

Reputation: 158

What you want to do is test the collision on both axis seperately. That means you safe the current position of the player and then calculate two bounding boxes. One of which is the players's bounding box with the horizontal offset added and one with the vertical offset added.

sf::FloatRect oldBounds = Player.getPosition();

sf::FloatRect newBoundsH = (oldBounds.left + movement.x *speed*dt.asSeconds(), oldBounds.top, oldBounds.width, oldBounds.height);

sf::FloatRect newBoundsV = (oldBounds.left, oldBounds.top + movement.y *speed*dt.asSeconds(), oldBounds.width, oldBounds.height);

So you can write:

    // Test horizontal collision.
    if(tiler.intersects(newBoundsH)){
        Player.setPosition(oldpos.x, Player.getPositions().y);
    }

// Test vertical collision.
    if(tiler.intersects(newBoundsV)){
        Player.setPosition(Player.getPositions().x, oldpos.y);
    }

This method absolutely has its flaws but I think it is easy to understand.

Upvotes: 1

Related Questions