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
30Particles::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
66Particles::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
105void
106Particles::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
130void
131Particles::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