shake.cpp

Go to the documentation of this file.
00001 
00002 //            Copyright (C) 2004-2007 by The Allacrost Project
00003 //                         All Rights Reserved
00004 //
00005 // This code is licensed under the GNU GPL version 2. It is free software 
00006 // and you may modify it and/or redistribute it under the terms of this license.
00007 // See http://www.gnu.org/copyleft/gpl.html for details.
00009 
00010 #include "utils.h"
00011 #include <cassert>
00012 #include <cstdarg>
00013 #include "video.h"
00014 #include <math.h>
00015 #include "gui.h"
00016 
00017 using namespace std;
00018 using namespace hoa_video::private_video;
00019 
00020 namespace hoa_video 
00021 {
00022 
00023 // time between screen shake updates in milliseconds
00024 const int32 VIDEO_TIME_BETWEEN_SHAKE_UPDATES = 50;  
00025 
00026 //-----------------------------------------------------------------------------
00027 // ShakeScreen: shakes the screen with a given force and shake method
00028 //              If you want it to shake until you manually stop it, then
00029 //              pass in VIDEO_FALLOFF_NONE and 0.0f for falloffTime
00030 //-----------------------------------------------------------------------------
00031 
00032 bool GameVideo::ShakeScreen(float force, float falloff_time, ShakeFalloff falloff_method)
00033 {
00034   // check inputs
00035   if(force < 0.0f)
00036   {
00037     if(VIDEO_DEBUG)
00038       cerr << "VIDEO ERROR: passed negative force to ShakeScreen()!" << endl;
00039     return false;
00040   }
00041 
00042   if(falloff_time < 0.0f)
00043   {
00044     if(VIDEO_DEBUG)
00045       cerr << "VIDEO ERROR: passed negative falloff time to ShakeScreen()!" << endl;
00046     return false;
00047   }
00048 
00049   if(falloff_method <= VIDEO_FALLOFF_INVALID || falloff_method >= VIDEO_FALLOFF_TOTAL)
00050   {
00051     if(VIDEO_DEBUG)
00052       cerr << "VIDEO ERROR: passed invalid shake method to ShakeScreen()!" << endl;
00053     return false;
00054   }
00055   
00056   if(falloff_time == 0.0f && falloff_method != VIDEO_FALLOFF_NONE)
00057   {
00058     if(VIDEO_DEBUG)
00059       cerr << "VIDEO ERROR: ShakeScreen() called with 0.0f (infinite), but falloff method was not VIDEO_FALLOFF_NONE!" << endl;
00060     return false;
00061   }
00062     
00063   // create the shake force structure
00064   
00065   int32 milliseconds = int32(falloff_time * 1000);
00066   ShakeForce s;
00067   s.current_time  = 0;
00068   s.end_time      = milliseconds;
00069   s.initial_force = force;
00070   
00071   
00072   // set up the interpolation
00073   switch(falloff_method)
00074   {
00075     case VIDEO_FALLOFF_NONE:
00076       s.interpolator.SetMethod(VIDEO_INTERPOLATE_SRCA);
00077       s.interpolator.Start(force, 0.0f, milliseconds);
00078       break;
00079     
00080     case VIDEO_FALLOFF_EASE:
00081       s.interpolator.SetMethod(VIDEO_INTERPOLATE_EASE);
00082       s.interpolator.Start(0.0f, force, milliseconds);
00083       break;
00084     
00085     case VIDEO_FALLOFF_LINEAR:
00086       s.interpolator.SetMethod(VIDEO_INTERPOLATE_LINEAR);
00087       s.interpolator.Start(force, 0.0f, milliseconds);
00088       break;
00089       
00090     case VIDEO_FALLOFF_GRADUAL:
00091       s.interpolator.SetMethod(VIDEO_INTERPOLATE_SLOW);
00092       s.interpolator.Start(force, 0.0f, milliseconds);
00093       break;
00094       
00095     case VIDEO_FALLOFF_SUDDEN:
00096       s.interpolator.SetMethod(VIDEO_INTERPOLATE_FAST);
00097       s.interpolator.Start(force, 0.0f, milliseconds);
00098       break;
00099     
00100     default:
00101     {
00102       if(VIDEO_DEBUG)
00103         cerr << "VIDEO ERROR: falloff method passed to ShakeScreen() was not supported!" << endl;
00104       return false;
00105     }   
00106   };
00107   
00108   // add the shake force to GameVideo's list
00109   _shake_forces.push_front(s);
00110   
00111   return true;
00112 }
00113 
00114 
00115 //-----------------------------------------------------------------------------
00116 // StopShaking: removes ALL shaking on the screen
00117 //-----------------------------------------------------------------------------
00118 
00119 bool GameVideo::StopShaking()
00120 {
00121   _shake_forces.clear();
00122   _x_shake = _y_shake = 0.0f;
00123   return true;
00124 }
00125 
00126 
00127 //-----------------------------------------------------------------------------
00128 // IsShaking: returns true if the screen has any shake effect applied to it
00129 //-----------------------------------------------------------------------------
00130 
00131 bool GameVideo::IsShaking()
00132 {
00133   return !_shake_forces.empty();
00134 }
00135 
00136 
00137 //-----------------------------------------------------------------------------
00138 // _RoundForce: rounds a force to an integer. Whether to round up or round down
00139 //             is based on the fractional part. A force of 1.37 has a 37%
00140 //             chance of being a 2, else it's a 1
00141 //             This is necessary because otherwise a shake force of 0.5f
00142 //             would get rounded to zero all the time even though there is some
00143 //             force
00144 //-----------------------------------------------------------------------------
00145 
00146 float GameVideo::_RoundForce(float force)
00147 {
00148   int32 fraction_pct = int32(force * 100) - (int32(force) * 100);
00149   
00150   int32 r = rand()%100;
00151   if(fraction_pct > r)
00152     force = ceilf(force);
00153   else
00154     force = floorf(force);
00155     
00156   return force;
00157 }
00158 
00159 
00160 //-----------------------------------------------------------------------------
00161 // _UpdateShake: called once per frame to update the the shake effects
00162 //              and update the shake x,y offsets
00163 //-----------------------------------------------------------------------------
00164 
00165 void GameVideo::_UpdateShake(int32 frame_time)
00166 {
00167   if(_shake_forces.empty())
00168   {
00169     _x_shake = _y_shake = 0;
00170     return;
00171   }
00172 
00173   // first, update all the shake effects and calculate the net force, i.e.
00174   // the sum of the forces of all the shakes
00175   
00176   float net_force = 0.0f;
00177   
00178   list<ShakeForce>::iterator iShake = _shake_forces.begin();
00179   list<ShakeForce>::iterator iEnd   = _shake_forces.end();
00180   
00181   while(iShake != iEnd)
00182   {
00183     ShakeForce &s = *iShake;
00184     s.current_time += frame_time;
00185 
00186     if(s.end_time != 0 && s.current_time >= s.end_time)
00187     {
00188       iShake = _shake_forces.erase(iShake);
00189     }
00190     else
00191     {
00192       s.interpolator.Update(frame_time);
00193       net_force += s.interpolator.GetValue();
00194       ++iShake; 
00195     }
00196   } 
00197 
00198   // cap the max update frequency
00199   
00200   static int32 time_til_next_update = 0;    
00201   time_til_next_update -= frame_time;
00202   
00203   if(time_til_next_update > 0)
00204     return;
00205   
00206   time_til_next_update = VIDEO_TIME_BETWEEN_SHAKE_UPDATES;
00207 
00208 
00209   // now that we have our force (finally), calculate the proper shake offsets
00210   // note that this doesn't produce a radially symmetric distribution of offsets
00211   // but I think it's not noticeable so... :)
00212   
00213   _x_shake = _RoundForce(RandomFloat(-net_force, net_force));
00214   _y_shake = _RoundForce(RandomFloat(-net_force, net_force)); 
00215 }
00216 
00217 
00218 }  // namespace hoa_video

Generated on Fri Jul 6 23:11:23 2007 for Hero of Allacrost by  doxygen 1.5.1