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.)
function _draw() cls() for i=0,6 do if btn(i) then print("x",i*8,0) end if btnp(i) then print("x",i*8,8) end end end
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.
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!
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
[Please log in to post a comment]