Avoiding Dropped Input

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
Deldrith
Prole
Posts: 5
Joined: Fri Apr 08, 2016 6:48 pm

Avoiding Dropped Input

Post by Deldrith » Fri Apr 08, 2016 6:55 pm

I was wondering what I should do in order to avoid input being dropped. Through testing, I realized that love.keyboard.isDown(key) would only return true if key was down when update() for that frame was running. Wanting to be able to get a true value even if a key is pressed and released quickly between updates, I tried love.keypressed(key) and love.keyreleased(key), but still had dropped input! I am assuming this is because, regardless of my order, they are both called before update(), so releasing the key would make the boolean for the key being pressed false before update() even ran.

Is there a commonly accepted way to avoid input drops?

Thank you.

User avatar
Tanner
Party member
Posts: 166
Joined: Tue Apr 10, 2012 1:51 am

Re: Avoiding Dropped Input

Post by Tanner » Fri Apr 08, 2016 8:45 pm

If you want to know if a key was pressed since your last frame you should be setting the boolean flag to false in `update` not in `keyreleased`.

User avatar
substitute541
Party member
Posts: 484
Joined: Fri Aug 24, 2012 9:04 am
Location: Southern Leyte, Visayas, Philippines
Contact:

Re: Avoiding Dropped Input

Post by substitute541 » Sun Apr 10, 2016 1:03 am

Also (this is just a quick idea,) you can use an action queue[1]. After each keypressed, append the queue with the actions caused by the key press: for example, <spacebar> => append table with action "jump", <uparrow> => append table with action "moveup" so on so forth. Actions can be functions, or string keys to another table which holds the functions.

Then at love.update, you just run the action queue in sequence and remove them (taking great care not to skip table indices.) Or you may not remove the actions as you go, and allow for reverse actions ala Braid

I'm just thinking out loud here, didn't actually use these ideas...

1. Making stuff up here, though I think that's what it's called...
Currently designing themes for WordPress.

Sometimes lurks around the forum.

User avatar
s-ol
Party member
Posts: 1077
Joined: Mon Sep 15, 2014 7:41 pm
Location: Cologne, Germany
Contact:

Re: Avoiding Dropped Input

Post by s-ol » Sun Apr 10, 2016 1:40 am

Deldrith wrote:I was wondering what I should do in order to avoid input being dropped. Through testing, I realized that love.keyboard.isDown(key) would only return true if key was down when update() for that frame was running. Wanting to be able to get a true value even if a key is pressed and released quickly between updates, I tried love.keypressed(key) and love.keyreleased(key), but still had dropped input! I am assuming this is because, regardless of my order, they are both called before update(), so releasing the key would make the boolean for the key being pressed false before update() even ran.

Is there a commonly accepted way to avoid input drops?

Thank you.
may I ask how you are testing this? All keyboard events should go through SDL, and all SDL events should go through the love keyboard handlers. And there cannot be a smaller update rate than the framestep because SDL events are only handled there (unless you replace the default love.run and do it yourself in some other way).

s-ol.nu /blog  -  p.s-ol.be /st8.lua  -  g.s-ol.be /gtglg /curcur

Code: Select all

print( type(love) )
if false then
  baby:hurt(me)
end

User avatar
slime
Solid Snayke
Posts: 2854
Joined: Mon Aug 23, 2010 6:45 am
Location: Nova Scotia, Canada
Contact:

Re: Avoiding Dropped Input

Post by slime » Sun Apr 10, 2016 2:54 am

s-ol wrote:may I ask how you are testing this? All keyboard events should go through SDL, and all SDL events should go through the love keyboard handlers. And there cannot be a smaller update rate than the framestep because SDL events are only handled there (unless you replace the default love.run and do it yourself in some other way).
The OS will queue up multiple input events before love.event.pump puts them all into LÖVE's queue every frame. Then the default love.run calls love.event.poll in a loop until all events are processed, every frame. So it's definitely possible to press and release a key and have it cause a keypress and keyrelease event but not cause love.keyboard.isDown(key) to return true during a frame.

