Log In  


So I finally had some time to play with Pico-8 yesterday, and wrote two tiny cartridges, and instead of spamming zep on Twitter I thought it would be more useful to post my thoughts here, in order of appearance.

  1. Jelpi is a pretty impressive demo, i love everything about this handheld console that never existed :D

  2. There should be a version of the manual that looks like a 90's devkit manual black & white hardcopy, with a serious layout like the devkit cost $10k. But this is a bootlegged copy of the manual, so it got xerox smudges, is not fully level and is obviously copied right out of a bound book, and right on the first page it says stuff like "FOR YOUR EYES ONLY. YOU ARE CONTRACTUALLY BOUND TO NOT DISCLOSE ANY INFO" etc. On the second page there's a pompous introductory text from the company founder that flaunts the pico-8's luxurious capabilities, telling you how you can be proud to be able to develop for this console and how it's lightyears ahead of the competition. The manual is not even a full copy, it seems like it's just the most important pages copied out; the pages are numbered like 110-112, 351, 430, with paragraphs that make reference to appendixes that don't exist ("see Appendix E for chipset layout").

  3. It's obvious that this pico-8 firmware is the devkit, which starts with a prompt. I imagine a "consumer device" would boot right into the cartridges. :-)

  4. First I thought Lua's numeric type had been downgraded to signed short, but then I realized it's actually fixed point 16bit for both integer and fractional part. Very cool.

  5. I'd remove all references to Lua and give this language a different name, e.g. Picoscript or Picolua; otherwise I'd just expect everything to work the same way; it's sufficiently different, i think. Considering how all the commands are named, PicoBASIC seems most fitting.

  6. I thought that it would be more useful to arrange the palette in a way that makes the 4-bits more significant (e.g. LRGB), similar to how the default EGA color palette is arranged. In EGA, bit 3 effectively changes brightness (sort of) without altering hue, that allows for very easy lighting tricks. The numeric bits correspond to RGB, so you can fake additive light effects with simple bit twiddling. Here, i'd ultimately do it with a lookup table; I guess it's too late to change it anyway.

  7. I missed a few important math functions, in order of importance: sqrt(x), atan(y,x), exp(x), log(x)

  8. The very first thing I attempted to write was a simple per-pixel fullscreen effect, and I ended up with a CPU usage of > x4. I have absolutely no clue which operations are how expensive, and it would help tremendously to have some sort of clock cycle table that shows which operations eat how much time. Do graphics and sound run on separate chips like with the SNES? I hope yes.

  9. The sequencer and tracker lack a copy function. It seems also despite the game controller correctly recognizing my german keyboard, the note editor does not take keys by scancode, and so Y and Z are swapped there. I can imagine french keyboards have it even worse.

  10. I missed file system operations for file rename and deletion.

  11. There's no quicksave shortcut, which made me very nervous. Ctrl+S has no effect. I hoped "save" without arguments would save the module to the last saved file but it had no effect either. I'm a "I need to save every 3 minutes" kind of dude, so that got annoying very quick.

  12. It would be cool to be able to load two cartridges, so one can act as an editor for the other one, so people can write alternative editors; The idea being here that the built-in editor could be implemented as a separate cartridge that makes no use of secret system functions.

  13. It would be useful to have primitive support for keyboard and mouse peripherals, like the editor has. Maybe as a special "devkit" mode that won't work on "consumer devices".

I'll also shortly post the first cartridges I did.

Cheers



"Picolus" is also a good language name ;)


  1. As mentioned in the manual, the # operator is broken (the only way to get the length of a string) because it doesn't work for the 16:16 numeric type, but shl(#s,16) fixes the issue and gives the proper value.

  2. Trying to write a more elaborate scrolling routine, I found that there seems to be no way to slice or iterate a string? s:sub isn't working, string.sub is missing.

  1. How and where to best store savegames? It would be nice to have a dedicated ROM area for that instead of eating from the asset space.

  2. A cart can load another using load() and run(), but there seems to be no way to pass on state? -- except for the screen page, perhaps, if it's not cleared. -- that does work, in this order: A) load new cart B) clear screen, write info into pixels C) run; it's also be possible to copy values into the other carts ROM at this point. I guess that also solves point 12. I also figured out that this way carts can use other carts as asset libraries. Good stuff.

16. How and where to best store savegames? It would be nice to have a dedicated ROM area for that instead of eating from the asset space.

