This effect consists of two particle effects: trail and bang. In this example there are three different colors, which could be easily changed in particle emitters settings.
The main script fireworks.script
spawns the fireworks trail particlefx on startup or when any key is pressed or the mouse button is clicked. It also has a timer that spawns the particlefx in a loop with a 3 second delay.
To start effect:
Images for particles are taken from Kenney Particle Pack.
fireworks.script
local colors = {"red", "green", "blue"} -- list of existing fireworks colors
local instances = {} -- list of active fireworks instances
local _tension = 0.9 -- emulation of air tension. More value leads to faster deceleration
local _gravity = 980 -- gravity, measuring in mm/sq.s.
local function start_fireworks(trail_id, bang_id, start_pos, speed, time, gravity, tension)
go.set_position(start_pos, trail_id)
particlefx.play(trail_id)
local m = {
update = function(self, dt)
if self.time > 0 then
local prev_pos = vmath.vector3(self.start_pos)
self.start_pos.x = self.start_pos.x + self.speed.x*dt
self.start_pos.y = self.start_pos.y + self.speed.y*dt
local triangle = vmath.vector3(prev_pos.x - start_pos.x, prev_pos.y - start_pos.y, 0)
local angle = math.atan2(triangle.y, triangle.x)
self.speed.x = self.speed.x - self.speed.x * self.tension*dt
self.speed.y = self.speed.y - self.speed.y * self.tension*dt - self.gravity*dt
go.set_position(self.start_pos, self.trail)
go.set_rotation(vmath.quat_rotation_z(angle+math.pi/2), self.trail)
if self.time > 0 then
go.set_scale(self.time, self.trail)
end
elseif self.time <= 0 and not self.is_stopped then
self.is_stopped = true
particlefx.stop(self.trail, { clear = true })
go.set_position(self.start_pos, self.bang)
particlefx.play(self.bang)
elseif self.time <= -1.5 and self.bang then
go.delete(self.bang)
self.bang = nil
end
self.time = self.time - dt
end,
start_pos = start_pos,
time = time,
speed = speed,
gravity = gravity or _gravity,
tension = tension or _tension,
trail = trail_id,
bang = bang_id
}
return m
end
local function single_shot()
if #instances > 5 then
return
end
local color = colors[math.random(1, #colors)]
local splat = factory.create("#"..color.."_splat_factory")
local trail = factory.create("#"..color.."_trail_factory")
local strength = 1000+math.random()*600 -- scalar value of speed
local angle = (-0.2+math.random()*0.4)*math.pi -- angle beetween central vertical line and trail
local pos = vmath.vector3(360-math.sin(angle)*350, 0, 0)
local speed = vmath.vector3(strength*math.sin(angle), strength*math.cos(angle), 0)
table.insert(instances,
start_fireworks(trail, splat,
pos, speed,
1.2+math.random()*0.5
)
)
end
function init(self)
single_shot()
timer.delay(3, true, single_shot)
msg.post(".", "acquire_input_focus")
end
function update(self, dt)
for i, val in ipairs(instances) do
if not val.bang then
table.remove(instances, i)
else
val:update(dt)
end
end
end
function on_input(self, action_id, action)
if action.pressed then
single_shot()
end
end
If you want to play with these examples, you can get the project on Github.
Do you want to see more examples? Why not write a few yourself and submit a pull request? We love contributions.
GITHUB