I have been using SFML for about 4 months now. I recently began making a 2D platformer, after finally learning how to make a sprite jump by using AlexanderX's jumping tutorial. I pretty much use the same code AlexanderX used to make the sprite jump. I have no problem with the jumping overall, but there was one nagging issue I encountered that involved the sprite jumping over a block. When I hold down either the left or right key, collide into a block, and jump while still holding down either the left or right key, the moment the sprite goes over the corner of the block, the sprite acts as though it already landed and jumped again. Because this happens, the player looks like it is moving diagonally over a staircase of blocks. To better explain it, the sprite looks as though it never collides with the ground, and looks like it is floating diagonally over a staircase of blocks. I realize this could be a very common problem, but I couldn't find anything online to help solve it.
The code I have here is the code from the tutorial. I'm using this because it is much shorter than my code, and I didn't want to just show a small part, since you can't really see how it is applied. This code still has the same issue that I had in my code, so it will still help identify the problem.
#include <SFML/Graphics.hpp>
#include <vector>
const int gravity = 500;
bool onGround = false;
float inAir;
float maxInAir = 0.3f;
void move(sf::Vector2f &playerVelocity, float dt)
{
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Left))
{
playerVelocity.x = -gravity;
}
else if (sf::Keyboard::isKeyPressed(sf::Keyboard::Right))
{
playerVelocity.x = gravity;
}
else if (playerVelocity.x != 0)
{
playerVelocity.x = 0;
}
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Up) && (onGround || inAir < maxInAir))
{
playerVelocity.y = -gravity;
inAir += dt;
}
else
{
playerVelocity.y = gravity;
inAir = maxInAir;
}
}
int main()
{
sf::RenderWindow window(sf::VideoMode(800,600), "How to apply collision?");
// Loading player texture
sf::Texture playerTexture;
if (!playerTexture.loadFromFile("player.png")) return 0;
// Creating player sprite
sf::Sprite player;
player.setTexture(playerTexture);
// Loading grass texture
sf::Texture grassTexture;
if (!grassTexture.loadFromFile("grass.png")) return 0;
// Creating a vector because we have more blocks and we will need them into a container
std::vector<sf::Sprite> grass;
// Add 4 grass blocks to the container
grass.resize(4);
for (std::size_t i=0; i<3; ++i)
{
grass[i].setTexture(grassTexture);
grass[i].setPosition(128 * i, 384);
}
// Last grass block will bo above the first one
grass[3].setTexture(grassTexture);
grass[3].setPosition(0,256);
// Create a sf::Vector2f for player velocity and add to the y variable value gravity
sf::Vector2f playerVelocity(0, gravity);
sf::Clock clock;
while (window.isOpen())
{
// Get the frame elapsed time and restart the clock
float dt = clock.restart().asSeconds();
sf::Event event;
while (window.pollEvent(event))
{
if (event.type == sf::Event::Closed)
window.close();
}
// Apply physics to player
player.setPosition(player.getPosition().x + playerVelocity.x * dt, player.getPosition().y + playerVelocity.y * dt);
onGround = false;
for (std::size_t i=0; i<grass.size(); ++i)
{
// Affected area
sf::FloatRect area;
if (player.getGlobalBounds().intersects(grass[i].getGlobalBounds(), area))
{
// Verifying if we need to apply collision to the vertical axis, else we apply to horizontal axis
if (area.width > area.height)
{
if (area.contains({ area.left, player.getPosition().y }))
{
// Up side crash
player.setPosition({ player.getPosition().x, player.getPosition().y + area.height });
}
else
{
// Down side crash
onGround = true;
inAir = 0.f;
player.setPosition({ player.getPosition().x, player.getPosition().y - area.height });
}
}
else if (area.width < area.height)
{
if (area.contains({ player.getPosition().x + player.getGlobalBounds().width - 1.f, area.top + 1.f }))
{
//Right side crash
player.setPosition({ player.getPosition().x - area.width, player.getPosition().y });
}
else
{
//Left side crash
player.setPosition({ player.getPosition().x + area.width, player.getPosition().y });
}
}
}
}
move(playerVelocity, dt);
window.clear();
// Draw the grass
for (std::size_t i=0; i<grass.size(); ++i)
{
window.draw(grass[i]);
}
// Draw the player
window.draw(player);
window.display();
}
return 0;
}