0x4300...0x5F00 is user-defined data - you can peek/poke it and save() the cart to flush your changes into the cart file. It does seem a little weird, but I suppose that this is how it goes for now.


  1. the seed() function seems to be missing? I needed it a few times now.

[quote]0x4300...0x5F00 is user-defined data - you can peek/poke it and save() the cart to flush your changes into the cart file. It does seem a little weird, but I suppose that this is how it goes for now. [/quote]

the manual says that writing above 0x4300 would mess up the code ASCII. so i assumed 0x4300 was the upper limit.


Hey, thanks for the great feedback.

  1. Jelpi
    Cheers! It turned out to be a little too complex to learn from easily, so my plan is to finish it off as a regular cart and then make a simpler platform game for /demos/ to use as a template.

  2. Fantasy World Manual
    Yeah, that would be lovely :) Something to consider if there ever ends up being some official physical manifestation of pico-8. The cracks in the facade of pico-8 being a plausible historic machine show pretty fast if I try to explain anything too sincerely though!

  3. Devkit vs consumer machine
    Yes, this is my default story. But! Imagine if the editing tools were included standard, and save() means save to the cartridge currently physically in the slot. Then you can work on a game or some music and then take the cart and play it on your 6-button P8P on the train.

  4. Number representation
    The choice to use fixed point was partly because that's what Voxatron uses (which will be a host platform), and for better cross-platform determinism which might be handy later. Also I think less weird voodoo appears to happen for newer programmers.

  5. PICO-8's Lua environment is certainly quite different from most, but the implementation changes are quite shallow and I'd feel uncool calling it something new or that sounds like a fork. The main difference is the absence of the standard Lua library; I'm not sure how Lua programmers feel about this in general. Is it considered integral to the identity of the language?

  6. I shuffled the palette around a few times looking for something similar but thought there wasn't a nice 1-1 correspondence. The one you posted is quite nice! But yeah, a little too late to easily change now, heh.

Unfortunately there isn't much value in bit twiddling or even POKE()ing in pico-8's current state -- the binary functions are just regular calls with the usual overheads. e.g. it's actually faster to use x/2 than SHR(x,1) :( Something I'll review but it's at the bottom of the pile as it's quite hard to do properly and is only of interest to a small number of users.

One feature of the palette which is slightly useful is that the last 8 entries are in a vaguely loopable rainbow-like sequence. I use it for things like the trails in /demos/hello.p8 and /demos/jelpi.p8.

  1. sqrt() and atan2() are coming in 0.1.1. You'd have to sell me on exp() and especially log() -- could you give me an example of a cart that might use them? (I'm trying to keep the API tiny as possible)

  2. I didn't want to be too open about internal processing costs yet because they might change a little during alpha, which is a bit heart-breaking for any extremely optimized code. It runs at 4M lua vm instructions per second -- so about 8.5 per pixel per frame. Really not much. Operations like sprite blitting are assigned a cost equivalent to vm instructions. Sprite blits are 2 per pixel, so you can do about 4 full screens a frame. Stretch sprites are 4 per pixels, lines are 1 per pixel and memset / memcpy are 1 per byte (so 0.5 per pixel).

Lua can handle many more vm instructions per frame on a typical old desktop machine, but I'm keeping it quite low in the hope of supporting as much old/slow hardware as possible, and without needing to use LuaJIT. It's still /just/ possible to do games like wolf3d, simply 3d polys things and limited mode-7 ground, which I think feels about right in a fuzzy aesthetic way.

  1. Yeah the keyboard support sucks -- will fix this asap. Also, copy/paste/undo/redo for all the editing modes are arriving the next couple of updates.

  2. mv() rm()
    Wishlisted!

  3. Ctrl-S quicksaving is coming in 0.1.1 (along with automatic backups)

  4. Multiple carts open
    Hrm.. that's interesting. I had looked at multiple carts open thinking it's main use is making copying components easier, but I like the tools angle. One reason for allowing save() from within a running program is to keep it possible to write tools in pico-8 to do things like compress multiple carts of data to a single cartridge, then load back the editor. Or to edit data in a format not visualizable with the default tools (e.g. vector animation). I still need to clarify which parts of memory are clobbered during the loading/saving process and if it might be a sufficient solution.

  5. Mouse / keyboard support
    Possible in the future, but think the space of possible cartridges atm is fairly good, and don't want to fracture which carts can run on which systems too early (similar motivation for keeping the cpu speed quite low and standardized). Also, one of pico-8's primary objectives is to reduce decision fatigue in the process of making cartridges, which adding mouse and definitely keyboard would chip away at. I am thinking of adding a 3rd button though! (which means 'menu')

