Mana
Loading...
Searching...
No Matches
particleemitter.cpp
Go to the documentation of this file.
1/*
2 * The Mana Client
3 * Copyright (C) 2006-2009 The Mana World Development Team
4 * Copyright (C) 2009-2012 The Mana Developers
5 *
6 * This file is part of The Mana Client.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
22#include "animationparticle.h"
23#include "imageparticle.h"
24#include "log.h"
25#include "map.h"
26#include "particle.h"
27#include "particleemitter.h"
28#include "rotationalparticle.h"
29
30#include "resources/dye.h"
31#include "resources/image.h"
33
34#include <cmath>
35
36#define SIN45 0.707106781f
37#define DEG_RAD_FACTOR 0.017453293f
38
40 Map *map, int rotation,
41 const std::string &dyePalettes)
42{
43 mMap = map;
44 mParticleTarget = target;
45
46 // Initializing default values
47 mParticlePosX.set(0.0f);
48 mParticlePosY.set(0.0f);
49 mParticlePosZ.set(0.0f);
52 mParticlePower.set(0.0f);
55 mParticleBounce.set(0.0f);
56 mParticleFollow = false;
63 mOutput.set(1);
65 mParticleAlpha.set(1.0f);
66
67 for (auto propertyNode : emitterNode.children())
68 {
69 if (propertyNode.name() == "property")
70 {
71 std::string name = propertyNode.getProperty("name", "");
72
73 if (name == "position-x")
74 {
75 mParticlePosX = readParticleEmitterProp(propertyNode, 0.0f);
76 }
77 else if (name == "position-y")
78 {
79
80 mParticlePosY = readParticleEmitterProp(propertyNode, 0.0f);
84 }
85 else if (name == "position-z")
86 {
87 mParticlePosZ = readParticleEmitterProp(propertyNode, 0.0f);
91 }
92 else if (name == "image")
93 {
94 std::string image = propertyNode.getProperty("value", "");
95 // Don't leak when multiple images are defined
96 if (!image.empty() && !mParticleImage)
97 {
98 if (!dyePalettes.empty())
99 Dye::instantiate(image, dyePalettes);
100
102 mParticleImage = resman->getImage(image);
103 }
104 }
105 else if (name == "horizontal-angle")
106 {
113 }
114 else if (name == "vertical-angle")
115 {
120 }
121 else if (name == "power")
122 {
123 mParticlePower = readParticleEmitterProp(propertyNode, 0.0f);
124 }
125 else if (name == "gravity")
126 {
127 mParticleGravity = readParticleEmitterProp(propertyNode, 0.0f);
128 }
129 else if (name == "randomnes" || name == "randomness") // legacy bug
130 {
132 }
133 else if (name == "bounce")
134 {
135 mParticleBounce = readParticleEmitterProp(propertyNode, 0.0f);
136 }
137 else if (name == "lifetime")
138 {
141 }
142 else if (name == "output")
143 {
144 mOutput = readParticleEmitterProp(propertyNode, 0);
145 mOutput.maxVal +=1;
146 }
147 else if (name == "output-pause")
148 {
149 mOutputPause = readParticleEmitterProp(propertyNode, 0);
151 }
152 else if (name == "acceleration")
153 {
155 }
156 else if (name == "die-distance")
157 {
158 mParticleDieDistance = readParticleEmitterProp(propertyNode, 0.0f);
159 }
160 else if (name == "momentum")
161 {
162 mParticleMomentum = readParticleEmitterProp(propertyNode, 1.0f);
163 }
164 else if (name == "fade-out")
165 {
166 mParticleFadeOut = readParticleEmitterProp(propertyNode, 0);
167 }
168 else if (name == "fade-in")
169 {
170 mParticleFadeIn = readParticleEmitterProp(propertyNode, 0);
171 }
172 else if (name == "alpha")
173 {
174 mParticleAlpha = readParticleEmitterProp(propertyNode, 1.0f);
175 }
176 else if (name == "follow-parent")
177 {
178 mParticleFollow = propertyNode.getBoolProperty("value", true);
179 }
180 else
181 {
182 Log::info("Particle Engine: Warning, unknown emitter property \"%s\"",
183 name.c_str());
184 }
185 }
186 else if (propertyNode.name() == "emitter")
187 {
188 ParticleEmitter newEmitter(propertyNode, mParticleTarget, map,
189 rotation, dyePalettes);
190 mParticleChildEmitters.push_back(newEmitter);
191 }
192 else if (propertyNode.name() == "rotation")
193 {
195 }
196 else if (propertyNode.name() == "animation")
197 {
199 }
200 else if (propertyNode.name() == "deatheffect")
201 {
202 mDeathEffect = propertyNode.textContent();
204 if (propertyNode.getBoolProperty("on-floor", true))
205 {
207 }
208 if (propertyNode.getBoolProperty("on-sky", true))
209 {
211 }
212 if (propertyNode.getBoolProperty("on-other", false))
213 {
215 }
216 if (propertyNode.getBoolProperty("on-impact", true))
217 {
219 }
220 if (propertyNode.getBoolProperty("on-timeout", true))
221 {
223 }
224 }
225 }
226}
227
229{
230 *this = o;
231}
232
265
266
268
269
270template <typename T> ParticleEmitterProp<T>
272{
274
275 def = (T) propertyNode.getFloatProperty("value", (double) def);
276 retval.set((T) propertyNode.getFloatProperty("min", (double) def),
277 (T) propertyNode.getFloatProperty("max", (double) def));
278
279 std::string change = propertyNode.getProperty("change-func", "none");
280 T amplitude = (T) propertyNode.getFloatProperty("change-amplitude", 0.0);
281 int period = propertyNode.getProperty("change-period", 0);
282 int phase = propertyNode.getProperty("change-phase", 0);
283 if (change == "saw" || change == "sawtooth")
284 retval.setFunction(FUNC_SAW, amplitude, period, phase);
285 else if (change == "sine" || change == "sinewave")
286 retval.setFunction(FUNC_SINE, amplitude, period, phase);
287 else if (change == "triangle")
288 retval.setFunction(FUNC_TRIANGLE, amplitude, period, phase);
289 else if (change == "square")
290 retval.setFunction(FUNC_SQUARE, amplitude, period, phase);
291
292 return retval;
293}
294
295
296std::list<Particle *> ParticleEmitter::createParticles(int tick)
297{
298 std::list<Particle *> newParticles;
299
300 if (mOutputPauseLeft > 0)
301 {
303 return newParticles;
304 }
306
307 for (int i = mOutput.value(tick); i > 0; i--)
308 {
309 // Limit maximum particles
311
312 Particle *newParticle;
313 if (mParticleImage)
314 {
315 newParticle = new ImageParticle(mMap, mParticleImage);
316 }
317 else if (mParticleRotation.getLength() > 0)
318 {
319 newParticle = new RotationalParticle(mMap, mParticleRotation);
320 }
321 else if (mParticleAnimation.getLength() > 0)
322 {
323 newParticle = new AnimationParticle(mMap, mParticleAnimation);
324 }
325 else
326 {
327 newParticle = new Particle(mMap);
328 }
329
330 Vector position(mParticlePosX.value(tick),
331 mParticlePosY.value(tick),
332 mParticlePosZ.value(tick));
333 newParticle->moveTo(position);
334
335 float angleH = mParticleAngleHorizontal.value(tick);
336 float angleV = mParticleAngleVertical.value(tick);
337 float power = mParticlePower.value(tick);
338 newParticle->setVelocity(
339 cos(angleH) * cos(angleV) * power,
340 sin(angleH) * cos(angleV) * power,
341 sin(angleV) * power);
342
343 newParticle->setRandomness(mParticleRandomness.value(tick));
344 newParticle->setGravity(mParticleGravity.value(tick));
345 newParticle->setBounce(mParticleBounce.value(tick));
346 newParticle->setFollow(mParticleFollow);
347
348 newParticle->setDestination(mParticleTarget,
351 );
352 newParticle->setDieDistance(mParticleDieDistance.value(tick));
353
354 newParticle->setLifetime(mParticleLifetime.value(tick));
355 newParticle->setFadeOut(mParticleFadeOut.value(tick));
356 newParticle->setFadeIn(mParticleFadeIn.value(tick));
357 newParticle->setAlpha(mParticleAlpha.value(tick));
358
359 for (auto &particleChildEmitter : mParticleChildEmitters)
360 {
361 newParticle->addEmitter(new ParticleEmitter(particleChildEmitter));
362 }
363
364 if (!mDeathEffect.empty())
365 {
367 }
368
369 newParticles.push_back(newParticle);
370 }
371
372 return newParticles;
373}
374
376{
377 if (w == 0 || h == 0) return; // new dimensions are illegal
378
379 // calculate the old rectangle
380 int oldWidth = mParticlePosX.maxVal - mParticlePosX.minVal;
381 int oldHeight = mParticlePosX.maxVal - mParticlePosY.minVal;
382 int oldArea = oldWidth * oldHeight;
383 if (oldArea == 0)
384 {
385 //when the effect has no dimension it is
386 //not designed to be resizeable
387 return;
388 }
389
390 // set the new dimensions
391 mParticlePosX.set(0, w);
392 mParticlePosY.set(0, h);
393 int newArea = w * h;
394 // adjust the output so that the particle density stays the same
395 float outputFactor = (float)newArea / (float)oldArea;
396 mOutput.minVal *= outputFactor;
397 mOutput.maxVal *= outputFactor;
398}
int getLength() const
Returns the length of this animation in frames.
Definition animation.h:70
static Animation fromXML(XML::Node node, const std::string &dyePalettes={})
Loads an animation from XML.
Definition animation.cpp:50
static void instantiate(std::string &target, const std::string &palettes)
Fills the blank in a dye placeholder with some palette names.
Definition dye.cpp:252
A particle that uses an image for its visualization.
A tile map.
Definition map.h:147
Every Particle can have one or more particle emitters that create new particles when they are updated...
std::string mDeathEffect
Particle * mParticleTarget
ParticleEmitterProp< float > mParticlePosZ
ParticleEmitterProp< int > mOutput
Number of particles spawned per update.
ParticleEmitterProp< float > mParticleAngleHorizontal
initial vector of particles:
ParticleEmitterProp< float > mParticleDieDistance
ParticleEmitterProp< int > mParticleFadeIn
std::list< ParticleEmitter > mParticleChildEmitters
List of emitters the spawned particles are equipped with.
ResourceRef< Image > mParticleImage
Particle image, if used.
ParticleEmitterProp< int > mParticleRandomness
ParticleEmitterProp< float > mParticlePower
Initial velocity of particles.
ParticleEmitterProp< int > mParticleLifetime
std::list< Particle * > createParticles(int tick)
Spawns new particles.
ParticleEmitterProp< float > mParticleAngleVertical
ParticleEmitterProp< float > mParticleAcceleration
ParticleEmitterProp< float > mParticleGravity
ParticleEmitter & operator=(const ParticleEmitter &o)
Assignment operator that calls the copy constructor.
ParticleEmitterProp< int > mParticleFadeOut
ParticleEmitterProp< float > mParticleAlpha
Opacity of the graphical representation of the particles.
Animation mParticleAnimation
Filename of particle animation file.
ParticleEmitterProp< T > readParticleEmitterProp(XML::Node propertyNode, T def)
ParticleEmitterProp< float > mParticlePosX
initial position of particles:
ParticleEmitterProp< float > mParticleBounce
Animation mParticleRotation
Filename of particle rotation file.
Map * mMap
Map the particles are spawned on.
void adjustSize(int w, int h)
Changes the size of the emitter so that the effect fills a rectangle of this size.
ParticleEmitterProp< float > mParticleMomentum
ParticleEmitter(XML::Node emitterNode, Particle *target, Map *map, int rotation=0, const std::string &dyePalettes=std::string())
ParticleEmitterProp< float > mParticlePosY
ParticleEmitterProp< int > mOutputPause
Pause in frames between two spawns.
A particle spawned by a ParticleEmitter.
Definition particle.h:42
void setVelocity(float x, float y, float z)
Sets the current velocity in 3 dimensional space.
Definition particle.h:170
void setRandomness(int r)
Sets the ammount of random vector changes.
Definition particle.h:182
void setAlpha(float alpha) override
Sets the alpha value used to draw the actor.
Definition particle.h:253
virtual void setDeathEffect(const std::string &effectFile, char conditions)
Definition particle.h:255
static int particleCount
Current number of particles.
Definition particle.h:56
static int maxCount
Maximum number of particles.
Definition particle.h:57
void addEmitter(ParticleEmitter *emitter)
Adds an emitter to the particle.
Definition particle.h:128
void setFadeIn(int fadeIn)
Sets the remaining particle lifetime where the particle starts to fade out.
Definition particle.h:164
@ DEAD_TIMEOUT
Definition particle.h:47
@ DEAD_IMPACT
Definition particle.h:50
@ DEAD_OTHER
Definition particle.h:51
@ DEAD_SKY
Definition particle.h:49
@ DEAD_FLOOR
Definition particle.h:48
void setGravity(float gravity)
Sets the downward acceleration.
Definition particle.h:176
void moveTo(const Vector &pos)
Sets the position in 3 dimensional space in pixels relative to map.
Definition particle.h:134
void setDieDistance(float dist)
Sets the distance in pixel the particle can come near the target particle before it is destroyed.
Definition particle.h:216
void setLifetime(int lifetime)
Sets the time in game ticks until the particle is destroyed.
Definition particle.h:150
void setDestination(Particle *target, float accel, float moment)
Makes the particle move toward another particle with a given acceleration and momentum.
Definition particle.h:208
void setBounce(float bouncieness)
Sets the ammount of velocity particles retain after hitting the ground.
Definition particle.h:189
void setFadeOut(int fadeOut)
Sets the age of the pixel in game ticks where the particle has faded in completely.
Definition particle.h:157
void setFollow(bool follow)
Sets the flag if the particle is supposed to be moved by its parent.
Definition particle.h:195
A class for loading and managing resources.
static ResourceManager * getInstance()
Returns an instance of the class, creating one if it does not already exist.
ResourceRef< Image > getImage(const std::string &idPath)
Loads the Image resource found at the given identifier path.
Vector class.
Definition vector.h:33
int getProperty(const char *name, int def) const
Definition xml.h:144
double getFloatProperty(const char *name, double def) const
Definition xml.h:152
Children children() const
Definition xml.h:97
void info(const char *log_text,...) LOG_PRINTF_ATTR
#define SIN45
Definition particle.cpp:45
#define DEG_RAD_FACTOR
@ FUNC_TRIANGLE
@ FUNC_SQUARE
@ FUNC_SINE
void set(T min, T max)
void setFunction(ChangeFunc func, T amplitude, int period, int phase)