1
\$\begingroup\$

In my games update loop, which happens on a fixed timestep of 30 times per second, I am checking the current state of several keys to determine how to move the player. For example:

if(Keyboard.down(KEY_LEFT) { /* move character left */ }

This works fine in situations where I expect the player to hold the key down for extended periods (such as movement), but for things like shooting, where the player just taps the key quickly, it doesn't always pick up the key being down.

This is due to the key being both pressed and released in the gap between polling.

Now obviously I don't want to trigger my shooting code 30 times a second like I do my moving code, so the solution needs to incorporate some kind of buffering/delay mechanism to make sure each shot is still x milliseconds apart, but I need the first one to register immediately and with certainty.

I am using Javascript, so I can easily use event driven functions linked to keypresses (in fact I am doing this already in order to keep track of which keys are down), but I didn't want to have game logic outside of the fixed timestep update.

Can anyone suggest a solution? I'm not looking for code, more an idea of how to design/structure the code around the problem.

\$\endgroup\$
5
  • \$\begingroup\$ This is dependent on your platform/language/API, as most offer buffered input in some form. Could you edit your post to specify what you're using? \$\endgroup\$
    – Kylotan
    Dec 31, 2011 at 13:39
  • 1
    \$\begingroup\$ You should not polling user input at all! Your main loop is the place where you see what happened. UI is managed by interrupts and events. \$\endgroup\$
    – FxIII
    Dec 31, 2011 at 16:46
  • \$\begingroup\$ @FxIII Like Kylotan said, it depends on the API. For instance, the standard XNA input API is entirely polled, so not much you can do there (except for using workarounds such as intercepting the window's messages directly, or another API entirely). Also, the main loop is typically divided into the Update phase and Render phase (which may run at different rates). The place where you see what happened is the Render phase, not the entire game loop. In fact, in a game it's a good idea to limit most of the processing to the Update phase. Handling the events directly brings unpredictability. \$\endgroup\$ Jan 1, 2012 at 17:05
  • \$\begingroup\$ @DavidGouveia My opinion remains the same: polling the user input is unaffordable solution (for every non trivial projects) \$\endgroup\$
    – FxIII
    Jan 1, 2012 at 22:48
  • \$\begingroup\$ @FxIII - if the API only offers polled input, then you have no choice, and if it wasn't affordable the API would be useless. (Luckily there is very little difference in terms of performance, because it's usually just a different interface onto the same data these days.) \$\endgroup\$
    – Kylotan
    Jan 2, 2012 at 18:48

4 Answers 4

4
\$\begingroup\$

Use the event driven API already provided for you, but instead of executing the events immediatly, queue and batch them to be executed in the next update iteration.

Here's an example in C# which I suppose you'll be capable of adapting to Javascript. In this case all events will be executed during the next frame after they were created:

var keyEventQueue = new List<Pair<object, KeyEventArgs>>();

private void OnKeyPress(object sender, KeyEventArgs e)
{
    keyEventQueue.Add(new Pair(sender, e));
}

public void Update(float elapsed)
{
    foreach(var evt in keyEventQueue) 
    {
        // Handle evt
    }
    eventQueue.Clear();
}

But if you'd like to ensure that there's at least one frame of delay between each event being handled, you simply need to change the Update method to:

public void Update(float elapsed)
{
    if(keyEventQueue.Count > 0)
    {
        var evt = keyEventQueue[0];
        // Handle evt
        keyEventQueue.RemoveAt(0);
    }
}
\$\endgroup\$
4
  • \$\begingroup\$ Luckily Javascript can handle this a lot easier. The problem with the keyEventQueue is that you'd have to process those events much more compact maybe causing runtime conditions, and you'd have to deal with other time issues because the bullets would be fired at the same time and not when they happen like in my example. \$\endgroup\$ Dec 31, 2011 at 16:20
  • \$\begingroup\$ @ThomasR.Koll Maybe you didn't catch my edit, but it's trivial to change so that only one event is processed per frame (while still doing the detection at an higher resolution which is what he wants). \$\endgroup\$ Dec 31, 2011 at 16:25
  • \$\begingroup\$ @ThomasR.Koll Also it has nothing to do with it being Javascript or not. I simply used C# because it's the one whose syntax and API I have clearer in my memory. The idea still remains for Javascript - make a copy of the state of your event and store it to be handled later when it's more appropriate (i.e. in the update portion of the game loop). \$\endgroup\$ Dec 31, 2011 at 16:35
  • \$\begingroup\$ I think this is pretty much the answer is was looking for, or something similar anyway. I need to just register the events as they happen, and then deal with them however I like within the loop. \$\endgroup\$
    – beeglebug
    Dec 31, 2011 at 19:00
1
\$\begingroup\$

That's the reason why APIs usually export things like KeyDown and KeyUp (or KeyPressed / KeyReleased). That way you don't check if a key is currently pressed, but its derivative. You then bind the action "Fire" to "KeyPressed", and the problem doesn't even exist.

\$\endgroup\$
3
  • \$\begingroup\$ I understand that, but thought it would be bad to have separate chunks of game logic inside events which could trigger at any time, rather than keeping it all inside the main update function. Different systems trigger events at different speeds, so any logic inside events could happen at unknown intervals, rather than a consistent 30 times per second. \$\endgroup\$
    – beeglebug
    Dec 31, 2011 at 14:21
  • \$\begingroup\$ @beeglebug: You could, as David says, just set a "key_pressed=true" on the keyPress event, then just handle it in your mainloop. What I meant is that you don't want to know if a key is down, you want to know if it has been pressed. See the difference ? \$\endgroup\$
    – Ravachol
    Dec 31, 2011 at 15:48
  • \$\begingroup\$ @Ravachol Sorry, I deleted my comment because I thought it needed more explanation. But I don't think you're targeting beeglebug's main question which is about having game logic running outside the fixed timestep update though. \$\endgroup\$ Dec 31, 2011 at 15:57
0
\$\begingroup\$

What's you problem with having that little firing code not being in you timestep update? I'd model my gamestate object to have a firePressed function that I call from the keyPressed event handler, that firePressed will create a new bullet or whatever it is and in the game's timesteop update I'd only do stuff like expiring bullets wether the hit something or went outside the viewfield.

\$\endgroup\$
1
  • \$\begingroup\$ What you suggest is no different from handling the event directly in the event handler. There's just one extra level of indirection in that method call. And maybe in a simple bullet case there would be no problems with having them spawned outside of the update loop's timeframe, but in general that might not be true. It's a matter of synchronization and predictability, and keeping all game processing inside the game loop. \$\endgroup\$ Dec 31, 2011 at 16:27
0
\$\begingroup\$

to get a pattern like that:

if (keyDown[KEYCODE_ENTER]) ...

you should attach event handlers for keydown and keyup. the event handlers respectively set/unset a property on an object (keyDown in the following example):

var keyDown = {};
document.attachEventHandler('keydown', function(event) {
    keyDown[ev.keyCode || ev.which] = true;
}, false);
document.attachEventHandler('keyup', function(event) {
    keyDown[ev.keyCode || ev.which] = false;
}, false);
\$\endgroup\$
1
  • \$\begingroup\$ Won't do what he asked. What if the player presses and releases a button twice before the frame is reached? By the time the update runs the only thing it will know is that the key is currently up. It won't tell him how many presses happened. \$\endgroup\$ Jan 1, 2012 at 13:22

You must log in to answer this question.

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