This is my second experiment with PICO-8, this time making a flexible and customizable particle emitter system. In this demo I've pre-made several different emitters that you can view by pressing (left) or (right).
Particles are only rendered as lines, but there are a lot of options to control how they look and behave. It took a while to figure out how to handle colliding with the edges of the screen such that it was accurate no matter how fast the particles were traveling or how long their trails were. Here's just the particle update function to see what's going on:
function particle:update()
if self.age < self.lifespan then
if self.jitter > 0 then
local curr_jitter = rnd(self.jitter)-self.jitter/2
local curr_angle = atan2(self.dx,self.dy)
local curr_mag = sqrt(self.dx^2+self.dy^2)
self.dx = cos(curr_angle+curr_jitter)*curr_mag
self.dy = sin(curr_angle+curr_jitter)*curr_mag
end
self.dx = (self.dx+self.xgrav)*self.drag
self.dy = (self.dy+self.ygrav)*self.drag
local next_x = self.x+self.dx
local next_y = self.y+self.dy
local line_pts = {{self.x, self.y}}
line_pts.segments = 0
while self.collide do
-- left collision
if next_x < 0 and btwn(self.y+((next_y-self.y)*self.x/(self.x-next_x)),0,screen) then
self.y += (next_y-self.y)*self.x/(self.x-next_x)
self.x = 0
self.dx *= -self.bounce
next_x *= -self.bounce
-- right collision
elseif next_x > screen and btwn(self.y+((next_y-self.y)*(screen-self.x)/(next_x-self.x)),0,screen) then
self.y += (next_y-self.y)*(screen-self.x)/(next_x-self.x)
self.x = screen
self.dx *= -self.bounce
next_x = screen-(next_x-screen)*self.bounce
-- top collision
elseif next_y < 0 and btwn(self.x+((next_x-self.x)*self.y/(self.y-next_y)),0,screen) then
self.x += (next_x-self.x)*self.y/(self.y-next_y)
self.y = 0
self.dy *= -self.bounce
next_y *= -self.bounce
-- bottom collision
elseif next_y > screen and btwn(self.x+((next_x-self.x)*(screen-self.y)/(next_y-self.y)),0,screen) then
self.x += (next_x-self.x)*(screen-self.y)/(next_y-self.y)
self.y = screen
self.dy *= -self.bounce
next_y = screen-(next_y-screen)*self.bounce
else -- no collision
break
end
add(line_pts, {self.x, self.y})
line_pts.segments += 1
end
self.x = next_x
self.y = next_y
add(line_pts, {self.x, self.y})
line_pts.segments += 1
add(self.lines, line_pts)
elseif self.maxlength >= 1 then
self.maxlength -= 1
end
-- trim the lines
while #self.lines > self.maxlength do
del(self.lines, self.lines[1])
end
-- get older
self.age += 1
end
|
With this code a particle can bounce multiple times in a single frame.
Anyway, if this is useful at all feel free to steal it, or just check out the demo.
edit: You can now press (x) to toggle performance info.
edit2: Improved readability of performance info and fixed bug where the particle:draw() function was being called on "dead" particles.
[Please log in to post a comment]



