I've played around and ended up with a nice solution, but I ain't feelin good about that coz I've always been thinking that I'd only done a hack just to get the desired behavior.
The code below says that the rect should clamp to the wall's bounds if any collision happened.
// Where...
// Rect A: Moving body
// Rect B: Static body
bool checkCollision(const sf::RectangleShape& rectA,
const sf::RectangleShape& rectB)
{
return rectB.getGlobalBounds().intersects(rectA.getGlobalBounds());
}
......
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))
{
rect.move(0.f, -rectVel * deltaTime.asSeconds());
if (checkCollision(rect, wall))
rect.setPosition(rect.getPosition().x, wall.getPosition().y + wall.getSize().y);
}
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::S))
{
rect.move(0.f, rectVel * deltaTime.asSeconds());
if (checkCollision(rect, wall))
rect.setPosition(rect.getPosition().x, wall.getPosition().y - rect.getSize().y);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A))
{
rect.move(-rectVel * deltaTime.asSeconds(), 0.f);
if (checkCollision(rect, wall))
rect.setPosition(wall.getPosition().x + wall.getSize().x, rect.getPosition().y);
}
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::D))
{
rect.move(rectVel * deltaTime.asSeconds(), 0.f);
if (checkCollision(rect, wall))
rect.setPosition(wall.getPosition().x - rect.getSize().x, rect.getPosition().y);
}
The multiple wall version
enum class Direction
{
Up, Down, Left, Right
};
void clampBody(sf::RectangleShape& rectA,
const sf::RectangleShape& rectB,
Direction dir);
// Where...
// Rect A: Moving body
// Rect B: Static body
void checkCollision(sf::RectangleShape& rectA,
const sf::RectangleShape& rectB,
Direction dir)
{
if (rectB.getGlobalBounds().intersects(rectA.getGlobalBounds()))
clampBody(rectA, rectB, dir);
}
void checkCollision(sf::RectangleShape& rectA,
const std::vector<sf::RectangleShape>& rects,
Direction dir)
{
for (const sf::RectangleShape& rect : rects)
if (rect.getGlobalBounds().intersects(rectA.getGlobalBounds()))
clampBody(rectA, rect, dir);
}
// Also where...
// Rect A: Moving body
// Rect B: Static body
void clampBody(sf::RectangleShape& rectA,
const sf::RectangleShape& rectB,
Direction dir)
{
switch (dir)
{
case Direction::Up:
// Snap to the bottom of rectB
rectA.setPosition(rectA.getPosition().x, rectB.getPosition().y + rectB.getSize().y);
break;
case Direction::Down:
// Snap to the top of rectB
rectA.setPosition(rectA.getPosition().x, rectB.getPosition().y - rectA.getSize().y);
break;
case Direction::Left:
// Snap to the right side of rectB
rectA.setPosition(rectB.getPosition().x + rectB.getSize().x, rectA.getPosition().y);
break;
case Direction::Right:
// Snap to the left side if rectB
rectA.setPosition(rectB.getPosition().x - rectA.getSize().x, rectA.getPosition().y);
break;
}
}
...............
if (sf::Keyboard::isKeyPressed(sf::Keyboard::W))
{
rect.move(0.f, -rectVel * deltaTime.asSeconds());
checkCollision(rect, walls, Direction::Up);
}
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::S))
{
rect.move(0.f, rectVel * deltaTime.asSeconds());
checkCollision(rect, walls, Direction::Down);
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::A))
{
rect.move(-rectVel * deltaTime.asSeconds(), 0.f);
checkCollision(rect, walls, Direction::Left);
}
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::D))
{
rect.move(rectVel * deltaTime.asSeconds(), 0.f);
checkCollision(rect, walls, Direction::Right);
}
I think there might be a better solution than mine.