I'm a prematurely-retired professional video game programmer. I have some health problems that ruin my concentration and keep me from doing the kind of programming people will pay you for. PICO-8 is really nice for me, because the limited scope of the platform tends to keep the scope of problems and solutions limited enough for my limited concentration to cope with. I don't think I'll ever manage to produce a game for PICO-8, but it sure is fun just to play with.
(If I've just handed you some ideas or advice, probably for the fifth time this week, and you're getting sick of my doing that, then I have a couple of things I should say: first of all, you should let me know, because I know unwelcome advice is annoying and I don't want to be annoying; but also, second, try not to be too irritated with me, because giving advice is the only way I still feel like I can be a productive member of the video game developer community. I mean well, I swear.)
Oh, and about the avatar... once upon a time, I chose a nice little image of Miku in glasses for my avatar, purely because it struck me as adorable. However, I kept it because I discovered it kept away those useless people who would judge a book by its cover. This is that avatar, but hand-pixeled into low-res, pico-8 palette format.
Presently, to load+run you literally have to load blahblah.p8 and then run.
Would it be a bother to run the "run" code through the same line parsing that handles "load", and then auto-run it afterward?
I ask because I was running a bunch of local carts from the command line and it was a tiny bother to have to do two steps each time.
...YES, I realize this is a very minor thing, but hey, why not mention it? The worst that happens is that it doesn't get implemented, right? XD
... uh... r—right...?
If we type "x = -6", the "-6" part requires two tokens, which I assume is because the version of Lua you use was still internally treating negative literals as positive literals with a unary-minus operation applied to them, e.g. "x = unm(6)".
However, using a negative literal in PICO-8 appears to have the same cycle cost as using a positive literal, as far as I can tell with my benchmarks. For instance, "x = y / -6" costs the same as "x = y / 6".
So basically we're being charged a token for an operation that doesn't actually seem to occur, and really shouldn't need to occur anyway.
Would it be possible to delete the token cost for unary-minus if it's being applied to a literal?
The alternative is that people in dire token straits will write "x = y / 0xfffa", which is just gross. :P
I think it's too late to suggest this, since you appear to have completely filled the printable characters with the kana glyphs, but just in case there's something to spare somewhere:
I just used one of the unicode thumb glyphs (👎,👍) and realized it'd be handy to have such glyphs in the PICO-8 character set.
I drew up some possible 7x5 PICO-8 glyphs for them:
You could type them with -/+ in glyph mode.
Even if they can't be fit into PICO-8 itself, the thumb-up might be good for the BBS, because I think a lot of people don't realize that's what the ★ glyph on BBS posts is for, given how seldom it seems to be used.
(I guess it's not a big deal if this isn't possible, though, since we can obviously just draw them manually.)
The built-in tuple "..." seems to confuse the syntax highlighter. Notice "END" isn't pink:
Not a big deal, but I figured you'd want to know.
Maybe a bug, maybe not. I just noticed that Ctrl+H goes to the start of the document (as with Ctrl+Home). On the other hand Ctrl+E goes to the end of the current line (as with plain End). Is this difference in behavior intentional? If so, no big deal. I just wanted to be sure it was intended vs. accidentally calling the wrong internal "home" or "end" function for one of them.
EDIT: Just as I posted this, I noticed that it's ^W/^E for line home/end, so I guess this probably isn't a bug. Disregard #2.
- fire up PICO-8
- switch to code editor
- type something like 123456789 and hit enter
- copy and paste that line few times to give yourself something to cursor through
- using the keyboard, navigate to the middle of one of these lines
- cursor up and down: should work normally
- click near the start or end of the line
- cursor up or down: will change the row properly but maintain the column from before the click
This is probably as easy to fix as just setting both the current and virtual column on mouse clicks.
Right now if you want to draw a line loop with the cool line(x,y) continuation method, you still have to do at least one line(x0,y0,x1,y1) first to make it work:
-- draw a simple triangle line(32,96,96,96) -- base line(64,32) -- right side line(32,96) -- left side
This isn't so bad if you're drawing the figure manually as I just did. But if you're, say, drawing an algorithmic figure's loop, you have to handle that first line conditionally within the loop:
-- draw a simple segmented circle local cx,cy,r=64,64,32 for a=0,1,0x.01 do local x,y=cx+cos(a)*r,cy+sin(a)*r if a==0 then line(x,y,x,y) -- sets the continuation point else line(x,y) -- continued from the last point end end
Or (not shown) you can remove the condition from the loop, but it requires doing math to get the first point outside of the loop and then calling line(x,y,x,y) as above before looping over the subsequent points.
All in all, neither is really better in terms of code than just drawing a series of distinct line(xi,yi,xj,yj) segments.
However, let's say line() with no args invalidates the last position. Let's also say that trying to continue via line(x,y) from an invalid position draws either nothing or just the one pixel, but it does update the last position. Suddenly everything gets a heck of a lot more concise and elegant:
-- draw a simple segmented circle local cx,cy,r=64,64,32 line() for a=0,1,0x.01 do line(cx+cos(a)*r,cy+sin(a)*r) end
This should be safe in terms of backcompat, because line() with no args doesn't currently do anything useful, and in fact I'd consider it an undocumented usage that would have been ill-advised to use anyway. Similarly, since there was no such thing as an invalid last point in the past, no one would have written line-continuation code that didn't first update it explicitly in a way that would still work with this change in place.
This call, with only one arg after the string:
print("hello world", anything_even_a_table_or_function_or_nil)
Behaves oddly and in a way that is not documented in the manual. It renders the string at the cursor and then exits without updating the cursor. It doesn't seem to use the extra argument at all.
The only thing I can see this being useful for is a text countup display, as seen in oldschool memory tests during BIOS startup on PCs. I can't imagine anyone has ever actually used it this way, though.
It'd be far better if this case were treated as if the user wanted the text colored, but didn't want to specify x,y coordinates because they wanted it to work like a regular, scrolling print():
print("I'm blue, da ba dee, da ba die", 12)
We had some back-and-forth on Discord about row-shifting effects and whether to do them with the CPU or by copying to sprite ram and using sspr. I came up with a pretty good function at the time for the CPU to do it in place, but I've since iterated on that to bring down the token count and also to optimize certain types of shifts.
This is a little demo wrapper built around that function. If anyone's interested in effects like this, I offer this up to them. Take a look at the full-fat version of the function in tab 1, and also at a low-fat version in tab 2, which is a little slower and lacks the edge-clamping feature, but uses about 2/3 of the tokens. You should be able to drop either version as-is into a game or demo and just use it right out of the box.
Performance: The full-fat version can apply a sine wave to the full screen at a cost of about 8-9% of a 30fps frame, while the low-fat version requires about 10-11%.
Token cost: The full-fat version is 155 tokens. The low-fat version is 96 tokens.
Limitations: To reduce token count and because this was written for someone to do a subtle water effect, I have no logic for shifting beyond +/-8 pixels (32 bits). It could be modified pretty easily to do so, it just doesn't right now. It would probably add maybe 1-2 dozen tokens to do so.
Is holdframe() intended to be a peer/complementary function to flip()?
I had it pointed out that I'd erroneously marked flip() as undocumented on the wiki, even though it is documented—I just suck at searching the manual. That reminded me to check holdframe(), to see if it was still undocumented, and it still is. It is, however, overtly called out in the changelog as having been added, so it's simultaneously documented and undocumented.
Is it intended that we're allowed to use it for custom game loops, or no? If we are, it'd be nice to have it documented in the manual. Otherwise I'll leave it in the nebulous wiki category of Undocumented API.
I discovered this while trying to reduce someone's not-quite-tweetcart, and I boiled it down to a simple repro case.
These compact lines both parse and function correctly:
But these don't:
Variable names don't seem to matter. I included versions with variable names swapped just so you know it's not the variable order at fault somehow.
Same thing happens both when executing editor/app code and at the shell prompt.
I tried on the BBS and the parser here isn't able to work it either.
I didn't try other operators, like *, /, or %.
Side note: On the same subject, would you mind adding ..= and ^= operators? I think that would make the set orthogonally-complete.
I was playing around with the slide effect on the volume for white noise and I realized that there was an awful lot of sputtering while it would ramp up the volume, but not while ramping down. It sounded as if maybe the waveform was being doubled in amplitude and thus clipping, or maybe something was messing up the randomizer. I really don't know. That's for @zep to figure out.
Here's a repro case, seems to work the same on the BBS as it did in the executable.
Pretty sure it's not local to my machine's audio hardware, but I'd appreciate others trying it and saying whether or not they hear the same issue.
Edit: Yeah, just checked out this post on my phone, it does the same thing there too. Definitely a bug.
Edit: Never mind, I think the sound driver on my system has some kind of volume compression enabled.
There seems to be something amiss with the SFX player code.
The cart below simply plays a single SFX. The SFX is a constant sine wave tone with a stepped volume envelope. The envelope steps up each half second, from 0 to 7, and then back down each half second, to 0.
On my PC, this results in the SFX immediately being nearly full volume, stepping up once, maybe twice, until it's actually full volume, and then remaining full volume almost until the end, when it then steps back down four times to medium volume and then abruptly turns off.
On the web player, it seems to be more symmetrical. I'm hearing it start at medium volume and step up four, maybe five times before holding steady for a while and then stepping back down four times to medium volume and abruptly turning off.
There was a discussion on twitter about not being able to get the stack trace for a dead coroutine, which is understandably frustrating. However, I was sure that I once figured out a way to do it, and I said so, but the code to do so is on a dead PC at the moment, so I had to spend some time figuring it out again.
This sample basically runs a coroutine that waits for 5 seconds and then does something fatal. Each frame it displays the known status and stack trace. Run it, you'll see.
I tried to set up the code to be as simple and understandable as possible, but if you have questions, please feel free to ask.
EDIT! For a VERY simple coroutine exception stack trace dump, see my follow-up post here
As simple as the subject.
- Write a cart that uses btnp().
- Run the cart.
- Press and hold a button to see it repeats.
- Hit esc to stop the cart.
- Enter 'resume' to resume the cart.
- Press and hold a button and see if it fails.
(Either that or key repeat isn't supposed to be a thing with btnp() and it only works right after you resume.)
This code is sufficient to show it:
boops=0 function _update() if btnp()!=0 then boops+=1 print("boop #"..boops) end end
Note: tested on win64 version.
The manual implies that the line-continuation syntax might allow for this...
line( 10,10, 20,10, 1 ) line( 20,20, 2 ) line( 10,20, 3 ) line( 10,10, 4 )
...which would make a rectangle with four differently-colored sides.
But PICO-8 seems to interpret line(x2,y2,col) as line(x1,y1,x2,0).
I can't remember if this was fixed the last time we reported it, but if it was, it's broken again.
Using backticks to insert inline code in text is broken, causing the entire remainder of the paragraph to be highlighted as code, even if the closing backtick is present.
For instance, this is how I'll write the next paragraph:
If this is already fixed, `this highlight should stop` <-- HERE.
If this is already fixed, this highlight should stop <-- HERE.
Also, just want to mention that I wish the inline code were simply a mono-spaced font, and not inverse the way it is now. It's visually jarring the way it is. :/
A tab character is supposed to move the cursor to the next column that's a multiple of the tab-width setting, but instead it just advances the cursor by tab-width columns every time.
In other words, it currently does this:
function do_tab() cursor_x += tab_width end
And it should do this:
function do_tab() cursor_x = (cursor_x + tab_width - 1) % tab_width end
I'm trying to write a tool that has text editing, and I find that the devkit keyboard doesn't return a lot of the special keys that it easily could.
You're returning a string, so there's no reason why it has to be just one character. So pressing the Home key could simply return the string "home". No need for special characters, escape sequences, etc., since these verbose names would all be distinct from any single regular typed character.
I'm mainly thinking of the standard navigation cluster: up, down, left, right, ins, del, home, end, pgup, pgdn.
It'd also be nice if there were a second stat() value that had a bitmask of the modifier keys that are currently pressed, if the host has them. Like, left/right shift, left/right alt/cmd, maybe left/right win/opt, altgr, maybe capslock. Not crucial, but definitely helpful. It'd be nice to be able to support things like ^Z for undo in my tool.
I say all this because one of the things I love about PICO-8 is working entirely within PICO-8, so it's nice to write tools that work inside of the platform, but the devkit functionality is a little limited in this department.
If I type this:
Look at my `inline code` please.
I get this, which I'm just going to let the BBS handle, so it might look right to anyone reading this after it's fixed:
Look at my inline code please.
The second backtick isn't closing the inline code.
As an aside, I personally would prefer it if inline code were simply a monospaced font, and not inverted as it is now. It makes using inline code very ugly and hard on the eyes. :/
I do like the old-printer-paper code block format though. :)
I notice Benjamin Soulé's username doesn't show up right, even after your emoji fix.
Looks like this at my end:
It seems to work fine inside this post's text though.
Edit: Yeah, there's some kind of encoding issue, not a font issue, because if I copy and paste it here, it still comes out "Benjamin Soul�", even though I was able to write it correctly above.
View Older Posts