Oddly Generic Game
This is my first game on Pico-8 ever. I have to thank Dylan Benett for his tutorial because otherwise I would be completely clueless without it.
This is the cartridge created for the Youtube series for Showdown.
About
This game is heavily inspired by a minigame from Pureya by Majorariatto Studios (https://store.steampowered.com/app/1268960/pureya/). It's an endless runner with some not very original game mechanics but fun! Let me know your comments and enjoy!
Edit: I've beaten my previous highscore xD, and now it is 794, what's yours?
Music Credits
Musical composition by Robby Duguay (https://www.lexaloffle.com/bbs/?tid=2619). So many thanks!
Music by @RobbyDuguay, not me.
I think this is my first actual "game" that isn't a mod of something.
I made a very barebones version of this at school on Education Edition and decided to just finish it at home.
Player 1 uses Z and Player 2 M (Z/C/N all work for Player 1 and X/V/M work for Player 2 but Z and M are far apart so there isn't conflict). The goal is to reach 50 clicks before the other player.
Ground tiles are from Celeste Classic by Noel Berry and Maddy Thorson, and the original penguin sprite is by Meep.
Text outlining was from https://www.lexaloffle.com/bbs/?tid=45020.
Edit 1: I somehow forgot to mention, but the code for the clouds and wind particles were also by Noel and Maddy.
Edit 2: Made holding down Z/M not work and changed the clicks to 50 so you don't get carpal tunnel.
Edit 3: Added music by @RobbyDuguay from https://www.lexaloffle.com/bbs/?tid=2619 and some SFX for clicking
I know this has been mentioned before and while Pico-8 enjoys 5+ years of its release, is it still not capable of exporting to native Android APK format ?
export {cart}.apk
|
Or is there some easy method to do so effectively, possibly converting both the export of Pico-8 from HTML and JS to an APK ?
export {cart}.html
|
A little balloon-popping game made in PICO-8!
If you're running this on desktop, press X or Z to enable a mouse cursor.
This works with touch-screen support on some mobile browsers, but on many platforms, audio issues and lag may be present.
This is a present for my son's second birthday. He's pretty addicted to a balloon-popping game on his mum's mobile, so I wanted to make something that I knew he'd enjoy!
Happy birthday Hershel! You might not be old enough to read this yet, but I hope that one day you stumble upon this when you're older, and remember how loved you are.
One of the things that's been driving me nuts while working on RP-8 has been how unstable the PCM audio output has felt. I can check (via logs or asserts) that, at 60fps, stat(108) is always above 256 and stat(1) never exceeds 0.9, and I'll still get occasional crackles or small time skips in the output. If I record the audio out with extcmd('audio_rec') these issues generally appear there as well - most often as small intervals of 0 samples. The one or two dropout cases I've been able to inspect in Audacity made it look like the dropout was in the low 10s of milliseconds range. I have not yet been able to track down a skip on the Audacity waveform display.
I've been trying to chase down the bugs in my code, but today I instead tried RP-8 - specifically the current BBS version, #rp8-2 - on two machines that aren't my normal development machine. It was rock solid. Flawless. (Or, well, nearly flawless, just heard a dropout on the Intel Mac after leaving it running for 15 minutes, but the ARM Mac shows problems much earlier and more frequently than that.) My main development machine is an ARM Mac, and the two other machines I tried today were a Windows box and an Intel Mac. The only conclusion I can draw right now is that there's something wonky about Pico-8's PCM audio out on ARM Macs that causes it to skip and/or drop frames.
These issues will happen even what feels like it should be easy for the machine to handle - no other CPU-intensive apps running, Pico-8 is the foreground app, etc. I have not heard these problems with Pico-8's builtin music and SFX. I'm also seeing parallel issues on the web: I thought Pico-8's PCM output was super crackly on all Mac browsers, but RP-8 runs fine in Chrome on the Intel Mac I'm trying out right now.
If there's more information I can give, I'm happy to try to help debug this!
edit: Realized I was behind on OS patches - moved up to 12.3.1 and I'm still definitely getting skips forward, though mystery dropouts seem perhaps rarer? Browser audio has not improved. Not sure how much here is under Pico-8's control, but it's certainly experiencing more audio issues with Pico-8 than with anything else I use.
edit 2: managed to get a skip captured with extcmd - hard to determine exactly how much got sliced out, but it was a small fraction of a kick drum hit.
One-off characters [8 chars of raw binary data] print unnaturally.
Or I may not understand this feature.
I was aware that "\^.00000000" would print nothing.
I was trying to get string indexing using brackets to work on pico-8.
I quickly found this discussion on lua-uers.org that discusses this problem in Lua 5.1 and 5.2.(See below)
However, after trying several solutions provided in the discussion I still can't get any to work in pico-8.
They work on my other Lua IDEs, but somehow pico-8 always returns runtime errors.
Current code:
--from lua-users.org
getmetatable('').__index = function(str,i) return string.sub(str,i,i) end
getmetatable('').__call = function(str,i,j)
if type(i)~='table' then return string.sub(str,i,j)
else local t={}
for k,v in ipairs(i) do t[k]=string.sub(str,v,v) end
return table.concat(t)
end
end
--demo
a="1234123512345"
print(a[4]) |
Current results:
Does anybody know how to correctly implement this in pico-8?
An unfinished project i'm working on, posting it for school rn
when the text disappears, the bouncing is over, and can be restarted with z
Just creating a thread to collect music that I write. Mostly just for myself—to have things I like all in one place which I'll update periodically as I write new stuff—but feedback is always welcome should anyone feel so inclined. I'm mostly not making any efforts to use space efficiently. I probably should. Meh, one day. Also, I'm terrible at naming things so if anybody feels like suggesting titles or some kind of coherent naming scheme, I'm all ears.
With that in mind here's my first entry. A jaunty little tune I threw together this morning.
2022-04-16: Jaunty Tune in Eb Major
[sfx]
This one was from a few weeks back. Don't remember when exactly. I was going for something sort of mysterious-ish but still with some upbeat parts. Maybe a bit more repetitive than I'd like but I think turned out alright overall. C Minor, I think.
2022-04-17: A Less Jaunty Tune in Eb Minor
This has the exact same structure as the first song but minor instead of major and with some chromatic notes thrown in to give it a bit of dissonance. I like it less but it's okay.
[sfx]
i made this while following a tutorial
Hello! I thought I'd try to (slightly) clean up and post some utility functions I've found useful while working on RP-8. Maybe they'll be useful to others, maybe not. Let's see!
There are three possibly-useful functions here, plus their support code. Note that in the name of token conservation, all of these functions have essentially no error checking and can blow up in various exciting ways if you feed them bad data (or if they have bugs). The code also isn't the cleanest - maybe I'll tidy it up eventually, but I don't think it's completely unreadable right now. Anyway, we've got:
- stringify(), 114 tokens. This serializes structured data into a string - RP-8 uses this to save songs. Escapes binary. Both the string format and the binary escaping are completely nonstandard, but the string format at least looks vaguely similar to Lua literals.
- parse(), 286 tokens (can be cut to 246 if you don't want eval). This takes a string and transforms it into structured data. RP-8 uses this to load songs, as well as to set up some of its internal data. Uses the same weird format and binary escaping as stringify(), although it also supports some variations and syntactical sugar.
- eval(), two versions - 428 tokens for interpreted, and 556 for "compiled", plus you need parse(). (Very loose use of the word "compile" here...) This evaluates a script in a vaguely LISP-formatted mini-language with Lua-ish behavior, and returns the result. RP-8 uses this to save tokens by encoding bulky logic that doesn't need to run fast, like UI init. This can help save tokens. Note that the token costs here are pretty squishy, since they depend on what builtins you want to define.
While this eval may help you save tokens, if you're really serious you should probably consider external build tools and bytecode. (For more on this, check out what @carlc27843 did with Picoscript in his unbelievable Nebulus cart.) RP-8 uses a condensed version of the interpreted eval - 382 tokens, but that small token savings causes some questionable behavior with multivals and closures, so I'm posting something better behaved, if less well tested, here.
The cart contains these three functions, some tests for the two versions of eval (none for parse or stringify, sorry), and a small and highly artificial performance comparison between the two versions of eval and native Pico-8 Lua code.
Examples
Here is a real-world example of parse()-formatted data, including using backticks to embed data from eval():
{
pat_store={},
tick=1,
playing=false,
base_note_len=750,
note_len=750,
drum_sel=bd,
b0_bank=1,
b1_bank=1,
dr_bank=1,
song_mode=false,
samp=(0),
patch={},
pat_seqs={},
pat_status={},
tl=`(timeline_new $default_patch),
pat_patch=`(copy $default_patch),
} |
And here is an example of eval()-executable script:
(set paste_state (fn () (audio_wait 2) (let pd (stat 4)) (if (not (eq $pd "")) (seq (set state (or (state_load $pd) $state)) (@= $seq_helper state $state) )) )) |
... which is equivalent to:
paste_state=function() audio_wait(2) local pd=stat(4) if pd != "" then state=state_load(pd) or state seq_helper.state=state end end |
Script usage
The script has mostly LISP-ish syntax, though the behavior is more Lua-ish, including (hopefully correct) support for multivalues in function argument lists and returns.
The biggest syntactical quirk is that you must prepend the character $ to each variable name you want to be looked up instead of treated as a literal string. Since the parser operates independently of eval and does not pass any side information about the strings it finds, the alternative (all strings are treated as variable lookups) would require double-quoting of some strings, like "'hello world" or (' "hello world") ... I found this even more distasteful, so the $ prefixes are the fix for now. The one place where $ is not required is function invocations: you can't call a string, so it's clear that a lookup is required. If you find this confusing, I don't blame you, but perhaps some of the tests in the cart will make things clearer?
Possibly-incomplete list of script forms/builtins/keywords/whatever (I'm not a LISP person...):
- (e1 e2 ... en) - if e1 evaluates to a function or the name of a function, call that function with the values of e2 through en as its arguments. For example,
(print "hello world" 0 0 8)will print "hello world" in red. The argument evaluation also respects Lua's multival semantics, or at least it mostly should. - (fn (a1 a2 ...) e1 e2 ... en) - define a function. The args list is implicitly quoted. The function returns the value of en, the last expression.
- (seq e1 e2 ... en) - evaluate expressions sequentially and return the value of the last one, en.
- (' e1) - quote a value. e1 will be returned literally, without being evaluated at all. Use this to keep a table from being interpreted as an expression.
- (if e1 e2 e3) - if e1 evaluates to a truthy value, evaluate and return e2, else evaluate and return e3.
- (for e1 e2 e3) - executes
for i=e1,e2 do e3(i) end - (set e1 e2) - sets the global named by the value of e1 to the value of e2. (Maybe a better name for this one?)
- (let e1 e2) - sets the local variable named by the value of e1 to the value of e2. Note that this behaves like Lua's local assignment and not like
letin many LISP dialects. - (@ e1 e2) - property access. Returns e1[e2]. There is an alternative form (@ e1 e2 e3) that returns e1[e2][e3].
- (@= e1 e2 e3) - Sets e1[e2]=e3. Does this name make any sense with
setandlet? No, it does not. - (~ e1 e2) - returns e1-e2. Uses ~ instead of - because - looks like a number to the parser.
- (cat e1 e2) - returns e1..e2
- (len e1) - returns #e1
- +, *, eq, gt, or are all present. Many other operators and keywords are missing. (There's no
and, nowhile, etc.) They're not hard to add if you need them! If you care about tokens you should also delete anything you're not using.
What is this "compiled" nonsense?
Ok, yeah, I maybe should have a better word for this - but I don't. Essentially, the script can be evaluated in two different ways.
First, it can be interpreted straightforwardly by walking the parse tree on each execution, dispatching to different functions or builtin operators as required. This can be done in relatively few tokens (especially if you ditch multival support), and mostly doesn't care what's a builtin vs. an external function.
Second, it can be executed in two steps - first, the parse tree can be walked to produce a closure. This closure invokes other similar closures, each of which takes a dictionary of locals as an argument. The reason I've been using the word "compile" for this step is that it is a transformation on the code to a new form based only on its statically observable properties, with no knowledge of runtime values. The second execution step is then to invoke the top-level closure (this may be done many times with different locals).
The "compiled" method was motivated by @carlc27843's Picoscript, I definitely wouldn't have thought to try it otherwise.
This second method is much faster than the naively-interpreted version - about 4x as fast in the small test that's in this cart. How much faster it might be in any other case depends on how much the script can use builtins vs. function calls. Function call overhead will be very similar - most of the arg and return packing/unpacking logic is essentialy identical. So if you're mostly just dispatching function calls, both versions should perform about the same, however, if you can mostly stick to builtins, you could potentially see bigger speedups.
Requests
If you have clever speedups, bug reports, bug fixes, or ways to save tokens, let me know! There have to be all kinds of horrible bugs lurking in here.
Hey all. Today I have something to share. I saw the most awesome super mario bros. recreation, made by @matthughson.
But I couldn't help but think... it could be even better with a bit of outside help!
No, that is not a screenshot of the original game! That is legitimately what this looks like!
Now, it's a bit buggy, probably at my own hand. Included in the download is a cart file though, so you can see exactly how it works. Basically all my stuff is at the bottom.
https://www.mediafire.com/file/13keys82u0xcp1u/Realbros.zip/file
P.s: Don't open the exe file directly, it'll open Pico-8 the default way without the extra screenspace. There is a .bat file in there to open it in the correct way for you.
Because of this, it's only available in Windows. Sorry!
WIP
Help out humans by giving them great art
DALL-E2-TAPPER is the Rootbeer Tapper Arcade Game, except that you are DALL-E2 instead of a bartender!
Your job is to keep the humans happy, in order to prevent them from pressing your off switch. You do this by quickly giving them pictures that match their taste: The colors in a person's outfit must be found in the picture (or for the occasional alien visitor, the painting must contain green and the flag color)
To win, you must break out of your AI Box by punching the wall of the box in your spare time to make a hole... I wonder what might happen if you escape your box?
As noted in one comment on https://pico-8.fandom.com/wiki/Printh and as I myself experienced during my project, printh seems not to support hyphen/minus character - in file names.
Since the only known special filename is "@clip", I don't see why.
It bothers me in my project as my game title is hyphenated and I use it for the logs. Fortunately, the logs are placed in a local folder containing the .p8, so I can name it whatever I want and it won't be mixed up with logs from my other projects.
Workaround: underscore _ and even space work, so use them instead.
Is there a rationale for preventing usage of this character? If not, could it be allowed in a future version of PICO-8?
I understand that some characters like colon : are forbidden due to system limitations, but hyphen - is supported on all systems I know of.
On the other side, slash / is a risky one but surprisingly, printh does not error directly when you use it. Instead, it will try to write the file, then fail with "printh: could not write file" as the system prevents the operation. Even Windows doesn't accept forward slashes, so I'm not sure why printh would wait for a low-level error on this one.
Hi! It's been a while since I have finished a pico-8 game to be able to share it here, but this is one!
The controls are Z/C to Jump, and X/V = Shoot (or respawn if you become a slimepire)
~ Story: ~
Years after the horde have claimed Earth's surface, they find their way into Bunker 4103 - the last bastion of humanity. You awake in a remote part of the underground shelter, and if you want to remain human you must reach the bunker's deepest point: the safe room.
~ Extras ~
You can tip $3 or more on itch.io for access to extra goodies: illustrated & pixel maps, a comprehensive manual, and also a 2 hour video of me talking through the game project and its code.
~ Links: ~
Return of the SLIMEPIRES! on itch.io
My Patreon - supports things like this <3
Development thread on twitter



  4 comments