Hi,
I just discovered the Pico-8 virtual console yesterday. I love the concept of a very constain console, and the presence of a fully integrated development platform.
It will be a fun way to create mini-games and prototype puzzle games.
For testing purpose, I just wrote a 'light cycles' game.
You can use the cursor keys to move around.
At each level, either there is an additional competitor or the speed of the game is increased.
Sorry, no sound nor fancy graphics for the time being.

I've been thinking about how PICO-8 could provide very primitive 3D software rasterization capabilities that remain within the spirit of the system. These are just goofy ideas, please feel free to bury them if they're too far outside the project scope, but I had to at least write it down once.
In any case, it should be possible to implement nearly all of the features below in a cartridge.
Following things need to be implemented in order for this to work:
- Mesh ROM
- Mesh editor
- API functions
- Z-buffer
Mesh ROM specs:
- 128 meshes (or less? animated meshes are considered here)
- per mesh: 16 vertices, 16 quads (96 bytes)
- index of 8x8 sprite to use as texture / colormap
- Vertex format: 3x(0..7) position
- Quad format: 4x(0..15) vertex index, 2x2x(0..7) uv rect (x1,y1,x2,y2)
0 = no quad
The editor would get a new page with an editing view (64x64) that supports two modes: mesh editing and uv editing.
mesh editing:
- The view supports free (orthogonal) rotation to preview the result and select obstructed vertices/faces.
- An extra label displays the index of the selected vertex or face.
- A toggle switches the view mode: textured / wireframe.
- left-double-click creates a new vertex.
- left-click selects a vertex or a face (depending on proximity of cursor to edge of face).
- right-click on a vertex begins to build a face; 4 vertices of which at least 3 are unique need to be right-clicked in succession to complete the face; right-clicks that don't hit vertices are ignored. a left-click will abort. If the 4 vertices already comprise a face, the operation has no effect.
- left-drag moves the vertex or face (all vertices of the face) along the orthogonal plane that's best facing the camera (dot product of view normal and plane normal closest to -1). That way no explicit orthogonal view is necessary. If a vertex is moved onto the position of another vertex, the vertex will be reset to its original position. That way, overlapping vertices are avoided.
- right-drag orbits the camera around the center, and implicitly selects the plane along which vertices and faces will be moved when editing.
- DELKEY removes the selected vertex or face. face removal does not remove vertices.
- the mesh can be copied/pasted to other slots in order to facilitate the creation of animations.
uv editing (allowed when a face is selected):
- The view shows the default 8x8 texture for this mesh, with a rectangle indicating the region that the active face will be mapped to. If only three vertices of the face are unique, the face will be a triangle (x1,y1 - x1,y2 - x2,y1).
- Per default, the face is mapped to the entire texture.
- x1,y1 are rounded to the upper left edge of the texel, x2,y2 are rounded to the lower right edge. That way, a single texel can color the entire quad.
- An extra panel allows selecting the default texture this mesh will use.
- left-drag draws a new rectangular bounding box for the quad. A simple left-click selects a single pixel as the quads texture.
The API gets 6 new functions:
clsz()
- clears the z-buffer to 0 (see Z-buffer notes further below)
zget(x,y)
zset(x,y,z)
- get or set the z-value of a z-buffer pixel.
camera3d(<x>, <y>, <z>, <m00>, <m01>, <m02>, <m10>, <m11>, <m12>, <m20>, <m21>, <m22>,
Save humanity from extinction:
Shoot and Cross your beams to destroy invaders!
- Up/Down to move BLUE shooter
- Left/Right to move YELLOW shooter
- Their intersection is a GREEN beam
- Z to shoot
- Kill the enemies with the righ beam color or they will spawn 2 other enemies! (killing a blue or yellow enemy with the green intersection = fail)
POST YOUR HIGH-SCORE
Feedbacks appreciated :)
Updated : added music made with a friend. Only problem : I forgot that I had SFX and he made a 4 channel music :s so I had to mute the drums... (at least I will not do that mistake again)
This is my first game with pico8, it was a lot of fun to do! I don't have a lot of spare time and Pico8 allows very short code/creation sessions! Thanks Zep!

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.
-
Jelpi is a pretty impressive demo, i love everything about this handheld console that never existed :D
-
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").
-
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. :-)
-
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.
-
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.
- 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.

