Making a 3D game with Ogre – Adding Sound 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

Ogre has no support for sounds – it is a graphics rendering engine only. Sound effect in the game will be provided courtesy of the IrrKlang sound engine, which is made by the guys who made the Irrlicht 3D engine. IrrKlang is a solid engine, and we are going to have to do very little to get it up and running.

We will wrap up the IrrKlang engine in a class call IrrKlangEngineManager. This is a very thin wrapper that basically starts the sound engine, exposes it so sound effect can be played, and cleans it up. In addition The IrrKlangEngineManager will maintain references to all the instances of RandomSoundEffect, which is a class that we will create to add random ambient noises to the level.

IrrKlangEngineManager.h

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

#ifndef IRRKLANGENGINEMANAGER_H_
#define IRRKLANGENGINEMANAGER_H_

#include "list"
#include "irrKlang.h"
#include "RandomSoundEffect.h"

typedef std::list RandomSoundEffectList;

using namespace irrklang;

#define IRRKLANGENGINEMANAGER IrrKlangEngineManager::Instance()

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

 void Startup();
 void Shutdown();

 ISoundEngine* GetSoundEngine() const {return engine;}
 RandomSoundEffect* GetRandomSoundEffect();

protected:
 IrrKlangEngineManager();
 void InitialiseVariables();
 ISoundEngine*   engine;
 RandomSoundEffectList randomSounds;
};

#endif

IrrKlangEngineManager.cpp

#include "IrrKlangEngineManager.h"

IrrKlangEngineManager::IrrKlangEngineManager()
{
 InitialiseVariables();
}

IrrKlangEngineManager::~IrrKlangEngineManager()
{

}

void IrrKlangEngineManager::InitialiseVariables()
{
 engine = NULL;
}

The Startup function initialises the IrrKlang engine, and keeps a pointer to it.

void IrrKlangEngineManager::Startup()
{
 engine = createIrrKlangDevice();
}

The Shutdown function shuts down and deletes all of the RandomSoundEffect objects, and the destroys the IrrKlang sound engine.

void IrrKlangEngineManager::Shutdown()
{
 for (RandomSoundEffectList::iterator iter = randomSounds.begin(); 
  iter != randomSounds.end(); ++iter)
 {
  RandomSoundEffect* effect = *iter;
  if (effect->IsStarted())
   effect->Shutdown();
  delete effect;
 }
 randomSounds.clear();
 engine->drop();
 InitialiseVariables();
}

Just like the WeaponDatabase, the IrrKlangEngineManager contains a collection of objects, RandomSoundEffect objects in this case, and will attempt to return an unused one from the pool when an object is requested through the GetRandomSoundEffect function, or will create a new RandomSoundEffect, add it to the pool, and then return it.

RandomSoundEffect* IrrKlangEngineManager::GetRandomSoundEffect()
{
 for (RandomSoundEffectList::const_iterator iter = randomSounds.begin(); 
  iter != randomSounds.end(); ++iter)
 {
  RandomSoundEffect* effect = *iter;
  if (!effect->IsStarted())
   return effect;
 }  

 RandomSoundEffect* effect = new RandomSoundEffect();
 randomSounds.push_back(effect);
 return effect;
}

In order to play a sound effect we call the play2D function from the IrrKlang sound engine. The Bullet class uses this function to play a sound effect whenever a bullet is fired.

float Bullet::Startup(const Vector3& position)
{
 Weapon::Startup(position);

 this->billboardSet = GAMELEVEL.GetSceneManager()->createBillboardSet(Utilities::GetUniqueName("BillboardSet"), 1);
 this->billboardSet->setMaterialName("Bullet");
 this->billboard = billboardSet->createBillboard(Vector3::ZERO, colour);
 this->weaponSceneNode->attachObject(billboardSet);
 this->weaponSceneNode->scale(BULLET_SCALE, BULLET_SCALE, BULLET_SCALE);
 IRRKLANGENGINEMANAGER.GetSoundEngine()->play2D(BULLET_SOUNDFX);
 return timeBetweenShots;
}

As was mentioned earlier, the RandomSoundEffect class is used to play ambient sound effects at random intervals throughout the level. It works by sitting in the background, and every second it will randomly determine if it should play a sound effect, based on a frequency that is supplied to the Startup function. A frequency of 10 means that every second there is a 1 in 10 chance the sound effect will be played.

RandomSoundEffect.h

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

#ifndef RANDOMSOUNDEFFECT_H_
#define RANDOMSOUNDEFFECT_H_

#include "PersistentFrameListener.h"

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

 void Startup(std::string filename, int frequency);
 void Shutdown();

 bool FrameStarted(const FrameEvent& evt);

protected:
 void InitialiseVariables();
 std::string filename;
 int   frequency;
 float  timeToNextCheck;
};

#endif

RandomSoundEffect.cpp

#include "RandomSoundEffect.h"
#include "IrrKlangEngineManager.h"
#include "stdlib.h"

RandomSoundEffect::RandomSoundEffect()
{
 InitialiseVariables();
}

RandomSoundEffect::~RandomSoundEffect()
{

}

void RandomSoundEffect::InitialiseVariables()
{
 filename = "";
 frequency = 0;
 timeToNextCheck = 0;
}

void RandomSoundEffect::Startup(std::string filename, int frequency)
{
 PersistentFrameListener::Startup();
 
 this->filename = filename;
 this->frequency = frequency;
}

void RandomSoundEffect::Shutdown()
{
 InitialiseVariables();
 PersistentFrameListener::Shutdown();
}

bool RandomSoundEffect::FrameStarted(const FrameEvent& evt)
{
 timeToNextCheck -= evt.timeSinceLastFrame;
 if (timeToNextCheck play2D(filename.c_str());
 }
 
 return true;
}

Finally, the DotSceneLoader is modified to create RandomSoundEffect objects, allows us to define the level sound effects from the XML file. If no frequency attribute is supplied, the sound effect is assumed to play continuously; otherwise a RandomSoundEffect object is created. You can view the XML file supplied with the demo to see how this is implemented.

The demo makes use of the new ability to play sound effects by adding a number ambient noises like a continuous loop of a rain sound effect, and a number of random thunder sound effects. A rain particle system has also been added – the DotSceneLoader already had the capability to add a particle system, so this didn’t require any code changes.

Share.

About Author

Leave A Reply