local DustParticle = {} DustParticle.__index = DustParticle local MAX_DUST = 30 local DRIFT_SPEED_MIN = 4 local DRIFT_SPEED_MAX = 12 local WOBBLE_AMP_MIN = 3 local WOBBLE_AMP_MAX = 8 local WOBBLE_FREQ_MIN = 0.8 local WOBBLE_FREQ_MAX = 2.5 local GLOW_FREQ_MIN = 1.5 local GLOW_FREQ_MAX = 4.0 local GLOW_RADIUS_MIN = 2 local GLOW_RADIUS_MAX = 5 local MARGIN = 16 local DUST_COLORS = { {1.0, 0.95, 0.75}, {0.85, 0.9, 1.0}, {1.0, 0.85, 0.6}, {0.75, 0.85, 1.0}, } function DustParticle.new(x, y) local self = setmetatable({}, DustParticle) self.x = x self.y = y local angle = math.random() * math.pi * 2 local speed = DRIFT_SPEED_MIN + math.random() * (DRIFT_SPEED_MAX - DRIFT_SPEED_MIN) self.dx = math.cos(angle) * speed self.dy = math.sin(angle) * speed self.perpX = -math.sin(angle) self.perpY = math.cos(angle) self.wobbleAmp = WOBBLE_AMP_MIN + math.random() * (WOBBLE_AMP_MAX - WOBBLE_AMP_MIN) self.wobbleFreq = WOBBLE_FREQ_MIN + math.random() * (WOBBLE_FREQ_MAX - WOBBLE_FREQ_MIN) self.wobblePhase = math.random() * math.pi * 2 self.glowFreq = GLOW_FREQ_MIN + math.random() * (GLOW_FREQ_MAX - GLOW_FREQ_MIN) self.glowPhase = math.random() * math.pi * 2 self.baseAlpha = 0.15 + math.random() * 0.25 self.color = DUST_COLORS[math.random(#DUST_COLORS)] self.time = 0 return self end function DustParticle:update(dt) self.time = self.time + dt local wobble = math.sin(self.time * self.wobbleFreq + self.wobblePhase) * self.wobbleAmp self.x = self.x + (self.dx + self.perpX * wobble * 0.3) * dt self.y = self.y + (self.dy + self.perpY * wobble * 0.3) * dt end function DustParticle:draw() local glowT = math.sin(self.time * self.glowFreq + self.glowPhase) local glowRadius = GLOW_RADIUS_MIN + (GLOW_RADIUS_MAX - GLOW_RADIUS_MIN) * (glowT * 0.5 + 0.5) local alpha = self.baseAlpha * (0.6 + 0.4 * (glowT * 0.5 + 0.5)) love.graphics.setBlendMode("add") love.graphics.setColor(self.color[1], self.color[2], self.color[3], alpha * 0.4) love.graphics.circle("fill", self.x, self.y, glowRadius) love.graphics.setColor(self.color[1], self.color[2], self.color[3], alpha) love.graphics.circle("fill", self.x, self.y, 1) love.graphics.setBlendMode("alpha") love.graphics.setColor(1, 1, 1, 1) end function DustParticle:isOutOfBounds(viewX, viewY, viewW, viewH) return self.x < viewX - MARGIN or self.x > viewX + viewW + MARGIN or self.y < viewY - MARGIN or self.y > viewY + viewH + MARGIN end local DustSystem = {} DustSystem.__index = DustSystem function DustSystem.new() local self = setmetatable({}, DustSystem) self.particles = {} self.spawned = false return self end function DustSystem:update(dt, camX, camY, camW, camH) if not self.spawned then for _ = 1, MAX_DUST do local x = camX + math.random() * camW local y = camY + math.random() * camH table.insert(self.particles, DustParticle.new(x, y)) end self.spawned = true end for _, p in ipairs(self.particles) do p:update(dt) end for i = #self.particles, 1, -1 do local p = self.particles[i] if p:isOutOfBounds(camX, camY, camW, camH) then local edge = math.random(4) local x, y if edge == 1 then x = camX - MARGIN * 0.5 y = camY + math.random() * camH elseif edge == 2 then x = camX + camW + MARGIN * 0.5 y = camY + math.random() * camH elseif edge == 3 then x = camX + math.random() * camW y = camY - MARGIN * 0.5 else x = camX + math.random() * camW y = camY + camH + MARGIN * 0.5 end self.particles[i] = DustParticle.new(x, y) end end while #self.particles < MAX_DUST do local x = camX + math.random() * camW local y = camY + math.random() * camH table.insert(self.particles, DustParticle.new(x, y)) end end function DustSystem:draw() for _, p in ipairs(self.particles) do p:draw() end end return DustSystem