Skip to content

Instantly share code, notes, and snippets.

@lucatronica
Last active January 27, 2022 22:25
Show Gist options
  • Save lucatronica/90889918a87dce4719d2fc8e7a5a3a6c to your computer and use it in GitHub Desktop.
Save lucatronica/90889918a87dce4719d2fc8e7a5a3a6c to your computer and use it in GitHub Desktop.
-- Color palette.
pal({131,3,139,11,138},1)
-- Set dither pattern.
-- `▒` is a global variable inserted by PICO-8 that has the value 23130.5.
-- The value corresponds to a fillp pattern that looks like the glyph itself.
-- We need to floor ▒ to remove the .5, which signifies the pattern should be transparent.
-- (`\` is PICO-8's integer divison operator. So `x\1` floors the left operand.)
fillp(▒\1)
-- Get a random number. Passing -1 will generate nearly any PICO-8 number.
r=rnd(-1)
-- Make short alias for sin.
f=sin
-- Render 151 frames.
-- Once this loop ends, we call `run()` to restart the application, which will
-- generate a new point of view thanks the previous `rnd` call.
for i=0,150 do
-- Camera rotation. Use random initial offset and increase over time.
-- ▤ is a PICO-8 global with the value 3855.5.
a=r+i/▤
-- To maximise performance need to use local variables rather than globals.
-- (Globals use a table lookup.)
-- `c` and `s` save the `cos(a)` and `sin(a)` values.
-- `u` and `v` will be used for world space coordinates.
-- `h` will be used for terrain height.
local c,s,u,v,h = cos(a),f(a)
-- Iterate pixels on the screen.
-- Each pixel will be transformed into world space, and we'll draw each point
-- as a section of terrain.
--
-- Note we extend past the bottom of the screen to ensure we render terrain
-- that originates from below the screen and is still visible.
for y=4,156 do
-- It's not possible to render 152*127 points in one frame, so we split them
-- over 6 frames. We render every 6th column, and change the offset by 1
-- every frame.
-- This causes some ghosting, but a slow camera hides most of it.
-- (This also causes the nice Windows Movie Maker transition between runs!)
for x=i%6,127,6 do
-- Convert screen space to world space (orthographic).
-- Note: x/5-13 ≈≈ (x-64)/5 (tilts the camera up)
u=x/5-13
v=y-90
u,v = (c*u - s*v+r)/5,(s*u + c*v)/5 -- Rotate and scale!
-- Get terrain height from world (u, v).
-- I found that frequency-modulation (using sin inside of sin) was a nice
-- simple way to get varied terrain.
-- The `3.2` was chosen so that `h` can be used directly as a color value.
h=3.2
+f(u/8 + f(u/9 - v/7)/3)
+f(u/8 - v/9 + f(v/7)/3)
-- Draw terrain point as vertical line.
-- `h + .5` is the first dithered color value (offset by half).
-- `h\1*16` is the second ditherd color value (shift right by 2 and no offset).
-- Note: h\1*16 == (h\1)*16 == flr(h)*16
line(
x, y,
x, y - h*7,
h + .5 + h\1*16
)
end
end
flip()
end
run()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment