Log In  

Cart #simpleinputsystem-0 | 2020-12-02 | Code ▽ | Embed ▽ | No License
3

Simple input system, to manage key/button presses.

Registers pressed and release buttons.
Horizontal axis, vertical axis, O and X buttons are all independent of each other.

The code is commented, so you can follow along what it is doing (and possibly improve it, if you wish).

As is, it is good enough and does the job, but I wouldn't be surprised if there is a more efficient way of doing this.

P#84964 2020-12-02 21:06 ( Edited 2020-12-02 21:06)

2

This is very cool. I like how the code is commented as very well optimized. One improvement I would suggest is adding player 2 inputs to the system. (Player 2 inputs: s,f,e,d,tab & x)

P#84969 2020-12-02 23:12
1

Hey, this is some great code. Thanks for sharing this. Here is another way of doing it.

Cart #robsinputsystem-1 | 2021-04-10 | Code ▽ | Embed ▽ | No License
1

Even though it looks enticing, we know that we cannot use the built-in functions alone for checking button released. We need to create a table so that we can know what buttons were pressed on the last frame and what buttons were pressed on the frame before it.

You can numerically index your players and maybe save a small few tokens, but I went with string players but numeric buttons. Below hardcoded table is SIMILAR to the table I construct in initbuttons() except that hard-coding like this is going to start your index at 1 where PICO-8 buttons start at 0. I use a for loop to take care and also save tokens. Anyway, table looks something like this:

buttons = {
 player0 = {
  {isdown = false, isup = false},
  {isdown = false, isup = false},
  {isdown = false, isup = false},
  {isdown = false, isup = false},
  {isdown = false, isup = false},
  {isdown = false, isup = false}
 },
  player1 = {
  {isdown = false, isup = false},
  {isdown = false, isup = false},
  {isdown = false, isup = false},
  {isdown = false, isup = false},
  {isdown = false, isup = false},
  {isdown = false, isup = false}
 },
}

The function I have for checking button state is basically same as the one you have given. You need to check the buttons on every frame or else it isn't gonna work right. Let's check the buttons in one function and then select values in a different function. It will look more like the built-in code. Here is how I'm checking buttons, calling this within each call to _update60()

function updatebuttons()
    for i=0,5 do
        if not btn(i) then
            buttons.p0[i].isup = buttons.p0[i].isdown
        end
        if not btn(i, 1) then
            buttons.p1[i].isup = buttons.p1[i].isdown
        end 
        buttons.p0[i].isdown = btn(i)
        buttons.p1[i].isdown = btn(i, 1)
    end 
end

And finally, and really the only thing you need to care about, is btnr(i, [p]). p is an optional parameter, so I am using some of that fancy Lua nil or value stuff on the first line there. I'm going to alias the buttons table to a local variable b because it is so satisfying to do so.

--btnr([i, [p]]) -- true when the button was released the frame before the last frame;
function btnr(i, p)
    p = p or 0

    local b
    if p == 1 then
        b = buttons.p1
    else
        b = buttons.p0
    end 
    return b[i].isup
end

So, to recap, all you need to copy n paste from my cart is

  • function initbuttons()
  • function updatebuttons()
  • function btnr(i, p)

It appears to take the exact amount of tokens as the OP cart, that's 139 tokens.
And I have tested some but please let me know if this does not work.

P#90322 2021-04-10 16:45 ( Edited 2021-04-10 19:13)
1

If you only care about released last frame and are already assuming a function call every update, this way uses less tokens (84 at minimum). I'm not sure about speed though. Also, it's not quite accurate. If btnr() is called with a player index above 1 it seems to correctly check the the button but not necessarily for the correct player

function initbuttons()
  btnrt={}
  for i=1,12 do btnrt[i]=0 end
end

function updatebuttons()
  for i=0,11 do 
    btnrt[i+1]=max(btnrt[i+1]-1,0) 
    if (btn(i%6,i\6)) btnrt[i+1]=2
  end
end

function btnr(i, p)
  if (p==1) i+=6
  return btnrt[i+1]==1
end
P#90329 2021-04-10 20:30
2

Since the button-released info seems to be the main thing this offers that standard functions don't, I just made a small function that does that. Only 32 tokens including initializing the 'previous button state' variable.

--place in _init()--
btn_old=0

function btnr(n)
 local v,r=2^n
 if(btn_old&v>btn()&v) r=1
 return r
end

--FIX, place in end of _update()--
btn_old=btn()

Or you can even get by without using a separate function at all, but this would only simplify things if you just need to test if certain buttons are released, as with O and X here. (27 tokens, and no function calls required).

--place in _init()--
btn_old=0

--place in _update()--
if(btn_old&16>btn()&16)...
if(btn_old&32>btn()&32)...
btn_old=btn()
P#90360 2021-04-11 17:12 ( Edited 2021-04-12 21:05)
1

@JadeLombax The 32 token version doesn't use the same paradigm as the btnp(i, p) function (which makes it counter-intuitive to use), wouldn't be able to handle player 2 with arrow symbols replacing the numbers, and would only work correctly if used exactly once per update for only one input.

Rather than setting btn_old equal to btn(), it should be setting just the one bit being checked. Otherwise the rest of the code has to figure out which single button was relevant to check for release. Even then, it would still require exactly one use per relevant input each frame. As such, I think requiring btn_old to be set equal to btn() at the end of the _update function would be best.

Using a single number as a bitmask is a good optimization, but I don't think it's a good idea to avoid the input system needing to be updated in _update(). If a game later turns out to need repeated checks or more usage than initially expected, being able to just call btnr() more times could save a lot of hassle.

P#90387 2021-04-12 02:42
1

Oh, okay, I see your point, that was an oversight on my part. As with the second bit of code, setting btn_old equal to btn() should come after all the inputs, I'll fix that.

P#90390 2021-04-12 04:23 ( Edited 2021-04-12 14:24)

I really love how you fellas came up with more efficient ways to do this, reading all these comments helped me a lot!!!

P#92261 2021-05-21 04:15

[Please log in to post a comment]

Follow Lexaloffle:        
Generated 2021-09-18 19:51:44 | 0.043s | Q:27