1 /////////////////////////////////////////////////////////////////////////////// 2 // Copyright (C) 2004-2011 by The Allacrost Project 3 // Copyright (C) 2012-2016 by Bertram (Valyria Tear) 4 // All Rights Reserved 5 // 6 // This code is licensed under the GNU GPL version 2. It is free software 7 // and you may modify it and/or redistribute it under the terms of this license. 8 // See http://www.gnu.org/copyleft/gpl.html for details. 9 /////////////////////////////////////////////////////////////////////////////// 10 11 /** *************************************************************************** 12 *** \file particle_effect.h 13 *** \author Raj Sharma, roos@allacrost.org 14 *** \author Yohann Ferreira, yohann ferreira orange fr 15 *** \brief Header file for particle effects 16 *** 17 *** Particle effects are basically nothing more than a collection of particle 18 *** systems. Many effects are just one system. However, for example, if you think 19 *** about a campfire effect, that might actually consist of fire + smoke + embers. 20 *** So, that's an example of an effect that consists of 3 systems. 21 *** 22 *** This file contains two classes: ParticleEffectDef, and ParticleEffect. 23 *** 24 *** ParticleEffectDef is a "definition" class, which holds a list of 25 *** ParticleSystemDefs. 26 *** 27 *** ParticleEffect is an "instance" class, which holds a list of 28 *** ParticleSystems. 29 *** 30 *** 31 *** This way, if you have 100 explosions, the properties of the 32 *** effect are stored only once in a ParticleEffectDef, and the only thing that 33 *** gets repeated 100 times is the ParticleEffect, which holds instance-specific stuff. 34 *** **************************************************************************/ 35 36 #ifndef __PARTICLE_EFFECT_HEADER__ 37 #define __PARTICLE_EFFECT_HEADER__ 38 39 #include "engine/video/particle_system.h" 40 41 namespace vt_script { 42 class ReadScriptDescriptor; 43 } 44 45 namespace vt_map 46 { 47 namespace private_map 48 { 49 class ParticleObject; 50 } 51 } 52 53 namespace vt_mode_manager 54 { 55 56 /*!*************************************************************************** 57 * \brief particle effect definition, just consists of each of its subsystems' 58 * definitions. 59 *****************************************************************************/ 60 61 class ParticleEffectDef 62 { 63 public: ParticleEffectDef()64 ParticleEffectDef(): 65 effect_width(0.0f), 66 effect_height(0.0f), 67 effect_collision_width(0.0f), 68 effect_collision_height(0.0f) 69 {} 70 Clear()71 void Clear() { 72 effect_width = 0.0f; 73 effect_height = 0.0f; 74 effect_collision_width = 0.0f; 75 effect_collision_height = 0.0f; 76 _systems.clear(); 77 } 78 79 /** The effect size in pixels, used to know when to display it when it used as 80 *** a map object for instance. It is used to compute the image rectangle. 81 *** \note Not used if equal to 0. 82 **/ 83 float effect_width; 84 float effect_height; 85 86 /** The effect collision size in pixels. 87 *** \note Not used if equal to 0. 88 **/ 89 float effect_collision_width; 90 float effect_collision_height; 91 92 //! list of system definitions 93 std::vector<ParticleSystemDef> _systems; 94 }; 95 96 97 /*!*************************************************************************** 98 * \brief particle effect, basically one coherent "effect" like an explosion, 99 * or snow falling from the sky. Consists of one or more ParticleSystems. 100 * An example of using multiple systems to create one effect would be 101 * a campfire where you have fire + smoke + glowing embers. 102 *****************************************************************************/ 103 104 class ParticleEffect 105 { 106 public: 107 /*! 108 * \brief Constructor 109 */ ParticleEffect()110 ParticleEffect() { 111 _Destroy(); 112 } 113 ParticleEffect(const std::string & effect_filename)114 ParticleEffect(const std::string &effect_filename) { 115 _Destroy(); 116 LoadEffect(effect_filename); 117 } 118 119 /** Create a particle effect without registering it to the particle manager. 120 *** It is useful managing a particle effect as a map object, for instance, 121 *** as one can control the drawing order. 122 *** \param filename The particle effect filename to load 123 *** \return whether the effect is valid. 124 **/ 125 bool LoadEffect(const std::string &effect_filename); 126 127 /*! 128 * \brief moves the effect to the specified position on the screen, 129 * This can be used if you want to move a particle system around 130 * on some flight path, or if you want to attach the system to an 131 * object. (e.g. smoke to a jet) 132 * \param x movement of system in x direction 133 * \param y movement of system in y direction 134 */ 135 void Move(float x, float y); 136 137 /*! 138 * \brief moves the effect dx and dy units relative to its current position 139 * \param dx x offset to move to from current x position 140 * \param dy y offset to move to from current y position 141 */ 142 void MoveRelative(float dx, float dy); 143 144 /*! 145 * \brief set the orientation of the effect (including all systems contained 146 * within the effect). This is essentially added to the emitter orientation 147 * for each system. For example, if you want to create a particle system for 148 * smoke coming out of a jet, set the emitter orientation to zero degrees (right) 149 * when you create the effect. Then, at runtime just call SetOrientation() every 150 * frame with the angle the jet is facing. 151 * \param angle rotation of particle system 152 */ SetOrientation(float angle)153 void SetOrientation(float angle) { 154 _orientation = angle; 155 } 156 157 /*! 158 * \brief set the position of an "attractor point". Any particle systems which use 159 * radial acceleration and have user-defined attractor points enabled will 160 * have particles move towards this point 161 * 162 * \note a positive radial acceleration will move a particle away from the attractor, 163 * and negative will move it towards it. 164 * \param x x coordiante of gravitation point 165 * \param y y coordiante of gravitation point 166 */ 167 void SetAttractorPoint(float x, float y); 168 169 /*! 170 * \brief returns true if the system is alive, i.e. the number of active 171 * particles is more than zero. This is used by the particle manager 172 * so it knows when to destroy an effect when registered to it. 173 * \return true if system is alive, false if dead 174 */ IsAlive()175 bool IsAlive() const { 176 return _alive; 177 } 178 179 /*! 180 * \brief stops this effect 181 * 182 * \param kill_immediate If this is true, the effect is immediately killed. If 183 * it isn't true, then we stop the effect from emitting 184 * new particles, and allow it to live until all the active 185 * particles fizzle out. 186 * \note When registered in the particle Manager, the effect will be destroyed 187 * at its end of life. 188 */ 189 void Stop(bool kill_immediate = false); 190 191 /*! 192 * \brief starts this effect 193 * \return whether the effect was started. 194 */ 195 bool Start(); 196 197 /*! 198 * \brief return the number of active particles in this effect 199 * \return number of particles in the system 200 */ GetNumParticles()201 int32_t GetNumParticles() const { 202 return _num_particles; 203 } 204 205 //! \brief return the position of the effect into x and y 206 const vt_common::Position2D& GetPosition() const; 207 208 /*! 209 * \brief return the age of the system, i.e. how many seconds it has been since 210 * it was created 211 * \return age of the system 212 */ GetAge()213 float GetAge() const { 214 return _age; 215 } 216 217 //! \brief Get the overall effect collision width/height in pixels. GetEffectCollisionWidth()218 float GetEffectCollisionWidth() const { 219 return _effect_def.effect_collision_width; 220 } GetEffectCollisionHeight()221 float GetEffectCollisionHeight() const { 222 return _effect_def.effect_collision_height; 223 } 224 225 //! \brief Get the overall effect image width/height in pixels. GetEffectWidth()226 float GetEffectWidth() const { 227 return _effect_def.effect_width; 228 } GetEffectHeight()229 float GetEffectHeight() const { 230 return _effect_def.effect_height; 231 } 232 233 IsLoaded()234 bool IsLoaded() const { 235 return _loaded; 236 } 237 238 //! \brief draws the effect. 239 void Draw(); 240 241 /*! 242 * \brief updates the effect. 243 * \param the new frame time 244 */ 245 void Update(float frame_time); 246 void Update(); 247 private: 248 /*! 249 * \brief destroys the effect. This is private so that only the ParticleManager class 250 * can destroy effects. 251 */ 252 void _Destroy(); 253 254 /*! 255 * \brief loads an effect definition from a particle file 256 * \param filename file to load the effect from 257 * \return Whether the effect def is valid 258 */ 259 bool _LoadEffectDef(const std::string &filename); 260 261 /** Creates the effect based on the particle effect definition. 262 *** _LoadEffectDef() must be called before this one. 263 **/ 264 bool _CreateEffect(); 265 266 //! \brief Helper function used to read a color subtable. 267 vt_video::Color _ReadColor(vt_script::ReadScriptDescriptor &particle_script, 268 const std::string ¶m_name); 269 270 //! The effect definition 271 ParticleEffectDef _effect_def; 272 273 //! list of subsystems that make up the effect. (for example, a fire effect might consist 274 //! of a flame + smoke + embers) 275 std::vector<ParticleSystem> _systems; 276 277 //! Tells whether the effect definition and systems arewere successfully loaded 278 bool _loaded; 279 280 //! position of the effect 281 vt_common::Position2D _pos; 282 283 //! position of attractor point 284 vt_common::Position2D _attractor; 285 286 //! orientation of the effect (angle in radians) 287 float _orientation; 288 289 //! is the effect is alive or not 290 bool _alive; 291 292 //! age of the effect (seconds since it was created) 293 float _age; 294 295 //! number of active particles (this is updated on each call to Update()) 296 int32_t _num_particles; 297 }; // class ParticleEffect 298 299 } // namespace vt_mode_manager 300 301 #endif //! __PARTICLE_EFFECT_HEADER__ 302