Making a 3D game with Ogre – Adding Effects

Google+ Pinterest LinkedIn Tumblr +

DOWNLOAD THE DEMO AND SOURCE CODE FOR WINDOWS

DOWNLOAD THE DEMO AND SOURCE CODE FOR LINUX

RETURN TO THE TUTORIAL INDEX

With collision detection up and running it is now possible to destroy the enemies. The effect is a little unsatisfying though because they simply disappear. We can use a particle system for an explosion, but by default particle systems in Ogre are designed to be permanent effects i.e. once added to the scene a particle system will display its effect until it is removed. Since an explosion is a one off “bang”, we need a way to add a particle system, wait for it to finish, and then remove it from the scene. The ParticleSystemEffect class will be used for this purpose.

ParticleSystemEffect.h

/*
 *  ParticleSystemEffect.h
 *
 *      Author:  Matthew Casperson
 * Email:  matthewcasperson@gmail.com
 * Website: http://www.brighthub.com/hubfolio/matthew-casperson.aspx
 */

#ifndef PARTICLESYSTEMEFFECT_H_
#define PARTICLESYSTEMEFFECT_H_

#include "PersistentFrameListener.h"

class ParticleSystemEffect :
 public PersistentFrameListener
{
public:
 ParticleSystemEffect();
 ~ParticleSystemEffect();

 void Startup(const Vector3& position, const String& particleSystemName);
 void Shutdown();

 bool FrameStarted(const FrameEvent& evt);

protected:
 void InitialiseVariables();

 float    timeToLive;
 SceneNode*   sceneNode;
 ParticleSystem*  particleSystem;
};

#endif

ParticleSystemEffect.cpp

#include "ParticleSystemEffect.h"
#include "GameLevel.h"
#include "Utilities.h"

ParticleSystemEffect::ParticleSystemEffect()
{
 InitialiseVariables();
}

ParticleSystemEffect::~ParticleSystemEffect()
{

}

The Startup function is very similar to the Startup functions for the enemies and weapons in that it creates a SceneNode to which it attaches an Ogre object (a particle system in this case).

void ParticleSystemEffect::Startup(const Vector3& position, const String& particleSystemName)
{
 PersistentFrameListener::Startup();
 
 sceneNode = GAMELEVEL.GetPlayerSceneNode()->createChildSceneNode(position);
 particleSystem = GAMELEVEL.GetSceneManager()->createParticleSystem(Utilities::GetUniqueName("ParticleSystemEffect"), particleSystemName);
 sceneNode->attachObject(particleSystem);


We then need to work out how long the particle system should run for before being removed from the level. The duration property of the emitter defines how long a particle system should emit particles for. When you add this value to the to the life span of the individual particles you can work out how long the effect will run for. We store this value in the timeToLive variable.

 timeToLive = particleSystem->getEmitter(0)->getDuration() + particleSystem->getEmitter(0)->getTimeToLive();
}

void ParticleSystemEffect::Shutdown()
{
 sceneNode->detachObject(particleSystem);
 GAMELEVEL.GetSceneManager()->destroyParticleSystem(particleSystem);
 GAMELEVEL.GetPlayerSceneNode()->removeAndDestroyChild(sceneNode->getName());
 InitialiseVariables();
 PersistentFrameListener::Shutdown();
}

void ParticleSystemEffect::InitialiseVariables()
{
 timeToLive = 0;
 sceneNode = NULL;
 particleSystem = NULL;
}

The FrameStarted function will count down the timeToLive variable, and when it reaches zero the Shutdown function is called, removing the particle system from the level.

bool ParticleSystemEffect::FrameStarted(const FrameEvent& evt)
{
 timeToLive -= evt.timeSinceLastFrame;
 if (timeToLive <= 0)
  Shutdown();
 
 return true;
}

Just like the enemies, weapons and other objects that respond to Ogre frame events, ParticleSystemEffect objects exist in a pool, with those that have finished being in a suspended state until they are reused. The ParticleSystemEffectManager class maintains this pool of ParticleSystemEffect objects. The code to create ParticleSystemEffect objects, store them in a pool and return unused objects is the same as the corresponding code in the WeaponDatabase and EnemyDatabase classes. In fact the ParticleSystemEffectManager class does nothing but maintain this pool of ParticleSystemEffect objects.

ParticleSystemEffectManager.h

/*
 *  ParticleSystemEffectManager.h
 *
 *      Author:  Matthew Casperson
 * Email:  matthewcasperson@gmail.com
 * Website: http://www.brighthub.com/hubfolio/matthew-casperson.aspx
 */

#ifndef PARTICLESYSTEMEFFECTMANAGER_H_
#define PARTICLESYSTEMEFFECTMANAGER_H_

#include "ParticleSystemEffect.h"
#include "list"

typedef std::list ParticleSystemEffectList;

#define PARTICLESYSTEMEFFECTMANAGER ParticleSystemEffectManager::Instance()

class ParticleSystemEffectManager
{
public:
 ~ParticleSystemEffectManager();
 static ParticleSystemEffectManager& Instance()
 {
  static ParticleSystemEffectManager instance;
  return instance;
 }

 void Startup();
 void Shutdown();

 ParticleSystemEffect* GetParticleSystemEffect();

protected:
 ParticleSystemEffectManager();
 ParticleSystemEffect* CreateParticleSystemEffect();
 ParticleSystemEffectList particleSystemEffectList;
};

#endif

ParticleSystemEffectManager.cpp

#include "ParticleSystemEffectManager.h"

ParticleSystemEffectManager::ParticleSystemEffectManager()
{

}

ParticleSystemEffectManager::~ParticleSystemEffectManager()
{

}

void ParticleSystemEffectManager::Startup()
{
 
}

void ParticleSystemEffectManager::Shutdown()
{
 for (ParticleSystemEffectList::iterator iter = particleSystemEffectList.begin();
  iter != particleSystemEffectList.end(); ++iter)
 {
  ParticleSystemEffect* effect = *iter;
  if (effect->IsStarted())
   effect->Shutdown();

  delete effect;
 }

 particleSystemEffectList.clear();
}

ParticleSystemEffect* ParticleSystemEffectManager::GetParticleSystemEffect()
{
 for (ParticleSystemEffectList::iterator iter = particleSystemEffectList.begin();
  iter != particleSystemEffectList.end(); ++iter)
 {
  ParticleSystemEffect* effect = *iter;
  if (!effect->IsStarted())
   return effect;
 }

 ParticleSystemEffect* effect = CreateParticleSystemEffect();
 particleSystemEffectList.push_back(effect);
 return effect;
}

ParticleSystemEffect* ParticleSystemEffectManager::CreateParticleSystemEffect()
{
 return new ParticleSystemEffect();
}

In order to display a particle system effect for the explosion we create start a ParticleSystemEffect object when an enemy is shut down. We also play an explosion sound effect. The new killed parameter lets the Shutdown function know if the enemy is being removed from the level because it was destroyed, or because the level itself is being shutdown (in which case we don’t want to add any effects).

void Enemy::Shutdown(const bool killed)
{
 if (killed)
 {
  PARTICLESYSTEMEFFECTMANAGER.GetParticleSystemEffect()->Startup(
   enemySceneNode->getPosition(),
   EXPLOSION_PARTICLE_SYSTEM);
  IRRKLANGENGINEMANAGER.GetSoundEngine()->play2D(EXPLOSION_SOUND);
 }
 
 GAMELEVEL.GetPlayerSceneNode()->removeAndDestroyChild(enemySceneNode->getName());
 InitialiseVariables();
 CollisionObject::Shutdown();
}

Similar code changes have been implemented in the Weapon class to show a small weapon hit effect.

4219711837_750a28d452.jpg

Share.

About Author

Leave A Reply