src/object/snow_particle_system.cpp

Go to the documentation of this file.
00001 //  SuperTux
00002 //  Copyright (C) 2006 Matthias Braun <matze@braunis.de>
00003 //
00004 //  This program is free software: you can redistribute it and/or modify
00005 //  it under the terms of the GNU General Public License as published by
00006 //  the Free Software Foundation, either version 3 of the License, or
00007 //  (at your option) any later version.
00008 //
00009 //  This program is distributed in the hope that it will be useful,
00010 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 //  GNU General Public License for more details.
00013 //
00014 //  You should have received a copy of the GNU General Public License
00015 //  along with this program.  If not, see <http://www.gnu.org/licenses/>.
00016 
00017 #include "object/snow_particle_system.hpp"
00018 
00019 #include <math.h>
00020 
00021 #include "math/random_generator.hpp"
00022 #include "supertux/globals.hpp"
00023 #include "video/drawing_context.hpp"
00024 
00025 // TODO: tweak values
00026 namespace SNOW {
00027 static const float SPIN_SPEED = 60.0f;
00028 static const float WIND_SPEED = 30.0f; // max speed of wind will be randf(WIND_SPEED) * randf(STATE_LENGTH)
00029 static const float STATE_LENGTH = 5.0f;
00030 static const float DECAY_RATIO = 0.2f; // ratio of attack speed to decay speed
00031 static const float EPSILON = 0.5f; //velocity changes by up to this much each tick
00032 static const float WOBBLE_DECAY = 0.99f; //wobble decays exponentially by this much each tick
00033 static const float WOBBLE_FACTOR = 4 * .005f; //wobble approaches drift_speed by this much each tick
00034 }
00035 
00036 SnowParticleSystem::SnowParticleSystem() :
00037   state(RELEASING),
00038   timer(),
00039   gust_onset(0),
00040   gust_current_velocity(0)
00041 {
00042   snowimages[0] = Surface::create("images/objects/particles/snow2.png");
00043   snowimages[1] = Surface::create("images/objects/particles/snow1.png");
00044   snowimages[2] = Surface::create("images/objects/particles/snow0.png");
00045 
00046   virtual_width = SCREEN_WIDTH * 2;
00047 
00048   timer.start(.01);
00049 
00050   // create some random snowflakes
00051   size_t snowflakecount = size_t(virtual_width/10.0);
00052   for(size_t i=0; i<snowflakecount; ++i) {
00053     SnowParticle* particle = new SnowParticle;
00054     int snowsize = graphicsRandom.rand(3);
00055 
00056     particle->pos.x = graphicsRandom.randf(virtual_width);
00057     particle->pos.y = graphicsRandom.randf(SCREEN_HEIGHT);
00058     particle->anchorx = particle->pos.x + (graphicsRandom.randf(-0.5, 0.5) * 16);
00059     // drift will change with wind gusts
00060     particle->drift_speed = graphicsRandom.randf(-0.5, 0.5) * 0.3;
00061     particle->wobble = 0.0;
00062 
00063     particle->texture = snowimages[snowsize];
00064     particle->flake_size = powf(snowsize+3,4); // since it ranges from 0 to 2
00065 
00066     particle->speed = 2 * (1 + (2 - snowsize)/2 + graphicsRandom.randf(1.8)) * 10; // gravity
00067 
00068     // Spinning
00069     particle->angle = graphicsRandom.randf(360.0);
00070     particle->spin_speed = graphicsRandom.randf(-SNOW::SPIN_SPEED,SNOW::SPIN_SPEED);
00071 
00072     particles.push_back(particle);
00073   }
00074 }
00075 
00076 void
00077 SnowParticleSystem::parse(const Reader& reader)
00078 {
00079   z_pos = reader_get_layer (reader, /* default = */ LAYER_BACKGROUND1);
00080 }
00081 
00082 SnowParticleSystem::~SnowParticleSystem()
00083 {
00084 }
00085 
00086 void SnowParticleSystem::update(float elapsed_time)
00087 {
00088   // Simple ADSR wind gusts
00089 
00090   if (timer.check()) {
00091     // Change state
00092     state = (State) ((state + 1) % MAX_STATE);
00093 
00094     if(state == RESTING) {
00095       // stop wind
00096       gust_current_velocity = 0;
00097       // new wind strength
00098       gust_onset   = graphicsRandom.randf(-SNOW::WIND_SPEED, SNOW::WIND_SPEED);
00099     }
00100     timer.start(graphicsRandom.randf(SNOW::STATE_LENGTH));
00101   }
00102 
00103   // Update velocities
00104   switch(state) {
00105     case ATTACKING:
00106       gust_current_velocity += gust_onset * elapsed_time;
00107       break;
00108     case DECAYING:
00109       gust_current_velocity -= gust_onset * elapsed_time * SNOW::DECAY_RATIO;
00110       break;
00111     case RELEASING:
00112       // uses current time/velocity instead of constants
00113       gust_current_velocity -= gust_current_velocity * elapsed_time / timer.get_timeleft();
00114       break;
00115     case SUSTAINING:
00116     case RESTING:
00117       //do nothing
00118       break;
00119     default:
00120       assert(false);
00121   }
00122 
00123   std::vector<Particle*>::iterator i;
00124 
00125   for(i = particles.begin(); i != particles.end(); ++i) {
00126     SnowParticle* particle = (SnowParticle*) *i;
00127     float anchor_delta;
00128 
00129     // Falling
00130     particle->pos.y += particle->speed * elapsed_time;
00131     // Drifting (speed approaches wind at a rate dependent on flake size)
00132     particle->drift_speed += (gust_current_velocity - particle->drift_speed) / particle->flake_size + graphicsRandom.randf(-SNOW::EPSILON,SNOW::EPSILON);
00133     particle->anchorx += particle->drift_speed * elapsed_time;
00134     // Wobbling (particle approaches anchorx)
00135     particle->pos.x += particle->wobble * elapsed_time;
00136     anchor_delta = (particle->anchorx - particle->pos.x);
00137     particle->wobble += (SNOW::WOBBLE_FACTOR * anchor_delta) + graphicsRandom.randf(-SNOW::EPSILON, SNOW::EPSILON);
00138     particle->wobble *= SNOW::WOBBLE_DECAY;
00139     // Spinning
00140     particle->angle += particle->spin_speed * elapsed_time;
00141     particle->angle = fmodf(particle->angle, 360.0);
00142   }
00143 }
00144 
00145 /* EOF */

Generated on Mon Jun 9 03:38:20 2014 for SuperTux by  doxygen 1.5.1