I have a side scrolling tile based game, and I am having a bug with the collision detection on tiles. It works for the most part, but there is one bug which I can't figure out how to solve.
When a player moves and hits a wall, if they try to move in the opposite direction, they end up going through the wall.
(http://i.imgur.com/mHk4jml.png)
(http://i.imgur.com/c59U5y1.png)
I am not too sure how to handle it.
Here is the collision detection code:
if(level_One->checkCollision(player1->playerSprite)){
sf::Vector2<float> speed;
speed.y = playerSpeed.y;
if(key == sf::Keyboard::Right){
speed.x = -2.0f;
player1->updatePlayer(speed);
}
else if(key == sf::Keyboard::Left){
speed.x = 2.0f;
player1->updatePlayer(speed);
}
}
bool level::checkCollision(sf::Sprite &playerSprite){
for(int i = 0; i < mapHeight; i++){
for(int j = 0; j < mapWidth; j++){
sf::Rect<float> playerBounds = playerSprite.getGlobalBounds();
playerBounds.height -= 20;
sf::Rect<float> tileBounds = mapSprites[i][j].sprite->getGlobalBounds();
if(playerBounds.intersects(tileBounds) && !mapSprites[i][j].passThrough){
return true;
}
}
}
return false;
}
Any help is appreciated.
I believe I may have solved it.
1) The player moves right until he hits something. The game sets the player's velocity to be the reverse of the direction of movement, away from the tile.
2) This causes you to move a little bit away from the tile, but not far enough away to trigger the collision detection.
3) As long as the user get pressing the Right key, they wouldn't go through the wall but would be continuously put back to the position right before it.
4) If the user decided to press the Left button, the collision detection would still trigger even though there was nothing behind the sprite and the tile causing the issue is the one in front.
5) The player would then move in the opposite direction of the (wrong) obstructing tile, which in this case is towards the actual blocking tile. This bypassing the collision detection.
My solution was to simulate their movements again inside of the collision check
if(level_One->checkCollision(player1->playerSprite)){
//level::Tile tile= level_One->GetTile(player1->playerSprite);
sf::Vector2<float> speed;
speed.y = playerSpeed.y;
if(key == sf::Keyboard::Right){
speed.x = -1.0f;
sf::Sprite temp = player1->playerSprite;
temp.setPosition(player1->getPosition().x - 1.0f, player1->getPosition().y);
if(!level_One->checkCollision(temp)){
player1->updatePlayer(speed);
}
else{
speed.x = 1.0f;
player1->updatePlayer(speed);
}
}
else if(key == sf::Keyboard::Left){
speed.x = 1.0f;
sf::Sprite temp = player1->playerSprite;
temp.setPosition(player1->getPosition().x + 1.0f, player1->getPosition().y);
if(!level_One->checkCollision(temp)){
player1->updatePlayer(speed);
}
else{
speed.x = -1.0f;
player1->updatePlayer(speed);
}
}
else{
player1->updatePlayer(speed);
}
}
This seems to work.
updatePlayer
void Player::updatePlayer(sf::Vector2<float> position){
//Eventually add damage and health modifications here.
//playerSprite.setPosition(position.x, position.y);
playerSprite.move(position.x, position.y);
}