2 // Copyright (C) 2006 Matthias Braun <matze@braunis.de>
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.
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.
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/>.
17 #include "object/snow_particle_system.hpp"
21 #include "math/random_generator.hpp"
22 #include "supertux/globals.hpp"
23 #include "video/drawing_context.hpp"
27 static const float SPIN_SPEED = 60.0f;
28 static const float WIND_SPEED = 30.0f; // max speed of wind will be randf(WIND_SPEED) * randf(STATE_LENGTH)
29 static const float STATE_LENGTH = 5.0f;
30 static const float DECAY_RATIO = 0.2f; // ratio of attack speed to decay speed
31 static const float EPSILON = 0.5f; //velocity changes by up to this much each tick
32 static const float WOBBLE_DECAY = 0.99f; //wobble decays exponentially by this much each tick
33 static const float WOBBLE_FACTOR = 4 * .005f; //wobble approaches drift_speed by this much each tick
36 SnowParticleSystem::SnowParticleSystem() :
40 gust_current_velocity(0)
42 snowimages[0] = Surface::create("images/objects/particles/snow2.png");
43 snowimages[1] = Surface::create("images/objects/particles/snow1.png");
44 snowimages[2] = Surface::create("images/objects/particles/snow0.png");
46 virtual_width = SCREEN_WIDTH * 2;
50 // create some random snowflakes
51 size_t snowflakecount = size_t(virtual_width/10.0);
52 for(size_t i=0; i<snowflakecount; ++i) {
53 SnowParticle* particle = new SnowParticle;
54 int snowsize = graphicsRandom.rand(3);
56 particle->pos.x = graphicsRandom.randf(virtual_width);
57 particle->pos.y = graphicsRandom.randf(SCREEN_HEIGHT);
58 particle->anchorx = particle->pos.x + (graphicsRandom.randf(-0.5, 0.5) * 16);
59 // drift will change with wind gusts
60 particle->drift_speed = graphicsRandom.randf(-0.5, 0.5) * 0.3;
61 particle->wobble = 0.0;
63 particle->texture = snowimages[snowsize];
64 particle->flake_size = powf(snowsize+3,4); // since it ranges from 0 to 2
66 particle->speed = 2 * (1 + (2 - snowsize)/2 + graphicsRandom.randf(1.8)) * 10; // gravity
69 particle->angle = graphicsRandom.randf(360.0);
70 particle->spin_speed = graphicsRandom.randf(-SNOW::SPIN_SPEED,SNOW::SPIN_SPEED);
72 particles.push_back(particle);
77 SnowParticleSystem::parse(const Reader& reader)
79 z_pos = reader_get_layer (reader, /* default = */ LAYER_BACKGROUND1);
82 SnowParticleSystem::~SnowParticleSystem()
86 void SnowParticleSystem::update(float elapsed_time)
88 // Simple ADSR wind gusts
92 state = (State) ((state + 1) % MAX_STATE);
94 if(state == RESTING) {
96 gust_current_velocity = 0;
98 gust_onset = graphicsRandom.randf(-SNOW::WIND_SPEED, SNOW::WIND_SPEED);
100 timer.start(graphicsRandom.randf(SNOW::STATE_LENGTH));
106 gust_current_velocity += gust_onset * elapsed_time;
109 gust_current_velocity -= gust_onset * elapsed_time * SNOW::DECAY_RATIO;
112 // uses current time/velocity instead of constants
113 gust_current_velocity -= gust_current_velocity * elapsed_time / timer.get_timeleft();
123 std::vector<Particle*>::iterator i;
125 for(i = particles.begin(); i != particles.end(); ++i) {
126 SnowParticle* particle = (SnowParticle*) *i;
130 particle->pos.y += particle->speed * elapsed_time;
131 // Drifting (speed approaches wind at a rate dependent on flake size)
132 particle->drift_speed += (gust_current_velocity - particle->drift_speed) / particle->flake_size + graphicsRandom.randf(-SNOW::EPSILON,SNOW::EPSILON);
133 particle->anchorx += particle->drift_speed * elapsed_time;
134 // Wobbling (particle approaches anchorx)
135 particle->pos.x += particle->wobble * elapsed_time;
136 anchor_delta = (particle->anchorx - particle->pos.x);
137 particle->wobble += (SNOW::WOBBLE_FACTOR * anchor_delta) + graphicsRandom.randf(-SNOW::EPSILON, SNOW::EPSILON);
138 particle->wobble *= SNOW::WOBBLE_DECAY;
140 particle->angle += particle->spin_speed * elapsed_time;
141 particle->angle = fmodf(particle->angle, 360.0);