Fixed some little errors with the drawing functions.
[luagame.git] / base / ParticleSystem.lua
blobcd97edf1c0395bf1c421f7256d56be316fdc5cdf
1 --[[
2 ParticleSystem class
3 --------------------
5 TODO:
7 This class provides a number of particle systems:
8 The "type" field should be set to either:
9 point -- emits from a single point in space - requires the "x" and "y" fields to be set
10 rect -- emits particles within a rectangle in space - requires the "rect" field to be set
12 It can operate in two modes, "random" and "ordered".
13 The "method" field should be set to either:
14 random -- randomly generates particles based on parameters -- does nothing with "point"
15 ordered -- generates particles in order from min to max, in a cycle
16 -- for "point" type, this has the effect of making a "spread"
18 Additionally, "ordered" has two modes of operation (does not apply to "point" type):
19 wrap -- will just wrap values when they hit max
20 bounce -- will "bounce" between min and max
22 --]]
24 ParticleSystem = {}
25 ParticleSystem.object = nil --this must be set to the Object that will be used in the particle system
26 ParticleSystem.object_args = nil --the table to pass to the object constructor
27 ParticleSystem.object_list = nil --the ObjectList that contains the Objects in the particle system
28 ParticleSystem.on = false --whether or not the system is currently emitting
29 ParticleSystem.type = "point" --the type of particle system
30 ParticleSystem.method = "random" --the method in which particles are generated
31 ParticleSystem.ordered_mode = "wrap" -- the mode in which ordered will operate
33 --for point type
34 ParticleSystem.x = 0
35 ParticleSystem.y = 0
37 --for rect type
38 ParticleSystem.rect = nil
39 ParticleSystem.ordered_step = 1
41 --Update Variables
42 ParticleSystem.particles_per_update_min = 1 --minimum number of particles to create per call of update
43 ParticleSystem.particles_per_update_max = 1 --maximum number of particles to create per call of update
44 ParticleSystem.update_delay = 0 -- the delay in calls of update between emittings
45 ParticleSystem.update_delay_current = 0 --current count -- do not touch
47 -- The following pertain to the emitted Objects --
49 ParticleSystem.angle_min = 0 --minimum angle in degrees
50 ParticleSystem.angle_max = 360 --maximum angle in degrees
52 ParticleSystem.speed_min = 0 --minimum speed
53 ParticleSystem.speed_max = 1 --maximum speed
55 ParticleSystem.life_min = 1 --minimum lifetime in updates -- set less than 1 to make infinity
56 ParticleSystem.life_max = 1 --maximum lifetime in updates
58 ParticleSystem.rotation_init_min = 0 --minimum initial rotation
59 ParticleSystem.rotation_init_max = 0 --maximum initial rotation
61 ParticleSystem.angular_velocity_min = 0 --minimum angular velocity
62 ParticleSystem.angular_velocity_max = 0 --maximum angular velocity
64 --state variables
65 ParticleSystem.ordered_position = 0
66 ParticleSystem.ordered_direction = 1
69 --constructor
70 function ParticleSystem:new(o)
71 o = o or {}
72 setmetatable(o, self)
73 self.__index = self
74 o.object_list = ObjectList:new()
75 return o
76 end
79 --internal function to emit a particle
80 -- recommend: do not use directly
81 function ParticleSystem:emit(angle)
82 local tobj = self.object:new(self.object_args)
84 --should be random for either creation method, at least for now
85 tobj.speed = (math.random() * (self.speed_max - self.speed_min)) + self.speed_min
86 tobj.rotation = (math.random() * (self.rotation_init_max - self.rotation_init_min)) + self.rotation_init_min
87 tobj.angular_velocity = (math.random() * (self.angular_velocity_max - self.angular_velocity_min)) + self.angular_velocity_min
89 if self.life_min < 1 then
90 tobj.max_updates = -1
91 else
92 tobj.max_updates = math.random(self.life_min, self.life_max)
93 end
95 if self.method == "random" then
96 tobj.heading = math.random(self.angle_min, self.angle_max)
98 if self.type == "point" then
99 tobj.x = self.x
100 tobj.y = self.y
101 elseif self.type == "rect" then
102 tobj.x = math.random(self.rect.x, self.rect.x + self.rect.w)
103 tobj.y = math.random(self.rect.y, self.rect.y + self.rect.h)
105 elseif self.method == "ordered" then
106 if self.type == "point" then
107 tobj.x = self.x
108 tobj.y = self.y
109 tobj.angle = angle
110 elseif self.type == "rect" then
111 tobj.angle = math.random(self.angle_min, self.angle_max)
112 tobj.y = math.floor(self.ordered_position / self.rect.w)
113 tobj.x = self.ordered_position % self.rect.w
117 self.object_list:push_back(tobj)
121 --updates all contained Objects and emits more if it is "on"
122 function ParticleSystem:update(delta)
123 self.object_list:update(delta)
125 --handles the delay. allows for both frame-based and delta-based animation
126 if self.update_delay ~= 0 then
127 if delta then
128 if self.update_delay_current >= self.update_delay then
129 self.update_delay_current = 0
130 else
131 self.update_delay_current = self.update_delay_current + delta
133 else
134 if self.update_delay_current == self.update_delay then
135 self.update_delay_current = 0
136 else
137 self.update_delay_current = self.update_delay_current + 1
142 --emit new Objects
143 if self.on == true and self.update_delay_current == 0 then
144 local cur_e = 1
145 local num_e = math.random(self.particles_per_update_min, self.particles_per_update_max)
147 local angle_spread = 0
148 if self.type == "point" and self.method == "ordered" then
149 angle_spread = (self.angle_max - self.angle_min) / (num_e)
152 while cur_e <= num_e do
153 self:emit((angle_spread * (cur_e - 1)) + self.angle_min)
154 cur_e = cur_e + 1
157 if self.type == "rect" and self.method == "ordered" then
158 self.ordered_position = self.ordered_position + (self.ordered_direction * self.ordered_step)
159 if self.ordered_position >= self.rect.w * self.rect.h then
160 if self.ordered_mode == "wrap" then
161 self.ordered_position = 0
162 elseif self.ordered_mod == "bounce" then
163 self.ordered_direction = -1
165 elseif self.ordered_position <= 0 then
166 self.ordered_direction = 1
174 --draws all contained Objects
175 function ParticleSystem:draw()
176 self.object_list:draw()