5.b Picolus also a good name for a Populous clone.

  1. operator: Buglisted

  2. substr() and len() are looking likely.

  3. Savegames
    I haven't decided on this yet, but I'm leaning towards making save data quite small -- around 16~32 bytes that are automatically mapped to permanent storage. Again, I think this cuts down possibilities in a good way, but I'm still open to negotiation!

  4. Clobbering memory on load()
    Ah.. I've messed that up. load()ing during execution shouldn't automatically copy anything to base ram (in order to do daisychain style tools). Also what YellowAfterLife said -- using 0x4300...0x5F00 for this purpose will be safe in future versions.

[quote]2. Fantasy World Manual
Yeah, that would be lovely :) Something to consider if there ever ends up being some official physical manifestation of pico-8. The cracks in the facade of pico-8 being a plausible historic machine show pretty fast if I try to explain anything too sincerely though![/quote]

it's a parallel universe. things moved a little differently there. e.g. lua is inspired by the pico-8's language, not the other way around!

[quote]6. I shuffled the palette around a few times looking for something similar but thought there wasn't a nice 1-1 correspondence. The one you posted is quite nice! But yeah, a little too late to easily change now, heh.[/quote]

indeed, the rainbow effect in the present table proved to be quite useful so far. and i recently realized the properties of the EGA table are not as great as i thought they would be, so forget about it. pico-8's palette is cute and fine.

[quote]7. sqrt() and atan2() are coming in 0.1.1. You'd have to sell me on exp() and especially log() -- could you give me an example of a cart that might use them? (I'm trying to keep the API tiny as possible)[/quote]

exp() and log() belong together; exp(log(x)) = x, and log(exp(x)) = x; also, they can be used in place of a pow function: pow(a,b) = exp(log(a) * b); exp() is a little faster than pow, and log(a) can be precomputed if a is constant. Also, log2(x) == log(x)/log(2), tells you how many bits are needed to represent x.

I tend to prevalently use it for 3 things, a) to compute frequency from pitch, pitch from frequency, b) db to linear amplitude and back c) for linear interpolation of zooming (needs to be done logarithmically to counteract the exponential nature of scaling)

I suppose for most cases people could just keep small tables in their programs, but those functions are a staple of every math library.

Alternatively, one could just provide the easier-to-implement log2(); when x is integer, exp2(x) is analog to shl(1,x) and needs no special function. with those two building blocks it should be possible to build a fast arbitrary pow() function for fixed point.

[quote]5. PICO-8's Lua environment is certainly quite different from most, but the implementation changes are quite shallow and I'd feel uncool calling it something new or that sounds like a fork. The main difference is the absence of the standard Lua library; I'm not sure how Lua programmers feel about this in general. Is it considered integral to the identity of the language?[/quote]

the lua library is as you may have noticed, very tiny. it lacks quite a bunch of functions, and the few that are there end up being rather essential -- that is, you can't emulate them with just the language itself. e.g. without string, which also provides the metamethods for string objects, there are no string operations, with the exception of ".."

[quote]Lua can handle many more vm instructions per frame on a typical old desktop machine, but I'm keeping it quite low in the hope of supporting as much old/slow hardware as possible, and without needing to use LuaJIT. It's still /just/ possible to do games like wolf3d, simply 3d polys things and limited mode-7 ground, which I think feels about right in a fuzzy aesthetic way[/quote]

It's a good choice. It would be nice to have at least an "overclocking" command switch to alter the cap in both directions, for experiments, personal prototypes, or even harder challenges (using a lower clock). I wanted to try a full signed distance field raytracer, that's impossible at the moment.

[quote]Also, one of pico-8's primary objectives is to reduce decision fatigue in the process of making cartridges, which adding mouse and definitely keyboard would chip away at. I am thinking of adding a 3rd button though! (which means 'menu')[/quote]

yeah, i thought the same, reg. fatigue. it's nice not having to care. the gameboy and nes both had a start/select button, but a single one would suffice to provide both pause and in-game menu.

[quote]16. Savegames
I haven't decided on this yet, but I'm leaning towards making save data quite small -- around 16~32 bytes that are automatically mapped to permanent storage. Again, I think this cuts down possibilities in a good way, but I'm still open to negotiation![/quote]

