Skip to content

Instantly share code, notes, and snippets.

@Achie72
Last active March 16, 2025 11:12
Show Gist options
  • Save Achie72/ab7d86dc57e7a6d51fd56d0dcb5f2041 to your computer and use it in GitHub Desktop.
Save Achie72/ab7d86dc57e7a6d51fd56d0dcb5f2041 to your computer and use it in GitHub Desktop.
PICO-8 Particles
-- inside init have a collection called particles
-- this is where we will store each an every particles, so we can iterate
-- over them in the future (aka process them one by one)
particles = {}
-- adder function, you call this anytime you want to add a new particle
-- to the system. This will help us centralise every modification as this
-- function is the only thing that you will have to modifiy.
function add_particle(_x, _y, _sx, _sy, _lifetime, _color, _type)
-- create a local temporary particle where we create the data
-- into this object. This is great because in the future you can access
-- any, so called member variables inside it
local part = {
x = _x, -- where it spawns on the x axis (horizontally)
y = _y, -- where i t spans on the y axis (vertically)
sx = _sx, --speed for the particle if they move around
sy = _sy, -- same but y direction
lifetime = _lifetime, -- how long it should live
color = _color, -- color to draw
type = _type -- type of it
}
-- for now type can be 1, and 2, 1 for pixels, 2 for exploding circles!
-- add the particle to our particle array
add(particles, part)
end
-- in update somewhere now we can
-- update all particles. Just call this function. We are yet again
-- movign this into a function so you can call it anywhere without having
-- to duplicate all the code inside.
function update_particles()
-- for xyz in all(table) do is basically a simple for cycle. It will take
-- everything in the table and place it into xyz one by one. If this sounds complicated
-- think of it as:
-- for i=1,#particles do
-- local particle = particles[i]
-- somecodeyouwant
-- end
-- they are basically the same
for particle in all(particles) do
-- now you can use particle as a name to access member variables and
-- use them how you like.
particle.x += particle.sx -- move the x direction by the speed
particle.y += particle.sy -- move the y direction by the speed
particle.lifetime -= 1 -- decrement by 1 each frame
-- if lifetime is over delete particle
if particle.lifetime <= 0 then
del(particles, particle)
end
--particle.color = flr(rnd(15))+1 -- this gonna generate a color between 1 and 15
-- if particle.type == 1 then
-- particle type 1 do something else
-- end
-- here for example you can have a type 1 that is just explosion clouds
-- filled in circles
-- and type 2, which is a shockwave, which is growing faster
end
end
-- in draw now you can call a function that will draw our particles
function draw_particles()
for part in all(particles) do
--pset(part.x, part.y, part.color)
-- part.type = 1 would be a pixel particle
if part.type == 1 then
pset(part.x, part.y, part.color)
-- part.type = 2 are circles
elseif part.type == 2 then
circfill(part.x, part.y, 3, part.color)
end
-- how can you draw different things over time?
-- calculating with lifetime is the easiest,
-- for expanding stuff you want to increase the size
-- so for example let's have a 10/lifetime for example, where
-- tweaking 10 is where you can dial in the maximum size.
-- here you divide 10 with a smaller and smaller number due to how
-- lifetime is decreasing over time
-- circfill(part.x, part.y, 10/part.lifetime, part.colo)
end
end
-- with this setup all you have to do is call the add_particle function
-- whenever you want to create some particles.
-- lets's say we have a player with x and y coordinates
player = {
x = 10,
y = 10
}
-- players will ahve a trail after them whenever they move
function _update()
-- move the player
if btn(0) then
player.x -= 1
end
if btn(1) then
player.x += 1
end
if btn(2) then
player.y -= 1
end
if btn(3) then
player.y += 1
end
-- now let's add a particle
-- we are not gonna move that particle, so sx, sy will be zero
-- let them live for 30 frames (1 second) and be white (color 7)
-- for now type doesn't matter as we ahven't added a code for it
-- add_particle(_x, _y, _sx, _sy, _lifetime, _color, _type)
add_particle(player.x, player.y, 0, 0, 30, 7, 1)
-- now let's call our particle update function
-- just to show, let's add some kind of explosion!
if btnp(4) then
-- add more particles, it is an explosion
for i=1,5 do
-- in an explosion not every cloud is moving
-- in the same direction so let's randomize that
-- we will use a random combination, that will
-- create us a random number between {-1,1}
-- first let's create one that is the number
-- random_speed = rnd(), this will be a number between 0,1
-- now let's give it a direction
-- dir = rnd({-1,1}, here we use rnd to grab a random element from the table
-- which is either 1, or -1. IF we multiply these two we get a random number
-- between {-1,1}
local speed_x = rnd()*rnd({-1,1})
local speed_y = rnd()*rnd({-1,1})
-- 30 is lifetime, 8 is color, 2 is type
add_particle(player.x, player.y, speed_x, speed_y, 30, 8, 2)
end
end
update_particles()
end
function _draw()
--clear screen
cls()
-- draw our particles
draw_particles()
-- draw bright green player
print("😐", player.x, player.y, 11)
end
@Achie72
Copy link
Author

Achie72 commented Mar 16, 2025

@Achie72
Copy link
Author

Achie72 commented Mar 16, 2025

If you would like to read more like this, feel free to checkout my Ko-fi articles, with many devlogs and code rundowns like this!
https://github.com/Achie72/kofi-articles

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment