All posts by lashdl

Sparks

We use the code from last tutorial.

Let’s extend our particle system with a new function:

explode=function(pcount)
  local cols={rnd(15),rnd(15)}
  local rndx=rnd(127)
  local rndy=rnd(127)
  local i=1
  while pcount>0 and i<maxparticles do
    local rndxs=rnd(10)-5
    local rndys=rnd(20)-10
    if _pool[i].launch(rndx,rndy,rndxs,rndys,cols) then
      pcount-=1
    end
    if (pcount==0) break
    i+=1
  end
end

In the above code we start by setting a color array with two values between 0-15 (max 16 colors in PICO-8 (standard colors)).
Then we set a random x-coordinate within the screen bounds and a random y-coordinate inside the screen bounds.
We then loop through the particles to get particles that can be launched (remember, if a particle has been launched it can’t be launched until it has left the screen on the y-axis).
If we find a particle we subtract one from pcount (particle count).
If there’s no more particles to launch we stop the function otherwise we add 1 to i and the loop continues.

If i has reached maxparticles then there are no particles available.

Now we can go to our _update function and add the following line:

if (frames%15==0) particlesys.explode(50)

Okay, we haven’t introduced frames yet. We can count time in PICO-8 in multiple ways. We have (if we use the standard _update() ) 30 frames per second, there’s also an _update60 that does 60 frames per second. For now we use _update but you should be able to transfer the code pretty easy to _update60. The above code basically let’s 15 frames pass (½ a second) and then it calls particlesys.explode().

Let’s add frames as a global variable inside _init():

frames=0

And in _draw we add frames+=1 on the last line of the function.

Now we need to go to our launch function of the particle.
Declare a variable called _col in the lines before the return statement.

The launch function needs to take in a new argument called cols which is the possible colors we want for the particle.

Inside the launch function we set the _col variable to the following:

_col=cols[flr(rnd(2))+1]

Inside the draw function of the particle we add the following to the line call:

line(_x,_y,_x+_xspeed,_y+_yspeed,_col)

Type run in the console and see the sparks in action!

Simple Rain in PICO-8

Hi there!
This is my first tutorial on PICO-8. Today we’re gonna make a simple rain particle system. I will not focus too much on token count but just show you how to make a particle system with a pool that can create a simple rain effect.


Let’s get started.

Start by entering the following. You probably already know this, but _INIT() is for game initialization, _DRAW() is the draw-loop and _UPDATE() is the update-loop.

We clear the screen to a black color at every frame. This is done by CLS(0).

Let’s get started on the particle system.

Create a new function called new_particle_system that takes in a count of elements as the max particles allowed at a time.

Inside the function we will create a local variable called _pool:

_pool={}

Next up we need to create a particle function. Go to a new tab or scroll down and write the following:

function new_particle()
  local _x,_y=0,0
  local _xspeed,_yspeed=0,0
  local _done=true
end

This is the basics of the particle class, we have an y-speed an x-speed and two positions (x,y). Now let’s add a return statement below _done=true:


function new_particle()
  local _x,_y=0,0
  local _xspeed,_yspeed=0,0
  local _done=true
  return {
    launch=function(x,y,xspd,yspd)
      if _done then
        _x,_y,_xspeed,_yspeed,_done=x,y,xspd,yspd,false
        return true
      end
    end,
    update=function()
      if (_done) return
      _x+=_xspeed
      _yspeed+=0.92
      _y+=_yspeed
      if _y>127 then
        _done=true
      end
    end,
    draw=function()
      if (_done) return
      line(_x,_y,_x+_xspeed,_y+_yspeed,7)
    end
  }
end

Above return an object with the following functions:
launch() – for launching the particle with x-position, y-position, x-speed and y-speed.
update() – for updating the position and the current speed of the particle.
draw() – for drawing the particle as a line with both speeds applied.

Let’s take a closer look at the functions:
launch starts by checking if _done is true. This means that we’re allowed to use the particle, so if that is the case we set all the variables to the inputs and set _done to false. We then return true. The return true will hopefully make sense later on.
update also starts by checking if _done and then we dismiss the function if that is the case. No reason to calculate anything if the particle isn’t supposed to show. After that we apply the _xspeed to _x and we apply gravity (0.92) to _yspeed. Then we check if the particle has left the screen (after 127 on y) and set _done to true if that is the case.
draw starts by dismissing if the particle is done. Else it will draw a line from _x,_y to _x+_xspeed, _y+_yspeed.

Cool! That’s all we need for the particle.

Let’s go to the particle system function and work some magic there.
Let’s initialize the particle pool by doing the following:

for i=1,maxparticles do
  _pool[i]=new_particle()
end

LUA’s arrays starts at index 1 so that’s the reason why we do it from i=1 and not i=0.

Now that we have initialized the pool we can return the object with the following functions: rain(), update(), draw().

return {
  rain=function()
  end,
  update=function()
  end
  draw=function()
  end
}

The above code shows how return the object with functions declared inside. Now let’s fill out the blanks:

rain=function()
  local rand=rnd(5)
  for i=1,maxparticles do
    if _pool[i].launch(rnd(127),-rand,0,rand) then
      return
    end
  end
end

The rain function sets a random number between 0 and 5, loops through all particles and dismisses the function in case a particle’s launch function has been called. The call to launch randomly places the particle at an x-position inside the screen and above the screen by -rand (remember PICO-8’s coordinate system is top-left (0,0) to bottom-right (127,127)). We also set the x-speed to 0 and the y-speed to rand.

Now let’s create the update function, it’s pretty straight-forward:

update=function()
  for i=1,maxparticles do
    _pool[i].update()
  end
end

The draw function is more or less the same except that we call draw instead of update:

for i=1,maxparticles do
  _pool[i].draw()
end

And that’s it. Now let’s put it to use…

Go back to your main tab (or where you placed the initial functions and write the following:

function _init()
  particlesys=new_particle_system(512)
end

function _draw()
  cls(0)
  particlesys.draw()
end

function _update()
  particlesys.rain()
  particlesys.update()
end

Go to the console and type in run and see it in action.

Next up is extending the particle systems with sparks!