Angel 3.2
A 2D Game Prototyping Engine
ParticleActor.cpp
1 
2 // Copyright (C) 2008-2013, Shane Liesegang
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of the copyright holder nor the names of any
14 // contributors may be used to endorse or promote products derived from
15 // this software without specific prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 // POSSIBILITY OF SUCH DAMAGE.
29 
30 #include "stdafx.h"
31 #include "../Actors/ParticleActor.h"
32 
33 #include "../Util/MathUtil.h"
34 
36 {
37  _maxParticlesAlive = 0;
38  _particles = 0;
39 
40  _particlesPerSecond = 20.0f;
41 
42  _generationResidue = 0.0f;
43  _numParticlesAlive = 0;
44 
45  _systemLifetime = 0.0f;
46  _particleLifetime = 2.0f;
47 
48  _spreadRadians = 0.0f;
49 
50  _endColor = Color(1.0f, 1.0f, 1.0f);
51 
52  _minSpeed = 2.0f;
53  _maxSpeed = 4.0f;
54 
55  _endScale = 1.0f;
56 
57  _gravity = Vector2(0.0f, -4.0f);
58  _attractor = Vector2(0.0f, 0.0f);
59  _attractorStrength = 0.0f;
60 }
61 
63 {
64  delete [] _particles;
65 }
66 
67 void ParticleActor::Update(float dt)
68 {
69  Actor::Update(dt);
70 
71  if (_maxParticlesAlive == 0)
72  return;
73 
74  //
75  // Update existing particles.
76  //
77  _numParticlesAlive = 0;
78  for (int i=0; i<_maxParticlesAlive; ++i)
79  {
80  Particle& currentParticle = _particles[i];
81 
82  if (currentParticle._age < 0.0f)
83  continue;
84 
85  if (currentParticle._age < currentParticle._lifetime)
86  {
87  currentParticle._age += dt;
88 
89  if (currentParticle._age < currentParticle._lifetime)
90  {
91  // Where are we in our lifespan? (0..1)
92  float lifePercent = currentParticle._age / currentParticle._lifetime;
93 
94  // Determine current position based on last known position, velocity and
95  // current time delta.
96  currentParticle._pos = currentParticle._pos + currentParticle._vel * dt;
97 
98  // Update our current velocity, which will be used next update.
99  currentParticle._vel = currentParticle._vel + _gravity * dt;
100  if (!MathUtil::FuzzyEquals(_attractorStrength, 0.0f))
101  {
102  Vector2 attractorShift = _attractor - currentParticle._pos;
103  attractorShift.Normalize();
104  attractorShift *= _attractorStrength;
105  currentParticle._vel += attractorShift * dt;
106  }
107 
108  currentParticle._color = MathUtil::Lerp(_color, _endColor, lifePercent);
109 
110  currentParticle._scale = MathUtil::Lerp(1.0f, _endScale, lifePercent);
111 
112  ++_numParticlesAlive;
113  }
114  else
115  {
116  currentParticle._age = -1.0f;
117 
118  }
119  }
120  }
121 
122  // Systems with 0.0f lifetime live forever.
123  if (_systemLifetime > 0.0f)
124  {
125  _systemLifetime -= dt;
126  if (_systemLifetime <= 0.f)
127  _systemLifetime = -1.f;
128  }
129 
130  // We're dead, but we're waiting for our particle to finish.
131  if (_systemLifetime < 0.0f)
132  {
133  if (_numParticlesAlive == 0)
134  {
135  Destroy();
136  }
137 
138  return;
139  }
140 
141  //
142  // Create new particles.
143  //
144 
145  // Add in any residual time from last emission.
146  float particlesToGenerate = _particlesPerSecond * dt + _generationResidue;
147  int numParticlesToGenerate = int(floorf(particlesToGenerate));
148  _generationResidue = particlesToGenerate - float(numParticlesToGenerate);
149 
150  if (numParticlesToGenerate > 0)
151  {
152  float rot = MathUtil::ToRadians(GetRotation());
153  float particleRot;
154 
155  int particlesGenerated = 0;
156  for (int i=0; i<_maxParticlesAlive; ++i)
157  {
158  Particle& currentParticle = _particles[i];
159 
160  if (currentParticle._age < 0.0f)
161  {
162  currentParticle._age = 0.0f;
163  currentParticle._lifetime = _particleLifetime;
164  currentParticle._pos = _position;
165  currentParticle._scale = 1.0f;
166  currentParticle._color = _color;
167 
168  particleRot = MathUtil::RandomFloatWithError(rot, _spreadRadians);
169  float speed = MathUtil::RandomFloatInRange(_minSpeed, _maxSpeed);
170  currentParticle._vel = Vector2(speed*cos(particleRot), speed*sin(particleRot));
171 
172  ++particlesGenerated;
173 
174  // If we've generated enough, break out.
175  if (particlesGenerated == numParticlesToGenerate)
176  break;
177  }
178  }
179  }
180 }
181 
183 {
184  if (!_particles)
185  return;
186 
187  int textureReference = _spriteTextureReferences[_spriteCurrentFrame];
188  if (textureReference >= 0)
189  {
190  glEnable(GL_TEXTURE_2D);
191  glBindTexture(GL_TEXTURE_2D, textureReference);
192  }
193 
194  // Render all of our particles.
195  for (int i=0; i<_maxParticlesAlive; ++i)
196  {
197  Particle& currentParticle = _particles[i];
198 
199  if (currentParticle._age < 0.0f)
200  continue;
201 
202  glPushMatrix();
203 
204  glTranslatef(currentParticle._pos.X, currentParticle._pos.Y, 0.0f);
205  glRotatef(_rotation, 0, 0, 1);
206  glScalef(_size.X * currentParticle._scale, _size.Y * currentParticle._scale, 1.0f);
207 
208  glColor4f( currentParticle._color.R,
209  currentParticle._color.G,
210  currentParticle._color.B,
211  currentParticle._color.A);
212 
213  const static float vertices[] = {
214  -0.5f, 0.5f,
215  -0.5f, -0.5f,
216  0.5f, 0.5f,
217  0.5f, -0.5f,
218  };
219  const static float texCoords[] = {
220  0.0f, 1.0f,
221  0.0f, 0.0f,
222  1.0f, 1.0f,
223  1.0f, 0.0f,
224  };
225  glEnableClientState(GL_VERTEX_ARRAY);
226  glEnableClientState(GL_TEXTURE_COORD_ARRAY);
227  glVertexPointer(2, GL_FLOAT, 0, vertices);
228  glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
229  glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
230 
231  glPopMatrix();
232  }
233 
234  if (textureReference >= 0)
235  {
236  glDisable(GL_TEXTURE_2D);
237  }
238 }
239 
241 {
242  if (pps < 0.0f)
243  {
244  pps = 0.0f;
245  }
246  _particlesPerSecond = pps;
247 }
248 
250 {
251  if (lifetime < 0.0f)
252  {
253  lifetime = 0.0f;
254  }
255  _systemLifetime = lifetime;
256 }
257 
259 {
260  if (lifetime < 0.0f)
261  {
262  lifetime = 0.0f;
263  }
264  _particleLifetime = lifetime;
265 }
266 
267 void ParticleActor::SetSpread(float radians)
268 {
269  _spreadRadians = radians;
270 }
271 
272 void ParticleActor::SetEndScale(float scale)
273 {
274  _endScale = scale;
275 }
276 
278 {
279  _endColor = color;
280 }
281 
282 void ParticleActor::SetSpeedRange(float minSpeed, float maxSpeed)
283 {
284  _minSpeed = minSpeed;
285  _maxSpeed = maxSpeed;
286 }
287 
288 void ParticleActor::SetMinSpeed(float minSpeed)
289 {
290  _minSpeed = minSpeed;
291 }
292 
293 void ParticleActor::SetMaxSpeed(float maxSpeed)
294 {
295  _maxSpeed = maxSpeed;
296 }
297 
298 void ParticleActor::SetGravity(const Vector2& gravity)
299 {
300  _gravity = gravity;
301 }
302 
303 void ParticleActor::SetAttractor(const Vector2& attractor)
304 {
305  _attractor = attractor;
306 }
307 
309 {
310  _attractorStrength = strength;
311 }
312 
313 void ParticleActor::SetMaxParticles(int maxParticles)
314 {
315  // Nothing to do if these match.
316  if (_maxParticlesAlive == maxParticles)
317  return;
318 
319  if (maxParticles <= 0)
320  {
321  maxParticles = 1;
322  }
323 
324  if (_particles)
325  {
326  delete [] _particles;
327  }
328  _maxParticlesAlive = maxParticles;
329  _particles = new Particle[_maxParticlesAlive];
330 
331  // Make them all available. Age < 0.0f = free.
332  for (int i=0; i<_maxParticlesAlive; ++i)
333  {
334  _particles[i]._age = -1.0f;
335  }
336 }
337