Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Best Game Loop for an Input Manager  (Read 3979 times)

0 Members and 1 Guest are viewing this topic.

MrPlosion1243

  • Newbie
  • *
  • Posts: 9
    • View Profile
Best Game Loop for an Input Manager
« on: January 19, 2013, 06:49:02 pm »
So from what I understand (please correct me if I'm wrong) in SMFL 2.0 you should use sf::Event::KeyPressed and sf::Event::KeyReleased when dealing with single key presses and releases, but if you want continuous input you should use the sf::Keyboard::isKeyPressed function. So in my input manager class I have done so for a single key press:

InputManager.h
class InputManager
{
public:
        static bool IsKeyPressed(const sf::Keyboard::Key key);
       
        static sf::Event event;
};

InputManager.cpp
sf::Event InputManager::event;

bool InputManager::IsKeyPressed(const sf::Keyboard::Key key)
{
        return event.type == sf::Event::KeyPressed && event.key.code == key ? true : false;
}

The static event member is being updated in a game loop labeled "here" like so:

StateManager.cpp
void StateManager::GameLoop()
{
        while(window.isOpen())
        {
                sf::Event event;
                while(window.pollEvent(event))
                {
                        InputManager::event = event; //here
                        //states[0]->Update(); //here 2

                        switch (event.type)
                        {
                                case sf::Event::Closed:
                                        window.close();
                                        break;
                                default:
                                        break;
                        }
                }

                for(size_t i = 0; i < states.size(); i++)
                {
                        states[i]->Update();

                        window.clear();
                        states[i]->Draw(window);
                        window.display();
                }
        }
}

Then anywhere I wan't to use input I can put this inside a state:

void SomeState::Update()
{
        if(InputManager::IsKeyPressed(sf::Keyboard::Key::Space))
        {
                //...
        }
}

The problem is that this doesn't work, the InputManager::IsKeyPressed function never returns true. However if I uncomment the code you saw above labeled "here 2" then the function executes fine. I don't know why it doesn't work updating the state after the poll event loop and I was hoping you guys could explain why. Another problem with this method is that once the event object leaves the poll event loop and there are no more events to be polled then the event object will never be resigned so the InputManager::IsKeyPressed function will return what ever it was previously.

I don't think updating the states inside the poll event loop is efficient so what is the best way to structure this game loop to fix the problems I'm having? Also why doesn't the event object work outside the poll event loop?

Thanks.

cire

  • Full Member
  • ***
  • Posts: 138
    • View Profile
Re: Best Game Loop for an Input Manager
« Reply #1 on: January 19, 2013, 07:53:23 pm »
You only keep track of the last event that was processed, so for isKeyPressed to return true, that would have to be last event processed, which is.. unlikely.

I wouldn't expect a function named isKeyPressed to use events.

MrPlosion1243

  • Newbie
  • *
  • Posts: 9
    • View Profile
Re: Best Game Loop for an Input Manager
« Reply #2 on: January 19, 2013, 10:50:51 pm »
You only keep track of the last event that was processed, so for isKeyPressed to return true, that would have to be last event processed, which is.. unlikely.

Oh, I see that would make since, and explains why updating the state inside the poll event loop worked. Thank you very much, but now I need to figure out how to solve this problem.

I wouldn't expect a function named isKeyPressed to use events.

What are you saying? That I should rename the function or that I should not use events?



From what I now know off the top of my head I thought to just change while(window.pollEvent()) to if(window.pollEvent()) and that seems to fix this problem as expected, but does this make things less efficient? Every single example of a game loop I've seen always uses while(window.pollEvent()) and google doesn't have anything on this topic.

krzat

  • Full Member
  • ***
  • Posts: 107
    • View Profile
Re: Best Game Loop for an Input Manager
« Reply #3 on: January 19, 2013, 10:51:09 pm »
You want to use sf::Keyboard::isKeyPressed
SFML.Utils - useful extensions for SFML.Net

cire

  • Full Member
  • ***
  • Posts: 138
    • View Profile
Re: Best Game Loop for an Input Manager
« Reply #4 on: January 19, 2013, 11:42:29 pm »
What are you saying? That I should rename the function or that I should not use events?

Yes.  isKeyPressed suggests to me that it returns true if a key is currently pressed.  It doesn't suggest to me that it returns true if there was a recent key press event.  It is also a little counter-intuitive if you're using a library (like SFML) with an isKeyPressed that does not deal with events.


From what I now know off the top of my head I thought to just change while(window.pollEvent()) to if(window.pollEvent()) and that seems to fix this problem as expected, but does this make things less efficient? Every single example of a game loop I've seen always uses while(window.pollEvent()) and google doesn't have anything on this topic.

If you want to deal with events, you might keep a vector of keys pressed per loop iteration and check that vector when the function is called -- obviously it would need to be cleared at the beginning of the next iteration.  Otherwise, you might actually check to see if the key is currently pressed, which seems to be what krzat is recommending.

MrPlosion1243

  • Newbie
  • *
  • Posts: 9
    • View Profile
Re: Best Game Loop for an Input Manager
« Reply #5 on: January 20, 2013, 02:10:48 am »
If you want to deal with events, you might keep a vector of keys pressed per loop iteration and check that vector when the function is called -- obviously it would need to be cleared at the beginning of the next iteration.  Otherwise, you might actually check to see if the key is currently pressed, which seems to be what krzat is recommending.

Thank you cire! I've implemented this brilliant solution and it works as expected.  :)