1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
|
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
|