Speck_Sys = {} Speck_Sys.__index = Speck_Sys function Speck_Sys.new() local self = setmetatable({}, Speck_Sys) self.data = { size = 0, pos = {}, vel = {}, alive = {}, lifetime = {}, lifetime_max = {}, scale_start = {}, scale_end = {} } self.free_ids = {} self.free_ids_size = 0 self.scale_curve = lerp self.scale_start_min = 0.8 self.scale_start_max = 1.25 self.scale_end_min = 0 self.scale_end_max = 0 self.forcex = 0 self.forcey = 0 self.lifetime_min = 1 self.lifetime_max = 5 self.interval = 0.1 self.spawn_timer = self.interval self.texture = get_tex("res/img/speck.png") self.x = 0 self.y = 0 return self end function Speck_Sys:check_bounce(i) if not self.bounce then return false end local scn = get_current_scene() assert(scn, "No scene set.") return has_tile( scn.tilemap, to_tile_coords(self.data.pos[i].x, self.data.pos[i].y)) end function Speck_Sys:update(dt) local data = self.data -- particle spawning self.spawn_timer = self.spawn_timer - dt if self.spawn_timer <= 0 then self.spawn_timer = self.interval local id if self.free_ids_size > 0 then id = self.free_ids[self.free_ids_size] self.free_ids_size = self.free_ids_size - 1 else self.data.size = self.data.size + 1 id = self.data.size end data.alive[id] = true data.pos[id] = { x = self.x, y = self.y } data.vel[id] = { x = 0, y = 0 } data.lifetime[id] = randf_range( self.lifetime_min, self.lifetime_max) data.lifetime_max[id] = data.lifetime[id] data.scale_start[id] = randf_range( self.scale_start_min, self.scale_start_max) data.scale_end[id] = randf_range( self.scale_end_min, self.scale_end_max) end -- particles processing for i = 1, data.size do if not data.alive[i] then goto next_speck_update end if data.lifetime[i] <= 0 then data.alive[i] = false self.free_ids_size = self.free_ids_size + 1 self.free_ids[self.free_ids_size] = i goto next_speck_update end data.vel[i].x = data.vel[i].x + self.forcex * dt data.vel[i].y = data.vel[i].y + self.forcey * dt -- move and bounce data.pos[i].x = data.pos[i].x + data.vel[i].x * dt if self:check_bounce(i) then data.vel[i].x = -data.vel[i].x data.pos[i].x = data.pos[i].x + data.vel[i].x * dt end data.pos[i].y = data.pos[i].y + data.vel[i].y * dt if self:check_bounce(i) then data.vel[i].y = -data.vel[i].y data.pos[i].y = data.pos[i].y + data.vel[i].y * dt end data.lifetime[i] = data.lifetime[i] - dt ::next_speck_update:: end end function Speck_Sys:draw() local scale_curve = self.scale_curve local data = self.data for i = 1, data.size do if not data.alive[i] then goto next_speck_draw end local anim = 1 - data.lifetime[i] / data.lifetime_max[i] local scale = scale_curve(data.scale_start[i], data.scale_end[i], anim) local w, h = self.texture:getDimensions() w = w * scale h = h * scale lg.draw( self.texture, data.pos[i].x - w/2, data.pos[i].y - h/2, 0, scale ) ::next_speck_draw:: end end register_comp("Speck_System", function(ent) ent.speck_sys = Speck_Sys.new() end) function speck_update_sys(ent, dt) ent.speck_sys.x = ent.x ent.speck_sys.y = ent.y ent.speck_sys:update(dt) end function speck_draw_sys(ent) ent.speck_sys:draw() end