I was using btnp() to fire bullets (and arrow keys for movement) but noticed that no bullets would be fired when I changed directions. The documentation claims "btnp() also returns true every 4 frames after the button is held for 15 frames." but it looks like it only returns true if no other keys changed state for 15 frames. For example, if you hold down Z and press left and right alternately you won't see btnp(4) be true.
(Incidentally, the long delay before repeat made btnp() a bad choice for my game anyway, but you do see it used in sample code, e.g. the DOM8VERSE tutorial in zine 3.)
test code
Interesting...I guess I wouldn't have used a for loop for the button captures. I mean, there's only 6 of them. Plus you should ideally put your input checks within the _update() loop rather than _draw() - which could be part of the issue.
I've done it that way and never had any issue with my controls+shooting, and all I've made so far is shooting games.
Something like this might lead you down a better path...but it's hard to give you something more detailed without going into a full thing.
x=64 function _update() shoot=false if btn(0) then x-=1 end if btn(1) then x+=1 end if btnp(4) then shoot=true end end function _draw() print(x, 0,0, 7) print(shoot, 0,30, 10) end |
The other way I've done it is not to use btnp() but then apply a timer to the shooting so it only happens every X number of ticks. This will get you a more consistent firing rate rather than the weird btnp() way of firing, then waiting a few then every 4.
Also take a look at this example
any buttonpress kills the repeat of other buttons for ~15 frames. also, button repeats are all synchronized. worst part is, this is true across players!
you can test this thoroughly here:
I think btnp() should be considered buggy and zep should revamp it.
a few ideas:
- btnpx() which does not repeat
- btnr() button released
- btnp() that does repeat each button independantly
a case could be made about synchronizing repeat for the dpad on diagonals though. - btnd(player, button, first_repeat_frames, further_repeat_frames)
define your own repeating scheme (defaults 15,4 @30 and 30,8 @60)
or... kill btnp altogether. I stopped using it and made my own by polling btn every frame. but hey, tokens!
Interesting read - I am also annoyed btnp repeats after 15 frames.
It's not really ... A button press function. Funny that this problem with it kinda makes it more like what it logically should do.
I write my own debouncing code because of this bug. I have multiple btn() variants:
- btn(): true if button is currently down, bitmask with no args (default)
- btnp(): true on the frame a button goes down or repeats (default)
- btnd(): true on the frame a button initially goes down
- btnh(): number of frames the button has been held, or 0
- btnu(): true on the frame a button finally goes up
It's really not very complex, so I might tidy my code and upload it.
@zep - I think, in windows, you need to ignore WM_KEYDOWN events that have the repeat count (lParam & 15) greater than 0. That or just use GetAsyncKeyState() to read the keyboard.
oh man I wish btnd
was a built-in. I implement it manually in almost every cart (and I must say that is a much better name for it than the one I've been using, Felice XD)
more on topic: I've noticed this bug too! but I guess because I don't use btnp much, I kind of ignored it or assumed it might be an OS-level issue (guess I was wrong!) :p
It looks like this was fixed in v0.2.0:
Changed: btnp() delay and repeats now work independently per-button
Thanks!
Is there a clean way to set the repeat interval via btnp() or at least toggle off the auto-repeat in the current version? Perhaps through an optional parameter (numeric/boolean)?
@Felice 's set looks very nice, so maybe I'll go that direction.
However, I do feel like there should be a zero-repeat option built-in since I think that's what btnp() was probably meant for vs. btn(). It seems fundamental enough to not require writing up an input-state handler, even if that is pretty simple.
Or is using poke(0x5f5c,delay) and poke(0x5f5d,delay) in _update() actually the finalized method by design?
I see. Thanks for clarifying @freds72 .
I'll use the poke() method then. Masking with syntactic sugar is simple enough.
[Please log in to post a comment]