From 8988ca5827de6c3aedc3308becf955675726a6c8 Mon Sep 17 00:00:00 2001 From: mathnerd314 Date: Mon, 18 Jan 2010 23:27:55 +0000 Subject: [PATCH] Snow ADSR (bug 221) This has the same ideas as the patch but is implemented slightly differently. Tweaks to various constants/timings welcome. git-svn-id: http://supertux.lethargik.org/svn/supertux/trunk/supertux@6261 837edb03-e0f3-0310-88ca-d4d4e8b29345 --- src/object/particlesystem.cpp | 2 +- src/object/particlesystem.hpp | 3 ++ src/object/snow_particle_system.cpp | 79 +++++++++++++++++++++++++++++++++---- src/object/snow_particle_system.hpp | 33 +++++++++++++++- 4 files changed, 107 insertions(+), 10 deletions(-) diff --git a/src/object/particlesystem.cpp b/src/object/particlesystem.cpp index 76846966a..ae15ba07d 100644 --- a/src/object/particlesystem.cpp +++ b/src/object/particlesystem.cpp @@ -66,7 +66,7 @@ void ParticleSystem::draw(DrawingContext& context) //if(pos.x > virtual_width) pos.x -= virtual_width; //if(pos.y > virtual_height) pos.y -= virtual_height; - context.draw_surface(particle->texture, pos, z_pos); + context.draw_surface(particle->texture, pos, particle->angle, Color(1.0f, 1.0f, 1.0f), Blend(), z_pos); } context.pop_transform(); diff --git a/src/object/particlesystem.hpp b/src/object/particlesystem.hpp index 0e72620f3..78e3616f4 100644 --- a/src/object/particlesystem.hpp +++ b/src/object/particlesystem.hpp @@ -55,6 +55,7 @@ protected: public: Particle() : pos(), + angle(), texture() {} @@ -62,6 +63,8 @@ protected: {} Vector pos; + // angle at which to draw particle + float angle; SurfacePtr texture; private: diff --git a/src/object/snow_particle_system.cpp b/src/object/snow_particle_system.cpp index cc02ffc1b..a0efa3550 100644 --- a/src/object/snow_particle_system.cpp +++ b/src/object/snow_particle_system.cpp @@ -22,7 +22,22 @@ #include "supertux/globals.hpp" #include "video/drawing_context.hpp" -SnowParticleSystem::SnowParticleSystem() +// TODO: tweak values +namespace SNOW { +static const float SPIN_SPEED = 60.0f; +static const float WIND_SPEED = 30.0f; // max speed of wind will be randf(WIND_SPEED) * randf(STATE_LENGTH) +static const float STATE_LENGTH = 5.0f; +static const float DECAY_RATIO = 0.2f; // ratio of attack speed to decay speed +static const float EPSILON = 0.5f; //velocity changes by up to this much each tick +static const float WOBBLE_DECAY = 0.99f; //wobble decays exponentially by this much each tick +static const float WOBBLE_FACTOR = 4 * .005f; //wobble approaches drift_speed by this much each tick +} + +SnowParticleSystem::SnowParticleSystem() : + state(RELEASING), + timer(), + gust_onset(0), + gust_current_velocity(0) { snowimages[0] = Surface::create("images/objects/particles/snow2.png"); snowimages[1] = Surface::create("images/objects/particles/snow1.png"); @@ -30,6 +45,8 @@ SnowParticleSystem::SnowParticleSystem() virtual_width = SCREEN_WIDTH * 2; + timer.start(.01); + // create some random snowflakes size_t snowflakecount = size_t(virtual_width/10.0); for(size_t i=0; ipos.x = systemRandom.randf(virtual_width); particle->pos.y = systemRandom.randf(SCREEN_HEIGHT); particle->anchorx = particle->pos.x + (systemRandom.randf(-0.5, 0.5) * 16); + // drift will change with wind gusts particle->drift_speed = systemRandom.randf(-0.5, 0.5) * 0.3; particle->wobble = 0.0; particle->texture = snowimages[snowsize]; + particle->flake_size = powf(snowsize+3,4); // since it ranges from 0 to 2 - particle->speed = 1 + (2 - snowsize)/2 + systemRandom.randf(1.8); - particle->speed *= 20; // gravity + particle->speed = 2 * (1 + (2 - snowsize)/2 + systemRandom.randf(1.8)) * 10; // gravity + + // Spinning + particle->angle = systemRandom.randf(360.0); + particle->spin_speed = systemRandom.randf(-SNOW::SPIN_SPEED,SNOW::SPIN_SPEED); particles.push_back(particle); } @@ -63,19 +85,60 @@ SnowParticleSystem::~SnowParticleSystem() void SnowParticleSystem::update(float elapsed_time) { + // Simple ADSR wind gusts + + if (timer.check()) { + // Change state + state = (State) ((state + 1) % MAX_STATE); + + if(state == RESTING) { + // stop wind + gust_current_velocity = 0; + // new wind strength + gust_onset = systemRandom.randf(-SNOW::WIND_SPEED, SNOW::WIND_SPEED); + } + timer.start(systemRandom.randf(SNOW::STATE_LENGTH)); + } + + // Update velocities + switch(state) { + case ATTACKING: + gust_current_velocity += gust_onset * elapsed_time; + break; + case DECAYING: + gust_current_velocity -= gust_onset * elapsed_time * SNOW::DECAY_RATIO; + break; + case RELEASING: + // uses current time/velocity instead of constants + gust_current_velocity -= gust_current_velocity * elapsed_time / timer.get_timeleft(); + break; + case SUSTAINING: + case RESTING: + //do nothing + break; + default: + assert(false); + } + std::vector::iterator i; for(i = particles.begin(); i != particles.end(); ++i) { SnowParticle* particle = (SnowParticle*) *i; float anchor_delta; + // Falling particle->pos.y += particle->speed * elapsed_time; - particle->pos.x += particle->wobble * elapsed_time /* * particle->speed * 0.125*/; - - anchor_delta = (particle->anchorx - particle->pos.x); - particle->wobble += (4 * anchor_delta * 0.05) + systemRandom.randf(-0.5, 0.5); - particle->wobble *= 0.99f; + // Drifting (speed approaches wind at a rate dependent on flake size) + particle->drift_speed += (gust_current_velocity - particle->drift_speed) / particle->flake_size + systemRandom.randf(-SNOW::EPSILON,SNOW::EPSILON); particle->anchorx += particle->drift_speed * elapsed_time; + // Wobbling (particle approaches anchorx) + particle->pos.x += particle->wobble * elapsed_time; + anchor_delta = (particle->anchorx - particle->pos.x); + particle->wobble += (SNOW::WOBBLE_FACTOR * anchor_delta) + systemRandom.randf(-SNOW::EPSILON, SNOW::EPSILON); + particle->wobble *= SNOW::WOBBLE_DECAY; + // Spinning + particle->angle += particle->spin_speed * elapsed_time; + particle->angle = fmodf(particle->angle, 360.0); } } diff --git a/src/object/snow_particle_system.hpp b/src/object/snow_particle_system.hpp index f66e923fb..682eb48ca 100644 --- a/src/object/snow_particle_system.hpp +++ b/src/object/snow_particle_system.hpp @@ -18,6 +18,7 @@ #define HEADER_SUPERTUX_OBJECT_SNOW_PARTICLE_SYSTEM_HPP #include "object/particlesystem.hpp" +#include "supertux/timer.hpp" class SnowParticleSystem : public ParticleSystem { @@ -41,14 +42,44 @@ private: float anchorx; float drift_speed; + // Turning speed + float spin_speed; + + // for inertia + unsigned int flake_size; + SnowParticle() : speed(), wobble(), anchorx(), - drift_speed() + drift_speed(), + spin_speed(), + flake_size() {} }; + // Wind is simulated in discrete "gusts" + + // Gust state + enum State { + ATTACKING, + DECAYING, + SUSTAINING, + RELEASING, + RESTING, + MAX_STATE + }; + State state; + + + // Gust state delay timer + Timer timer; + + // Peak magnitude of gust is gust_onset * randf(5) + float gust_onset, + // Current blowing velocity of gust + gust_current_velocity; + SurfacePtr snowimages[3]; private: -- 2.11.0