32 bytes sounds good enough. i have no real use case here yet. i'm particularly thinking of an adventure game. 32 bytes map 256 flags, in an adv game those would be shared for items you have, world state and explored dialog options. it sounds like that's enough flags for the pico-8.

[quote]17. Clobbering memory on load()
Ah.. I've messed that up. [/quote]

no, you didn't. i think it works as intended.

did you see point 18, the missing seed()?


I haven't ever used LUA before now, so there's been no gap of understanding for me so far... However - the lack of sqrt() was bound to catch up with me by the time of implementing 3d collision, so I'm glad that's being added. I haven't needed it yet, but asin and acos are also pretty useful... They are implementable in LUA as is but it would be a pain to work out from scratch.

As for performance, I agree that the Manual could use some extra information on API functions, and what specifically a LUA instruction is. (how many instuctions make up {x=2, y={3,4}}?) You mentioned that lines cost 1 per pixel, so where does that leave fillrect? How does that compare to cls/mcpy? So many important questions... 8O|

For bitshifts I've been tending to use mul/div instead of the provided functions simply because using a function seems like it would be slower... or just looks worse. I understand that LUA doesn't actually have bitwise operators, it's just a little annoying is all.

I have to admit, when I first heard of this I first thought that the code part was going to a fantasy assembly language like DCPU-16 was (for the short time it was a thing), but LUA is definitely more practical for the purpose of making games quickly- and makes it very game jam compatible.


[quote] I haven't needed it yet, but asin and acos are also pretty useful... They are implementable in LUA as is but it would be a pain to work out from scratch.[/quote]

you should never ever need asin() and acos() (avoid trigonometry, avoid storing anything in angles, use linear algebra!); if you think you do, explain your use case and i'll do my best to describe an alternative.


I haven't decided on this yet, but I'm leaning towards making save data quite small -- around 16~32 bytes that are automatically mapped to permanent storage. Again, I think this cuts down possibilities in a good way, but I'm still open to negotiation!

What about mini-city-building games though?
Or just allowing the player to build levels from in-game.

On performance, makes sense, though I agree with Rhys - raises even more questions since you don't quite see what your code becomes. Maybe some debugging tool would help in far future.


[quote]What about mini-city-building games though?
Or just allowing the player to build levels from in-game.[/quote]

that should go straight to the map memory.


@paniq: Specifically: angle difference using acos on dot product of two normals.


@Rhys: the dot product yields an unambiguous -1..1 value against which you can compare; e.g. instead of doing acos(dot(a,b)) < angle, you can use dot(a,b) < cos(angle). What else do you need the angle difference for?


zep said:
> one of pico-8's primary objectives is to reduce decision fatigue in the process of making cartridges

I love this aspect; as someone who typically stresses out about the details and gets overwhelmed with limitless possibilities to the point of not getting anything actually accomplished, I am finding that the limitations of PICO-8 are freeing me up to make something faster than I think I would be able to otherwise. Sorry it's sort of off-topic for this thread, but I just wanted to say thanks for the great design decision here :)


I second the addition of a menu/start button for the controllers.
A dedicated pause button is just nice.
I used to play on a Sega Master System back when and reaching over to hit the pause button on the machine itself was a pain.
One more button can't hurt I say.
Then perhaps a reset function if all keys are held down for a moment say if a keyboard isn't readily available.

Can't believe I missed the alpha release last month but I'm catching up with it.
Been really excited for this and throwing my spare Voxatron keys to get more friends trying it out.

If ya really wanna make a retro game you gotta make it in a retro way.
Just makes sense. xD

While I'm at it though I hope command line program loading/running comes soon as I'd like to setup some front ends like Launchbox or Anarchy Arcade to start games in fullscreen.
"Pico8.exe game.p8.png -Run -Fullscreen"
Perhaps a forced fullscreen mode could be useful with webplayer URLs for the same use though would hope that wouldn't get out of hand.

Either way, been way too excited for this darn thing as of late.
Hope it can get ported to all sorts of things one day. (Wii homebrew port maybe? Heh maybe not.)

I'm dying to try some concepts with this thing.
Now just to brush up on my coding skills, or lack there of.

Oh and one more thing, for tying two carts together, I'd suggest trying a password system for extra retro style.
Though a save file system would be best I suppose.



[Please log in to post a comment]