PICO-8 Program Structure
When a PICO-8 program runs, all of the code from tabs is concatenated (from left to right) and
executed. It is possible to provide your own main loop manually, but typically PICO-8 programs
use 3 special functions that, if defined by the author, are called during program execution:
_UPDATE() -- Called once per update at 30fps.
_DRAW() -- Called once per visible frame
_INIT() -- Called once on program startup.
A simple program that uses all three might look like this:
FUNCTION _INIT()
-- ALWAYS START ON WHITE
COL = 7
END
FUNCTION _UPDATE()
-- PRESS X FOR A RANDOM COLOUR
IF (BTNP(5)) COL = 8 + RND(8)
END
FUNCTION _DRAW()
CLS(1)
CIRCFILL(64,64,32,COL)
END
_DRAW() is normally called at 30fps, but if it can not complete in time, PICO-8 will attempt to
run at 15fps and call _UPDATE() twice per visible frame to compensate.
_UPDATE60()
When _UPDATE60() is defined instead of _UPDATE(), PICO-8 will run in 60fps mode:
- both _UPDATE60() and _DRAW() are called at 60fps
- half the PICO-8 CPU is available per
frame before dropping down to 30fps
Note that not all host machines are capable of running at 60fps. Older machines, and / or web
versions might also request PICO-8 to run at 30 fps (or 15 fps), even when the PICO-8 CPU is
not over capacity. In this case, multiple _UPDATE60 calls are made for every _DRAW call in the
same way.
Source code can be injected into a program at cartridge boot (but not during runtime), using
"#INCLUDE FILENAME", where FILENAME is either a plaintext file (containing Lua code), a tab
from another cartridge, or all tabs from another cartridge:
#INCLUDE SOMECODE.LUA
#INCLUDE ONETAB.P8:1
#INCLUDE ALLTABS.P8
When the cartridge is run, the contents of each included file are treated as if it had been
pasted into the editor in place of that line.
- Filenames are relative to the current cartridge (so, need to save first)
- Includes
are not performed recursively.
- Normal character count and token limits apply.
When a cartridge is saved as .P8.PNG, or exported to a binary, any included files are
flattened and saved with the cartridge so that there are no external dependencies.
#INCLUDE can be used for things like:
- Sharing code between cartridges (libraries or common multi-cart code)
- Using an
external code editor without needing to edit the .p8 file directly.
- Treating a
cartridge as a data file that loads a PICO-8 editing tool to modify it.
- Loading and
storing data generated by an external (non-PICO-8) tool.
Common gotchas to watch out for:
- The bottom half of the sprite sheet and bottom half of the map occupy the same memory. //
Best use only one or the other if you're unsure how this works.
- PICO-8 numbers have limited accuracy and range; the minimum step between numbers is
approximately 0.00002 (0x0.0001), with a range of -32768 (-0x8000) to approximately 32767.99999
(0x7fff.ffff)
// If you add 1 to a counter each frame, it will overflow after around 18
minutes!
- Lua arrays are 1-based by default, not 0-based. FOREACH starts at TBL[1], not TBL[0].
- @COS() and @SIN() take 0..1 instead of 0..PI*2, and @SIN() is inverted.
- @SGN(0) returns 1.
Although PICO-8 does not have a clearly defined CPU, there is a virtual CPU speed of 8MHz,
where each lua vm instruction costs around 2 cycles. Built-in operations like drawing sprites
also have a CPU cost. This means that a PICO-8 cartridge made on a host machine with a powerful
CPU can still be guaranteed to run (reasonably) well on much slower machines, and to not drain
too much battery on phones / when running on the web.
To view the CPU load while a cartridge is running, press CTRL-P to toggle a CPU meter, or print
out @STAT(1) at the end of each frame.