Generally the way to avoid "dropped input" is to only use isDown for things that are logically "stuff happening over a duration of time", where pressing and releasing a key before even a single frame has been processed would have negligible effect on the game even if it could be handled using isDown.

You'd use love.keypressed and love.keyreleased (and mousepressed and mousereleased) for any action that should result in something happening immediately and not continuously.

User avatar
s-ol
Party member
Posts: 1077
Joined: Mon Sep 15, 2014 7:41 pm
Location: Cologne, Germany
Contact:

Re: Avoiding Dropped Input

Post by s-ol » Sun Apr 10, 2016 9:01 am

slime wrote:
s-ol wrote:may I ask how you are testing this? All keyboard events should go through SDL, and all SDL events should go through the love keyboard handlers. And there cannot be a smaller update rate than the framestep because SDL events are only handled there (unless you replace the default love.run and do it yourself in some other way).
The OS will queue up multiple input events before love.event.pump puts them all into LÖVE's queue every frame. Then the default love.run calls love.event.poll in a loop until all events are processed, every frame. So it's definitely possible to press and release a key and have it cause a keypress and keyrelease event but not cause love.keyboard.isDown(key) to return true during a frame.

Generally the way to avoid "dropped input" is to only use isDown for things that are logically "stuff happening over a duration of time", where pressing and releasing a key before even a single frame has been processed would have negligible effect on the game even if it could be handled using isDown.

You'd use love.keypressed and love.keyreleased (and mousepressed and mousereleased) for any action that should result in something happening immediately and not continuously.
I guess I was a little unclear, by keyboars handlers I was only referring to keypressed and keyreleased.

If I understand OP correctly then he complains that keys don't show up there too?

s-ol.nu /blog  -  p.s-ol.be /st8.lua  -  g.s-ol.be /gtglg /curcur

Code: Select all

print( type(love) )
if false then
  baby:hurt(me)
end

User avatar
pgimeno
Party member
Posts: 1908
Joined: Sun Oct 18, 2015 2:58 pm
Location: Valencia, ES

Re: Avoiding Dropped Input

Post by pgimeno » Sun Apr 10, 2016 9:47 am

Tanner nailed it.

Code: Select all

local lk = love.keyboard
local pressed = {}

function love.keypressed(k)
  if k == "up" or k == "down" or k == "left" or k == "right" then
    pressed[k] = true
  end
end

function love.update(dt)

  -- use pressed.up etc here

end

function love.draw()
  -- Simulate very intensive calculations
  love.timer.sleep(0.1)

  -- Display results
  love.graphics.print(pressed.up and "UP pressed" or "UP not pressed")

  -- Clear keypresses
  if not lk.isDown("up") then pressed.up = nil end
  if not lk.isDown("down") then pressed.down = nil end
  if not lk.isDown("left") then pressed.left = nil end
  if not lk.isDown("right") then pressed.right = nil end
end
I moved it to love.draw because I needed the key press data in love.draw, but the idea is what Tanner said. This way, very quick key presses are not missed even if the frame duration is greater than the key press duration.

Edit: alternative way to clear them:

Code: Select all

for k, _ in pairs(pressed) do if not lk.isDown(k) then pressed[k] = nil end end
Edit 2: The problem is now to detect if the key was released and pressed again, as opposed to kept pressed. That needs extra logic in the game, but the necessary data can be obtained with love.keyreleased like this:

Code: Select all

local pressed = {}
local released = {}

function love.keypressed(k)
  if k == "up" or k == "down" or k == "left" or k == "right" then
    pressed[k] = true
  end
end

function love.keyreleased(k)
  if k == "up" or k == "down" or k == "left" or k == "right" then
    released[k] = true
  end
end

function love.update(dt)

  -- use pressed.up etc. here
  -- use also released.up etc. to detect that they were released this frame

  for k, _ in pairs(released) do pressed[k] = nil end
  released = {}
end

Post Reply

Who is online

Users browsing this forum: Bing [Bot] and 9 guests