1 //  SuperTux
2 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
3 //
4 //  This program is free software: you can redistribute it and/or modify
5 //  it under the terms of the GNU General Public License as published by
6 //  the Free Software Foundation, either version 3 of the License, or
7 //  (at your option) any later version.
8 //
9 //  This program is distributed in the hope that it will be useful,
10 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
11 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 //  GNU General Public License for more details.
13 //
14 //  You should have received a copy of the GNU General Public License
15 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16 
17 #include "object/particles.hpp"
18 
19 #include <math.h>
20 
21 #include "math/random.hpp"
22 #include "math/util.hpp"
23 #include "object/camera.hpp"
24 #include "supertux/sector.hpp"
25 #include "video/drawing_context.hpp"
26 #include "video/video_system.hpp"
27 #include "video/viewport.hpp"
28 
29 //TODO: remove this function in favor of the one below
Particles(const Vector & epicenter,int min_angle,int max_angle,const Vector & initial_velocity,const Vector & acceleration,int number,Color color_,int size_,float life_time,int drawing_layer_)30 Particles::Particles(const Vector& epicenter, int min_angle, int max_angle,
31                      const Vector& initial_velocity, const Vector& acceleration, int number,
32                      Color color_, int size_, float life_time, int drawing_layer_) :
33   accel(acceleration),
34   timer(),
35   live_forever(),
36   color(color_),
37   size(static_cast<float>(size_)),
38   drawing_layer(drawing_layer_),
39   particles()
40 {
41   if (life_time == 0) {
42     live_forever = true;
43   } else {
44     live_forever = false;
45     timer.start(life_time);
46   }
47 
48   // create particles
49   for (int p = 0; p < number; p++)
50   {
51     auto particle = std::make_unique<Particle>();
52     particle->pos = epicenter;
53 
54     float angle = math::radians(graphicsRandom.randf(static_cast<float>(min_angle), static_cast<float>(max_angle)));
55     particle->vel.x = /*fabs*/(sinf(angle)) * initial_velocity.x;
56     //    if(angle >= math::PI && angle < math::TAU)
57     //      particle->vel.x *= -1;  // work around to fix signal
58     particle->vel.y = /*fabs*/(cosf(angle)) * initial_velocity.y;
59     //    if(angle >= math::PI_2 && angle < 3*math::PI_2)
60     //      particle->vel.y *= -1;
61 
62     particles.push_back(std::move(particle));
63   }
64 }
65 
Particles(const Vector & epicenter,int min_angle,int max_angle,const float min_initial_velocity,const float max_initial_velocity,const Vector & acceleration,int number,Color color_,int size_,float life_time,int drawing_layer_)66 Particles::Particles(const Vector& epicenter, int min_angle, int max_angle,
67                      const float min_initial_velocity, const float max_initial_velocity,
68                      const Vector& acceleration, int number, Color color_,
69                      int size_, float life_time, int drawing_layer_) :
70 
71   accel(acceleration),
72   timer(),
73   live_forever(),
74   color(color_),
75   size(static_cast<float>(size_)),
76   drawing_layer(drawing_layer_),
77   particles()
78 {
79   if (life_time == 0) {
80     live_forever = true;
81   } else {
82     live_forever = false;
83     timer.start(life_time);
84   }
85 
86   // create particles
87   for (int p = 0; p < number; p++)
88   {
89     auto particle = std::make_unique<Particle>();
90     particle->pos = epicenter;
91 
92     float velocity = (min_initial_velocity == max_initial_velocity) ? min_initial_velocity :
93                      graphicsRandom.randf(min_initial_velocity, max_initial_velocity);
94     float angle = (min_angle == max_angle) ?
95       math::radians(static_cast<float>(min_angle)) :
96       math::radians(graphicsRandom.randf(static_cast<float>(min_angle), static_cast<float>(max_angle)));
97     // Note that angle defined as clockwise from vertical (up is zero degrees, right is 90 degrees)
98     particle->vel.x = (sinf(angle)) * velocity;
99     particle->vel.y = (-cosf(angle)) * velocity;
100 
101     particles.push_back(std::move(particle));
102   }
103 }
104 
105 void
update(float dt_sec)106 Particles::update(float dt_sec)
107 {
108   Vector camera = Sector::get().get_camera().get_translation();
109 
110   // update particles
111   for (auto i = particles.begin(); i != particles.end(); ) {
112     (*i)->pos.x += (*i)->vel.x * dt_sec;
113     (*i)->pos.y += (*i)->vel.y * dt_sec;
114 
115     (*i)->vel.x += accel.x * dt_sec;
116     (*i)->vel.y += accel.y * dt_sec;
117 
118     if ((*i)->pos.x < camera.x || (*i)->pos.x > static_cast<float>(SCREEN_WIDTH) + camera.x ||
119        (*i)->pos.y < camera.y || (*i)->pos.y > static_cast<float>(SCREEN_HEIGHT) + camera.y) {
120       i = particles.erase(i);
121     } else {
122       ++i;
123     }
124   }
125 
126   if ((timer.check() && !live_forever) || particles.size() == 0)
127     remove_me();
128 }
129 
130 void
draw(DrawingContext & context)131 Particles::draw(DrawingContext& context)
132 {
133   // draw particles
134   for (auto& particle : particles) {
135     context.color().draw_filled_rect(Rectf(particle->pos, Sizef(size,size)), color, drawing_layer);
136   }
137 }
138 
139 /* EOF */
140