Perhaps this is going to be useful for someone. This is a little keyboard handler I'm using in my code. It extends the functionality of the standard btn(k) function with detection of the onset of the key and its release. Sometimes it's useful to have those two and avoid btnp(k) repetition.
-- is_held(k) is true if the key k is held down -- is_pressed(k) is true if the key has just been pressed by the user -- is_released(k) is true if the key has just been released by the user keys={} function is_held(k) return band(keys[k], 1) == 1 end function is_pressed(k) return band(keys[k], 2) == 2 end function is_released(k) return band(keys[k], 4) == 4 end function upd_key(k) if keys[k] == 0 then if btn(k) then keys[k] = 3 end elseif keys[k] == 1 then if btn(k) == false then keys[k] = 4 end elseif keys[k] == 3 then if btn(k) then keys[k] = 1 else keys[k] = 4 end elseif keys[k] == 4 then if btn(k) then keys[k] = 3 else keys[k] = 0 end end end function init_keys() for a = 0,5 do keys[a] = 0 end end function upd_keys() for a = 0,5 do upd_key(a) end end |
You need to call these in your _init() and _update() functions:
function _init() init_keys() end function _update() upd_keys() end |
Very cool, thanks for sharing. This will come in handy in places like where I want single shot type of things. When I use btnp() to fire a bullet, it still fires after it's held down too.
Thank you. Exactly! I used that in my game to make sure the user wouldn't accidentally confirm a screen.
That's by design, I suspect, to make it hard to do RSI-as-balance game design.
Can anyone confirm if Pico-8 imposes the 5-key rollover limit? My keyboard supposedly has six-key USB rollover, but I don't have a better app to test it at the moment, and I'm only getting 5 in Pico-8.
Not an issue, just curious.
Thanks Adam J! These functions ended up being far more elegant than the kludges I have thrown into my past pico8 programs to get key_up functionality.
AdamJ, I have used your demo as the basis for an extended keyboard handler that supports buttons for 2 players and provides a "pulse" mechanism in addition to the held, pressed, and released functionality. I've utilized your display code for the same kind of demo effect.
Would you be ok with me posting it?
This is a modified version of AdamJ's keyboard handler. Some of the bit setting is handled a little differently, but it is pretty much exactly the same idea of using a couple of bits to track the current state of the buttons. I also encapsulated everything within the "keys" table/object.
I use the btn() function (as opposed to btn(b) which returns a single button status) to get a binary-encoded status of all of the buttons for players 1 and 2.
I also included a "pulse" function. keys:pulse(k,r) returns true every r frames while key k is held down. So, keys:pulse(0,6) will be true every six frames while the left arrow is held down. This is similar to the built-in btnp() function, except that btnp() is locked at every four frames.
When using pulse, I have an arbitrary limit/count of 30 frames. Any value of r that is a divisor of 30 should work smoothly, while numbers that are not factors for 30 will produce non-regular pulses. So, 1,2, 3, 5, 6, 10, 15, and 30 will all produce smooth results.
If you need some other smooth interval, modify the line that reads:
keys.ct[i]=(keys.ct[i]+1) % 30 |
And change the 30 to a multiple of the frequency you desire.
Pulses are tracked separately for each key, so if I press and hold button 0, and then three frames later press and hold button 3, and am looking for pulses of 6 on each button, I will get a pulse for button 0 on frame 6, and a pulse for button 3 on frame 9. Pulse counters are reset each time a key is pressed.
Here is the code for the keys object. It actually comes out slightly lighter on the tokens count than the original handler, even with the second player and pulse command added.
keys={btns={},ct={}} function keys:update() for i=0,13 do if band(btn(),shl(1,i))==shl(1,i) then if keys:held(i) then keys.btns[i]=2 keys.ct[i]=(keys.ct[i]+1) % 30 else keys.btns[i]=3 end else if keys:held(i) then keys.btns[i]=4 else keys.btns[i]=0 keys.ct[i]=0 end end end end function keys:held(b) return band(keys.btns[b],2) == 2 end function keys:down(b) return band(keys.btns[b],1) == 1 end function keys:up(b) return band(keys.btns[b],4) == 4 end function keys:pulse(b,r) return (keys:held(b) and keys.ct[b]%r==0) end |
You will need to call "keys:update()" in your _update function to update the keyboard state.
[Please log in to post a comment]