[8x8] | |
Since copyright was a concern earlier, I would like to state that this code and any other code I have or may produce in the future is licensed for use only under PICO-8. That is, my code is free for anyone and everyone to use entirely as they like for whatever freeware project they have in mind, yet its use is to remain strictly in this programming language PICO-8, and no other languages or derivations are allowed unless permission otherwise is granted from the author.
One other stipulation, if you use my work in a commercial setting or it is a project of more than one person, I must be able to see "dw817" somewhere in it. No-one ELSE needs to see it, but I do. So stuff it sideways or backwards in your 1-second logo, whatever. a reminder to let me know I helped someone else fulfill their project dream.
You can see this copyright and license in usage by the inclusion of the icon above in the SPRITES tab - and you are welcome to use it also for your own packages to denote the self-same copyright and license restrictions and allowances.
UPDATES
WHAT'S NEW ??
09-25-18
- PROJECT COMPLETE ! See instructions below for usage.
- Got type "2" working properly.
- Added option to change type during demo run. Press ⎠and ðŸ…¾ï¸ to do so.
09-24-18
- Got type "1" working properly.
09-23-18
- Got type "0" (zero) working properly.
So what exactly is this ?
It's a comprehensive function you can call to return the standard 6-keystrokes in many different ways.
If you set KEYTYPE to zero, you have true arcade controls. No staggering for any input, multiple keystrokes can be read via KEYIN("zz") where "zz" is the name of the key you want to see if it appears in that particular stroke.
Possible keys are "L" "R" "U" "D" "A" and "B" and can be returned singly or if multiple keys are held.
IF KEYIN("L") THEN ShipX=ShipX-1 IF KEYIN("R") THEN ShipX=ShipX+1 IF KEYIN("A") THEN CALL Fire() |
You can press any number of these keys including holding down the LEFT or RIGHT arrow key and the "O" button. No need to stop pressing one to register another. KEYIN() can return all 6-keystrokes simultaneously if need be.
You can also press UP and DOWN to return "UD" special keystroke.
Press LEFT and RIGHT to return "LR" special keystroke.
And press "O" and "X" (Z and X) to return "AB" special keystroke.
These 3-keystrokes will appear only once in a strobe and and then return no more keystrokes until you release them.
If you want regular input like for menus and selections where all keystrokes are staggered by delays and time held, change KEYTYPE to 1 (one).
Now diagonal movements flip between two keys if both are held. (A) and (B) register once, pause, again, pause, then repeat.
You truly get just one keystroke outside of the 3-special listed above. You can also change the default counting delay of 8 to anything you want. Change global "KEYTIME" shown at the beginning of _INIT()
The KEYTYPE #2 is a very special case indeed. You still have diagonal movements flip between two keys but now (A) and (B) only register when RELEASED. If you hold either down for a short while, you get a new special keystroke called either "A+" or "B+" depending upon which you held.
Continue to hold that key down and you can still navigate with the arrow keys. But if at any point you release (A) or (B), whichever was held, a new keystroke is sent of "A-" or "B-" signifying you have released it, and you can also register that comparison directly in your code.
That's it !
I hope you find this function instrumental and useful in your existing and future carts. I certainly plan to make use of it myself. Thank you for your time !
There are two things that come to mind.
One is the concept of an "abstract user event", which appears in many frameworks today: Instead of describing all actions in the most concrete terms of what the hardware is doing at that moment, the buttons are monitored for changes by the framework and processed into more abstract events like "A down", "B release" "up+down held", and so on. So somewhere in the program you would enumerate all the types of events you want to work with, and the framework's task would be to generate those events reliably.
Many frameworks also provide a system of registering "listener functions" that are called upon an event being triggered: an alternate strategy is simply to set or increment variables describing which events have happened since the last update.
Second, any "sequence of actions triggering unique events" concept like "first the button is pressed, now it is released" is an opportunity to formalize the model as a finite state machine. The full lifecycle of any button press would be:
button is now up
user presses the actual hardware
button is now pressed
"enough" time has passed (not necessarily an exact frame! old arcade games would poll multiple times per frame.)
button is now held
user releases the actual hardware
button is now up
Fortunately, in PICO-8 we already have a convenience function for the moment when the button is pressed: btnp(). So the timing aspect of distinguishing press from hold is just a matter of asking whether the button is NOT pressed.
To express something like a "lock key" we have to realize the idea of this "lifecycle" in terms of both button presses and time. I put together a little example for this: To do a "dragon punch" as in Street Fighter II, you have to input right, neutral, down, down+right, and while down+right are held, Z. If you do it too slowly, it times out.
To implement this system I first implement "hold" times and "release" events for each button. Then I use the release to determine whether I am in neutral for the second part of the dragon punch. If I wanted to implement a move where it requires me to wait for at least 4 frames, I could use the "hold" data for that.
bhold = {} brelease = {} for i=0,5 do bhold[i]=-1 brelease[i]=-1 end function pumpholds() color(6) for i=0,5 do brelease[i] = -1 if btn(i) then if btnp(i) then print(i.." down") end bhold[i] += 1 print(i.." held: frame "..bhold[i]) else if bhold[i] ~= -1 then print(i.." up") bhold[i] = -1 brelease[i] = 1 end end end end dragonpunch = -1 dragonpunch_timeout = 0 function fsm() color(8) if dragonpunch == -1 then if btnp(1) then dragonpunch = 0 dragonpunch_timeout = 60 print("started dp") end else dragonpunch_timeout -= 1 if dragonpunch == 0 then if brelease[1]==1 then print("release") dragonpunch += 1 end elseif dragonpunch == 1 then if btnp(3) then print("down") dragonpunch += 1 end elseif dragonpunch == 2 then if btn(3) and btnp(1) then print("down+right") dragonpunch += 1 end elseif dragonpunch == 3 then if btn(3) and btn(1) and btn(4) then color(9) stop("shoryuken!") dragonpunch = -1 end end if dragonpunch_timeout == 0 then dragonpunch = -1 print("dp timed out") end end end function _update() pumpholds() fsm() end |
edit: url fix
That's pretty neat. I like the karate punch thing. But no, I'm looking for where KEY the string is modified according to a plan:
keytype=0 ... anything goes, arcade
keytype=1 ... only one key at a time and staggered
keytype=2 ... special, can recognize held keys
KEY can contain, "L R U D A B LR UD AB A+ A- B+ B-"
If keytype is zero then you can stack the string so "LU RU LD RD" is possible.
One thing I am also seeing is multiple use of BTN() BTNP(). Now I'm not sure but I'm wondering if it's possible in one point of code to read a correct value for BTN() or BTNP() and later on in code if I attempt to read it AGAIN, I will get different results.
I haven't given a good in depth look to your code, but if you're intending to make this a library or similar for others to bootstrap to their games you may want to consider bitwise operations for your button checks in order to reduce token count. Similar to how I do in my "Keyboard and Mouse Library."
Revelant Code:
function _mouse() _mx,_my,_mb=stat(32),stat(33),stat(34) _mbld,_mblu,_mbru,_mbrd,_mbmu,_mbmd=false,false,false,false,false,false _mbld=_mbl==0 and band(0b0001,_mb)>0 _mblu=_mbl!=0 and band(0b0001,_mb)==0 _mbl=band(0b0001,_mb) _mbrd=_mbr==0 and band(0b0010,_mb)>0 _mbru=_mbr!=0 and band(0b0010,_mb)==0 _mbr=band(0b0010,_mb) _mbmd=_mbm==0 and band(0b0100,_mb)>0 _mbmu=_mbm!=0 and band(0b0100,_mb)==0 _mbm=band(0b0100,_mb) end |
Link to full library: https://www.lexaloffle.com/bbs/?tid=31079
But again, I should stress, this is if you aren't already doing such and of course you only use this for checks at the lowest level. Anything abstracted from there, such as multi checks, should be done a layer above.
Hi Cabledragon:
I tried out your CART. Tried pressing arrow keys, (O) and (X). Nothing registered.
I'm not going to be using the mouse at all until ZEP fixes the existing problems with touch-screens.
Nah, the arrow keys aren't what works in that demo. That library is for full keyboard input. So you can type stuff and press enter and it will display it. It's meant to be a "barebones" library, so it doesn't do things like surpress the menu when you press enter or anything like that. I just wanted to get the most functionality out of the fewest tokens. But what I was referring to was just specifically how I handled the state checks for the mouse buttons, joy state works in a similar way in pico-8 as far as I know.
I don't know if I can do that here. I've got the code just about as optimized as I can. There's one quick update I made this morning to improve it - but I think after that I've gone as far as my programming skills will allow me.
I only know enough about bits to set them with a +=2^n and to check for them with a function I use.
Certainly if someone wants to take my keyboard code and improve or optimize it using excelling methods, they are welcome.
[Please log in to post a comment]