0
\$\begingroup\$

I'm testing out SFML by trying to make a square move with lerp velocity. The desired result was that when, let's say, D was pushed, the square would accelerate smoothly from velocity.x = 0 to velocity.x = maxVel (20). When the D key is let go, it decelerates back to 0. The problem is, I can't get it to decelerate! When I let go of D, it keeps on going!

Player.cpp (only relevant code shown):

#include "Player.h"

void Player::input() {
    using Key = sf::Keyboard::Key;
    auto keyDown = [](sf::Keyboard::Key k) {
        return sf::Keyboard::isKeyPressed(k);
        };


    if (keyDown(Key::A)) {

        velocityGoal.x -= 3;
    }
    else if (keyDown(Key::D)) {
        velocityGoal.x += 3;
    }
    if(keyDown(Key::A) != true){
        velocity.x = 0;
    }
    else if (keyDown(Key::D) != true) {
        velocity.x = 0;
    }
    if (keyDown(Key::F)) {
        velocity = velocity; //just a breakpoint cue. Move along.
    }
}
void Player::update(float dt) {

    //interpolating velocity
    velocity.x = Math::interpolate(velocityGoal.x, velocity.x, dt);
    velocity.y = Math::interpolate(velocityGoal.y, velocity.y, dt);

        //capping out speeeeed
    if (velocityGoal.x > maxVel) {
        velocityGoal.x = maxVel;
    }
    if (velocityGoal.x < -maxVel) {
        velocityGoal.x = -maxVel;
    }

    //adding velocity to the player's position
    newPos += velocity;
    rect.setPosition(newPos);
}

void Player::draw(sf::RenderTarget& target) {
    target.draw(rect);
}

My interpolation function:

float Math::interpolate(float goal, float current, float deltaTime){
float diff = goal - current;
if (diff > deltaTime) {
    return current + deltaTime;
}
else if (diff < -deltaTime) {
    return current - deltaTime;
}

return goal;
}

It appears to be a problem with the if statements that set velocity.x to 0. SFML doesn't have anything like keyJustPressed or keyUp, so I just polled to see if keyDown(D) was not true. This evidently is not the right thing to do in this situation.

Does anyone know the right way to do this, or if there is some way I can track a key being released?

\$\endgroup\$

1 Answer 1

1
\$\begingroup\$

If I understand your question correctly, you want to differentiate between a keyboard press and a keyboard release.

What you want to do is keeping track of the keyboard's state in the current frame and the previous frame. By then comparing the two states, you can figure out if a key was either pressed, released or even held.

Below I've added a code example on how that can be made. I've added all the code in one file but you can of course move all the keyboard checking code to an input handler class etc. The same kind of code can also be used for mouse buttons, joystick buttons etc.

#include <SFML/Graphics.hpp>

// The keyboard's state in the current- and the previous frame
bool CurrentKeyState[sf::Keyboard::KeyCount];
bool PreviousKeyState[sf::Keyboard::KeyCount];

// See function bodies below
bool KeyPressed     (sf::Keyboard::Key Key);
bool KeyReleased    (sf::Keyboard::Key Key);
bool KeyHeld        (sf::Keyboard::Key Key);

int main()
{
    sf::RenderWindow Window(sf::VideoMode(800, 600), "SFML keyboard test");

    sf::Event Event;

    memset(CurrentKeyState,     false, sizeof(CurrentKeyState));
    memset(PreviousKeyState,    false, sizeof(PreviousKeyState));

    while(Window.isOpen())
    {
        while(Window.pollEvent(Event))
        {
            if(Event.type == sf::Event::Closed)
                Window.close();
        }

        //////////////////////////////////////////////////////////////////////////

        // Save the state of each keyboard key (must be done before any Key* function is executed)
        for(unsigned int i = 0; i < sf::Keyboard::KeyCount; ++i)
        {
            // Save the keyboard's state from the previous frame
            PreviousKeyState[i] = CurrentKeyState[i];

            // And save the keyboard's state in the current frame
            CurrentKeyState[i] = sf::Keyboard::isKeyPressed((sf::Keyboard::Key)i);
        }

        if(KeyPressed(sf::Keyboard::Escape))
            Window.close();

             // Not possible (and also doesn't make much sense) to use KeyHeld and KeyPressed together
        //   if(KeyHeld(sf::Keyboard::A))       printf("Key A is held\n");
             if(KeyPressed(sf::Keyboard::A))    printf("Key A has been pressed\n");
        else if(KeyReleased(sf::Keyboard::A))   printf("Key A has been released\n");

        //////////////////////////////////////////////////////////////////////////

        Window.clear(sf::Color::White);

        // Render stuff

        Window.display();
    }

    return 0;
}

bool KeyPressed(sf::Keyboard::Key Key)
{
    return (CurrentKeyState[Key] && !PreviousKeyState[Key]);
}

bool KeyReleased(sf::Keyboard::Key Key)
{
    return (!CurrentKeyState[Key] && PreviousKeyState[Key]);
}

bool KeyHeld(sf::Keyboard::Key Key)
{
    return CurrentKeyState[Key];
}
\$\endgroup\$
1
  • \$\begingroup\$ That's a nice and clean coded answer! everything inside, everything explained! \$\endgroup\$ Commented Sep 7, 2018 at 6:26

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .