This is my first try at a metaballs effect in Pico 8. A bit disappointing: too much noise. Maybe I should consider using ordered dither instead of random noise. Doing internal calculations at a higher precision and then converting to 16 colors is also an option, but no way to make it work @60fps fullscreen.
I have just noticed there's a previous cartridge which did a very good job drawing metaball outlines: Metaballs (Demoscene Effect) by samuelks
![](/gfx/set_like0.png)
![](/gfx/top_drop.png)
I was looking at this and said NO WAY. Then I thought about it and said, Oh I bet he's using all the sprites to save his ball in. Then mirror the x & y randomly to give it some character and then just SSPR() the lot of it to the screen.
And I was right ! :)
Sure would be nice if we could:
scrn={} memcpy(@scrn,24576,8192) |
![](/gfx/set_like0.png)
![](/gfx/top_drop.png)
Not exactly. Sprite mem is very scarce and with "metaballs" this big I need lots of memory, so number arrays in LUA memory are used instead. Pico 8 "GPU" has no "adding colours" mode so it has to be done the brute force way. First, I precompute 8 ball things with different horizontal shifting due to 32-bit alignment (8-pixel packs), and values 0-5 adding some nasty white noise dithering to reduce banding. Next, I take the results to LUA arrays using PEEK4(), 8 pixels per array element (8x4bits = 32 bits). Every frame, center positions are updated, and a lot of 32bit sum operations between array elements is done taking care that no individual 4bit pixel overflows (worst case 3x5=15 so it's safe as there's no overflow to neighbour 4bit pixel). In the end, the results are taken to sprite mem just to apply custom palette and apply transparency, but I forgot to include a background image, so this step can be skipped and results could be transferred directly to screen mem.
In the code there are 2 functions similar to what you suggest, but they transfer images from sprite/screen memory to LUA arrays (GRAB) or the opposite (RESTORE). They are at the beginning of my code.
![](/gfx/set_like0.png)
![](/gfx/top_drop.png)
Phew ! That's over my head. I might be able to do something similar ... Let me see ...
Yeah, it's not quite the same. Not bad for a first attempt though, maybe. :)
[Please log in to post a comment]