diff --git a/asteroids/Model.cc b/asteroids/Model.cc index 6268e52..c8af4e2 100644 --- a/asteroids/Model.cc +++ b/asteroids/Model.cc @@ -62,11 +62,22 @@ int Model::OnInit (int argc, char* argv[]) { mPlayerName = "Player"; + Engine::PlayMusic ("./data/sounds/intro_music.ogg"); + + Engine::RegisterListener (this, EventAccelerateStart); + Engine::RegisterListener (this, EventAccelerateStop); + return result; } bool Model::OnReceiveEvent (const Engine::EventBasePtr &event) { switch (event->mEventType) { + case EventAccelerateStart: + Engine::PlaySoundLoop("./data/sounds/thrust.wav", -1); + break; + case EventAccelerateStop: + Engine::HaltSoundLoop("./data/sounds/thrust.wav"); + break; case EventLevelComplete: return OnLevelComplete(); break; @@ -415,6 +426,8 @@ void Model::OnKillEntity (const Engine::EntityBase *entity) { GameEntityType entity_type = (GameEntityType) entity->mType; if (entity_type == GameEntityTypeAsteroid) { + Engine::PlaySound("./data/sounds/rock_destroyed.wav"); + unsigned int i; const AsteroidEntity *asteroid = static_cast(entity); mPoints += 150 + asteroid->mSubAsteroidsCount * 75; diff --git a/asteroids/ShipEntity.cc b/asteroids/ShipEntity.cc index 6490c76..d5009ab 100644 --- a/asteroids/ShipEntity.cc +++ b/asteroids/ShipEntity.cc @@ -126,6 +126,8 @@ void ShipEntity::Attack () { rocket_physics->mOrientation = entity_physic->mOrientation; rocket_physics->mVelocity = attack_dir.normalize(); rocket_physics->mVelocity *= ShipEntity::VarMaxSpeed.GetFloatValue() + 0.5; + + Engine::PlaySound ("./data/sounds/laser.wav"); } } diff --git a/data/sounds/sources.txt b/data/sounds/sources.txt new file mode 100644 index 0000000..1e4c3ba --- /dev/null +++ b/data/sounds/sources.txt @@ -0,0 +1,8 @@ +music.ogg DJad - Space Exploration (retrieved by Jamendo, http://www.jamendo.com/en/artist/DJad) +laser_samples.wav 93979__cormi__laser_weapon_02.wav (http://www.freesound.org/samplesViewSingle.php?id=93979) +thrust.wav http://www.freesound.org/samplesViewSingle.php?id=78559 +rock0.wav http://www.shockwave-sound.com/sound-effects/explosion%20sounds/damage.wav +laser0.wav http://www.nuedge.net/mightyshrimp/MyGame/FreeGameSounds/files/Ses_20050507_2009a_210.wav +laser1.wav http://www.nuedge.net/mightyshrimp/MyGame/FreeGameSounds/files/Ses_20050507_2009d_107.wav +laser2.wav http://www.nuedge.net/mightyshrimp/MyGame/FreeGameSounds/files/Ses_20050507_2009c_102_N.wav +laser3.wav http://www.nuedge.net/mightyshrimp/MyGame/FreeGameSounds/files/Ses_20050507_2009a_002.wav diff --git a/data/sounds/thrust.wav b/data/sounds/thrust.wav new file mode 100644 index 0000000..3081c90 Binary files /dev/null and b/data/sounds/thrust.wav differ diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index 853c78a..20d029e 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -3,13 +3,12 @@ CMAKE_MINIMUM_REQUIRED (VERSION 2.6) LIST( APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/CMake ) FIND_PACKAGE (SDL REQUIRED) +FIND_PACKAGE (SDL_mixer REQUIRED) FIND_PACKAGE (OpenGL REQUIRED) FIND_PACKAGE (PNG REQUIRED) FIND_PACKAGE (FreeType2 REQUIRED) FIND_PACKAGE (Boost COMPONENTS filesystem REQUIRED) -INCLUDE_DIRECTORIES (${Boost_INCLUDE_DIRS} ) - ADD_SUBDIRECTORY ( libraries ) SET ( ENGINE_SRCS @@ -17,13 +16,14 @@ SET ( ENGINE_SRCS ControllerBase.cc EntityBase.cc EntityFactoryBase.cc + EventBase.cc GameEntityBase.cc ModelBase.cc + OverlayBase.cc PhysicsBase.cc PhysicsEntityBase.cc + SoundBase.cc ViewBase.cc - EventBase.cc - OverlayBase.cc Commands.cc DrawingsGL.cc @@ -40,6 +40,8 @@ SET ( ENGINE_SRCS ) INCLUDE_DIRECTORIES ( + ${Boost_INCLUDE_DIRS} + ${SDLMIXER_INCLUDE_DIRS} ${PROJECT_SOURCE_DIR} libraries/mathlib/ libraries/coll2d/include @@ -55,6 +57,7 @@ ENDIF ( WIN32 ) TARGET_LINK_LIBRARIES ( Engine ${SDL_LIBRARY} + ${SDLMIXER_LIBRARY} ${OPENGL_LIBRARIES} ${PNG_LIBRARIES} ${Boost_LIBRARIES} diff --git a/engine/Engine.cc b/engine/Engine.cc index f66eb96..a18f812 100644 --- a/engine/Engine.cc +++ b/engine/Engine.cc @@ -5,6 +5,7 @@ #include "PhysicsBase.h" #include "CameraBase.h" +#include "SoundBase.h" #include "ViewBase.h" #include "ModelBase.h" @@ -69,12 +70,16 @@ int Engine::OnInit (int argc, char* argv[]) { // Initialize the SDL LogDebug ("Initializing SDL"); - if ( SDL_Init ( SDL_INIT_VIDEO ) < 0) { + if ( SDL_Init ( SDL_INIT_VIDEO | SDL_INIT_AUDIO ) < 0) { LogError ("Error initializing SDL: %s", SDL_GetError ()); exit (-1); } SDL_WM_SetCaption("Engine Initializing","Engine Initializing"); + /* Sound */ + mSoundManager = new SoundBase(); + mSoundManager->Init (argc, argv); + /* Model */ if (mModel == NULL) mModel = new ModelBase (); @@ -160,6 +165,12 @@ int Engine::OnInit (int argc, char* argv[]) { void Engine::OnDestroy () { SetStatus (EngineStatusDestroying); + if (mSoundManager) { + mSoundManager->Destroy(); + delete mSoundManager; + mSoundManager = NULL; + } + // Quit the SDL SDL_Quit (); diff --git a/engine/Engine.h b/engine/Engine.h index 3d3149e..8e27047 100644 --- a/engine/Engine.h +++ b/engine/Engine.h @@ -37,6 +37,7 @@ class ControllerBase; class PhysicsBase; class EntityFactoryBase; class EventManager; +class SoundBase; class Logging; class Commands; @@ -69,6 +70,7 @@ class Engine : public Module { mVariables = NULL; mEntityFactory = NULL; mEventManager = NULL; + mSoundManager = NULL; } virtual void MainLoop () { @@ -110,6 +112,7 @@ class Engine : public Module { PhysicsBase *mPhysics; EntityFactoryBase *mEntityFactory; EventManager *mEventManager; + SoundBase *mSoundManager; Logging *mLogging; Commands *mCommands; @@ -155,5 +158,6 @@ ControllerBase* EngineGetController (); #include "ModelBaseGlobal.h" #include "ViewBaseGlobal.h" #include "EventBaseGlobal.h" +#include "SoundBaseGlobal.h" #endif // _ENGINE_H diff --git a/engine/SoundBase.cc b/engine/SoundBase.cc new file mode 100644 index 0000000..8185e25 --- /dev/null +++ b/engine/SoundBase.cc @@ -0,0 +1,199 @@ +#include "SoundBase.h" +#include "SoundBaseGlobal.h" + +namespace Engine { + +static SoundBase* SoundInstance = NULL; + +/* Sound Sample */ +SoundSample::~SoundSample() { + Stop(); + + Mix_FreeChunk(mMixChunk); + mMixChunk = NULL; +} + +bool SoundSample::Load (const std::string &filename) { + assert (mMixChunk == NULL); + + LogDebug("Loading SoundSample %s", filename.c_str()); + mMixChunk = Mix_LoadWAV(filename.c_str()); + + if (mMixChunk == NULL) { + LogError("Loading of SoundSample %s failed: %s", filename.c_str(), Mix_GetError()); + return false; + } + + return true; +} + +void SoundSample::Play() { + mChannel = Mix_PlayChannel(-1, mMixChunk, 0); +} + +void SoundSample::Loop(int count) { + mChannel = Mix_PlayChannel(-1, mMixChunk, count); +} + +void SoundSample::Stop() { + if (mChannel != -1) + Mix_HaltChannel(mChannel); +} + +int SoundBase::OnInit(int argc, char* argv[]) { + SoundInstance = this; + + int audio_rate = 22050; + Uint16 audio_format = AUDIO_S16; + int audio_channels = 2; + int audio_buffers = 4096; + + LogDebug("Sound Init"); + if (Mix_OpenAudio (audio_rate, audio_format, audio_channels, audio_buffers)) { + LogError ("Unable to initialize the sound system!"); + } + + Mix_QuerySpec (&audio_rate, &audio_format, &audio_channels); + LogDebug("Sound: rate: %d channels: %d format: %d", audio_rate, audio_channels, audio_format); + + mCurrentMusicName = ""; + mCurrentMusic = NULL; + + Mix_VolumeMusic(MIX_MAX_VOLUME/2); + + return 0; +} + +void SoundBase::OnDestroy() { + LogDebug ("Sound Destroy"); + Mix_CloseAudio(); + + SoundInstance = NULL; +} + +/* Module specific functions */ +void SoundBase::PlaySound (const std::string &sound_name) { + if (!SoundInstance) { + LogError("Could not play sound %s: sound system not initialized!", + sound_name.c_str()); + } + + SampleIter iter = mSamples.find(sound_name); + + if (iter == mSamples.end()) { + SoundSamplePtr sample (new SoundSample); + sample->Load(sound_name); + mSamples[sound_name] = sample; + + iter = mSamples.find(sound_name); + } + + iter->second->Play(); +} + +void SoundBase::PlaySoundLoop (const std::string &sound_name, int count) { + if (!SoundInstance) { + LogError("Could not play sound %s: sound system not initialized!", + sound_name.c_str()); + } + + SampleIter iter = mSamples.find(sound_name); + + if (iter == mSamples.end()) { + SoundSamplePtr sample (new SoundSample); + sample->Load(sound_name); + mSamples[sound_name] = sample; + + iter = mSamples.find(sound_name); + } + + iter->second->Loop(count); +} + +void SoundBase::HaltSoundLoop (const std::string &sound_name) { + if (!SoundInstance) { + LogError("Could not play sound %s: sound system not initialized!", + sound_name.c_str()); + } + + SampleIter iter = mSamples.find(sound_name); + + if (iter == mSamples.end()) { + SoundSamplePtr sample (new SoundSample); + sample->Load(sound_name); + mSamples[sound_name] = sample; + + iter = mSamples.find(sound_name); + } + + iter->second->Stop(); +} + +void SoundBase::PlayMusic (const std::string &music_name) { + if (!SoundInstance) { + LogError("Could not play music %s: sound system not initialized!", + music_name.c_str()); + } + + if (music_name == mCurrentMusicName) + return; + + if (mCurrentMusic) { + Mix_HaltMusic(); + Mix_FreeMusic(mCurrentMusic); + mCurrentMusic = NULL; + } + + LogDebug("Loading Music %s", music_name.c_str()); + mCurrentMusic = Mix_LoadMUS(music_name.c_str()); + + if (mCurrentMusic == NULL) { + LogError("Loading of Music failed: %s", Mix_GetError()); + return; + } + + Mix_PlayMusic(mCurrentMusic, -1); +} + +/* + * Global Functions + */ + +void PlaySound (const std::string &sound_name) { + if (!SoundInstance) { + LogError("Could not play sound %s: sound system not initialized!", + sound_name.c_str()); + } + + SoundInstance->PlaySound(sound_name); +} + +void PlayMusic (const std::string &music_name) { + if (!SoundInstance) { + LogError("Could not play sound %s: sound system not initialized!", + music_name.c_str()); + } + + SoundInstance->PlayMusic(music_name); +} + +void PlaySoundLoop (const std::string &sound_name, int count) { + if (!SoundInstance) { + LogError("Could not play sound loop %s: sound system not initialized!", + sound_name.c_str()); + } + + SoundInstance->PlaySoundLoop(sound_name, count); +} + +void HaltSoundLoop (const std::string &sound_name) { + if (!SoundInstance) { + LogError("Could not halt sound %s: sound system not initialized!", + sound_name.c_str()); + } + + SoundInstance->HaltSoundLoop(sound_name); +} + + +}; diff --git a/engine/SoundBase.h b/engine/SoundBase.h new file mode 100644 index 0000000..077052a --- /dev/null +++ b/engine/SoundBase.h @@ -0,0 +1,56 @@ +#ifndef _SOUNDBASE_H +#define _SOUNDBASE_H + +#include "Engine.h" +#include + +namespace Engine { + +class Module; + +class SoundSample { + public: + SoundSample() : + mMixChunk (NULL), + mChannel (-1) { + } + ~SoundSample(); + + bool Load(const std::string &filename); + void Play(); + void Loop(int count); + void Stop(); + + private: + int mChannel; + Mix_Chunk *mMixChunk; +}; + +typedef boost::shared_ptr SoundSamplePtr; + +/** \brief Manages loading, saving and playing of sounds and music + * + */ +class SoundBase : public Module { + public: + void PlaySound (const std::string &sound_name); + void PlaySoundLoop (const std::string &sound_name, int count); + void HaltSoundLoop (const std::string &sound_name); + void PlayMusic (const std::string &music_name); + + protected: + /** \brief Initializes the system */ + virtual int OnInit (int argc, char* argv[]); + /** \brief Destroys the system (must be called!) */ + virtual void OnDestroy (); + + std::string mCurrentMusicName; + Mix_Music *mCurrentMusic; + + std::map mSamples; + typedef std::map::iterator SampleIter; +}; + +} + +#endif // _SOUNDBASE_H diff --git a/engine/SoundBaseGlobal.h b/engine/SoundBaseGlobal.h new file mode 100644 index 0000000..6eea6c7 --- /dev/null +++ b/engine/SoundBaseGlobal.h @@ -0,0 +1,13 @@ +#ifndef _SOUNDGLOBAL_H +#define _SOUNDGLOBAL_H + +namespace Engine { + +void PlaySound (const std::string &sound_name); +void PlaySoundLoop (const std::string &sound_name, int count); +void HaltSoundLoop (const std::string &sound_name); +void PlayMusic (const std::string &music_name); + +} + +#endif /* _SOUNDGLOBAL_H */