PICO-8 Tweetcart Studies

Back to main menu


Moon and Reflection

Author: Luca Harris (@lucatron_)
Link: https://twitter.com/lucatron_/status/1111025092236959744

Moon and Reflection

Summary

This cart is a made up of lot of lines of different lengths moving at different speeds (and wrapping back around to the left). The colour for each line is either 1 (the water colour), or the moon colour selected from the top of the screen.

srnd() seeds the random number generator on every frame, and this is used to get a set of random, but consistent, values each frame for each of the lines, their speeds, etc. It’s much easier and faster to do this than to e.g. generate all those values once and then store them in a table or an array.

Pictures

This is a slowed-down version showing how each frame is rendered.

This shows the midpoint and colour for each line (the effect with the width of each line being 0).

You can see how precise the reflection of the moon looks here. It just gets all jagged in the full effect because each pixel's colour is used for a whole line.

Tweet code

cls()
circfill(30,22,15,7)
::_::
flip()
srand()
rectfill(0,50,127,127,0)
for y=0,77 do
z=77/(y+1)
for i=0,z*8 do
x=(rnd(160)+t()*150/z)%160-16
w=cos(rnd()+t())*12/z
if(w>0)line(x-w,y+50,x+w,y+50,max(1,pget(x,49-y/2)))
end
end
goto _

Breakdown

-- black night sky
cls(0)

-- the moon
circfill(30,22,15,7)

-- start rendering loop
::_::
flip()

-- re-initialize the random seed each loop so that rnd
--  calls below will keep the same value.
-- we do this because we use rnd() in a loop from top
--  to bottom of the water to decide various things
srand()

-- cls() only the sea
rectfill(0,50,127,127,0)

-- loop from y=50 to y=127
--  (the draw calls below use y+50 everywhere)
for y=0,77 do
  -- how wide the reflection lines at this level are.
  -- in the distance they're super short, and they get
  --  longer as they come closer 77 -> 0, ~exponentially
  z=77/(y+1)

  -- z*8 random lines per y
  --
  -- some of these overlap and are going different
  --  speeds, which helps sell the shifting water effect
  for i=0,z*8 do

    -- x position of this line
    --
    -- rnd(160) is the base speed, and because we always
    --  seed using srand above, this stays the same for
    --  each line (better than generating the rnd values
    --  once and storing them in a table or an array).
    -- t()*150/z just makes it move, /z means slower
    --  near the horizon.
    -- %160 means that it'll loop back to 0 once it hits
    --  160, each line just loops.
    -- -16 so that rather than the full lines popping in
    --  on the left, they slide into the frame nicely
    x=(rnd(160)+t()*150/z)%160-16

    -- the width of the line, standard random-ish cos()
    --  that's smaller towards the horizon
    w=cos(rnd()+t())*12/z

    -- only draw when the width is over zero, fun~
    if (w>0) then
      -- max(1,pget(x,49-y/2) means that the colour will
      --  always either be 1 (water) or the grabbed
      --  pixel colour from top.
      -- note: the 'reflection' of the black sky is
      --  really just the lines not filling in the
      --  rectfill from above.
      --
      -- because x is random and the line is the same
      --  colour the whole way through, it creates real
      --  interesting shimmery reflections. this only
      --  looks good because the x-w and x+y means the
      --  colour is grabbed from the middle of the line
      line(x-w,y+50,x+w,y+50,max(1,pget(x,49-y/2)))
    end
  end
end

goto _