Hello!
This is the prototype version of:
---- The Aggressive Botany League ----
a local multiplayer plant based deathmatch
Plant seeds into walls to push your opponent into the ocean (or to squish him!)
--- Controls ---
-
Movement
Player1: arrows
Player2: EDSF -
Wall breaking:
Face a wall and press Z (player2: TAB) 3 times to break it - Plant seed:
Face a wall and press X (player2: Q) to plant a seed into it
There are 4 types of seed (green, yellow, red and black) each with a different effect
You can carry only one seed at a time
best played with 2-4 gamepads
enjoy!
A toy that pokes the sfx RAM full of random garbage and lets you play the results on multiple channels. It'll mostly sound like generic computer ambience from an old educational film.
The randomly generated sounds will be stored in the ROM on startup, so comment out the cstore() at the end of the _init() function if you want to save your sounds for posterity's sake.
Disabling a single channel should technically stop playback on that channel, but it occasionally won't. This might be due to the weird looping points that the program generates for each sfx.

So I'm getting ready to make a new game, in which the player will be able to push other objects around in an AOE.
I have a table, ACTORS, which will hold all my actors; each one will have x/y coordinates.
So, to get everything within radius R of point X, Y:
function get_near(x,y,r)
for i in all(actors) do
--use some math to get the hypotenuse
vx=i.x-x --get the distance on X
vy=i.y-y --same for Y
--SOME TRIG GOES HERE
--Sorry, still a little fuzzy on my trig
if(result<r)then
add(list,i)
end
end
return list
end
|
Which would return a list containing...what, exactly? This is where I run into the problem.
If adding an item from one list to another copies the original to the new list, then I get a list of actors that's basically useless--I can't push them around, because if I do anything to list, it won't affect actors.
However, if adding an item from one list to another creates a pointer to the first list, then I'll be able to use this to conveniently push stuff within a certain distance.

you are a duck!
z to sprint, x to quack (this will be tied to an eating mechanic later)
Spent a couple of hours working on this today once I realized I had access to Pico-8 :D.
Once time runs out, nothing happens. There is no score yet. You have three lives with no way of losing any of them.
There are no goals except for being a duck.
No real gameplay yet, but I'm posting it here to force myself to update it and to keep working on it.
Limitations always make me think about breaking them, and when last time I realized that you can “load()” cartridges while your program is running, that seemed something exploitable :)
So here is one way to circumvent the limitations somewhat: You can only fit one “fullscreen” picture in the gfx space in pico-8 - BUT the cartridge change and load is fast (at least compared to changing a physical cartridge :) ) so what if I put more pictures my program need in other cartridges, and load when I need?
Turns out it can be done. :)
Here is a demonstration: a “fullscreen” anim player. It reads the frames from the cartridges in the “frames” directory, and copies the contents to the screen.
It is not that fast as I hoped to be, but it is still useable. It plays an animation with no problem, and with some planning it should be useable for other purposes too (while something else is still happening on the screen, like a game for example :) )
As the screenshot shows: it consumes 96% of cpu time, but only in the frame when the load and refresh happens. (I refresh every third frame, that’s how the average is around 32% - two frames with zero cpu load, one with 96%).
In theory you could spread the cartridge load and the refresh to different frames, but unfortunately the load is not “silent” (it prints a message to the screen), and that scrolls/writes in the picture. I couldn’t come up with a way to hide that yet, but the separete load/update lowers the max cpu usage to 49.6% (the average is stays the same, because now we have one frame with zero, and two frames with roughly 49%).
But of course an animation player is really the stress test of this technique. Apart from… you now, actually playing animations (like intros or something) you don’t really need to refresh that fast probably, and loading data from other cartridges can be used a number of different ways: backgrounds for an adventure game or transition screens, or replacing the tileset for an another world in the game, etc.
I have the sample for you to download (I don't think it will work in the web player), but it seems that I can't post any links in this forum, so please go to my blog post on tumblr and download from there if you want to check it out: http://blog.ccatgames.com/post/118623662172/still-playing-with-pico-8-limitations-always-make

Might as well call this the finished version, since barring optimization and cleanup I'm out of space.
CHANGES:
-There wasn't really much point in moving away from your opponent, so backward movement has been replaced with a longer backstep that can be used to avoid attacks
-Tweaked a few pixels
ADDED:
-Logo graphics
-2 new backgrounds (chosen randomly for each round)
-Randomly generated character appearances (loser's character gets replaced after each round)
-Characters now have shadows
-1 new music track
-Options menu to change/disable the music and choose between 3 CPU difficulty levels
FIXED:
-Player 2 could still go slightly outside the screen's bounds
KNOWN BUGS:
-There's a certain set of inputs that will prevent a character from going into the win pose after knocking an opponent out, thus being able to move around freely and preventing the round from ending. I have no idea how to do it apart from buttonmashing. The CPU will occasionally manage to do this, since technically it's constantly buttonmashing. Don't think of it as a bug, think of it as the ultimate victory celebration!






4 comments











