diff --git a/include/AssetManager.h b/include/AssetManager.h index a5f635f..eb4d104 100644 --- a/include/AssetManager.h +++ b/include/AssetManager.h @@ -6,6 +6,7 @@ #include #include "Entity.h" +#include "SoundEffects.h" class Vector2D; class Manager; @@ -24,24 +25,14 @@ public: AssetManager(Manager* manager); ~AssetManager(); - void createProjectile(Vector2D pos, Vector2D velocity, int scale, int range, float speed, Textures textureEnum, Entity* owner); + void createProjectile(Vector2D pos, Vector2D velocity, int scale, int range, float speed, Textures textureEnum, Entity* owner, SoundEffects soundEffect); void createPowerup(Vector2D pos, std::function pickupFunc, Textures texture); Vector2D calculateSpawnPosition(); PowerupType calculateType(); - // sound management - void addSoundEffect(std::string id, const char* path); - - void addMusic(std::string id, const char* path); - - Mix_Chunk* getSound(std::string id); - Mix_Music* getMusic(std::string id); - private: Manager* man; - std::map soundEffects; - std::map music; }; diff --git a/include/BackgroundMusic.h b/include/BackgroundMusic.h new file mode 100644 index 0000000..48516a4 --- /dev/null +++ b/include/BackgroundMusic.h @@ -0,0 +1,3 @@ +#pragma once + +enum class BackgroundMusic; diff --git a/include/ProjectileComponent.h b/include/ProjectileComponent.h index da67ff6..d9f5071 100644 --- a/include/ProjectileComponent.h +++ b/include/ProjectileComponent.h @@ -3,6 +3,7 @@ #include "Component.h" #include "Vector2D.h" #include "Constants.h" +#include "SoundEffects.h" class TransformComponent; @@ -11,8 +12,8 @@ class ProjectileComponent : public Component //can maybe be split in separate .cpp file public: - ProjectileComponent(int range, int speed, Vector2D direction, Entity* owner) - : range(range), speed(speed), direction(direction), owner(owner) {} + ProjectileComponent(int range, int speed, Vector2D direction, Entity* owner, SoundEffects soundEffect) + : range(range), speed(speed), direction(direction), owner(owner), soundEffect(soundEffect) {} ~ProjectileComponent() {} void init() override; @@ -28,4 +29,6 @@ private: Entity* owner = nullptr; Vector2D direction; + + SoundEffects soundEffect; }; \ No newline at end of file diff --git a/include/SoundEffects.h b/include/SoundEffects.h new file mode 100644 index 0000000..609b9a5 --- /dev/null +++ b/include/SoundEffects.h @@ -0,0 +1,3 @@ +#pragma once + +enum class SoundEffects; diff --git a/include/SoundManager.h b/include/SoundManager.h index 38a6b2c..22d1c71 100644 --- a/include/SoundManager.h +++ b/include/SoundManager.h @@ -6,6 +6,8 @@ #include "ECS.h" #include "TextureManager.h" +#include "BackgroundMusic.h" +#include "SoundEffects.h" class GameInternal; @@ -17,8 +19,17 @@ class GameInternal; */ class SoundManager { + public: - SoundManager() {} + + SoundManager() { + if (this_instance == nullptr) { + this_instance = this; + } + else { + throw std::runtime_error("SoundManager instance already exists!"); + } + } ~SoundManager() { for (auto& it : this->sound_cache) { Mix_FreeChunk(it.second); @@ -32,35 +43,32 @@ class SoundManager SoundManager(SoundManager const&) = delete; void operator=(SoundManager const&) = delete; - std::map music_cache; - std::map sound_cache; - - /*! + /* * \brief Loads music from a file (mp3) * \returns a pointer to Mix_Music * \sa AssetManager::AddMusic(std::string id, const char* path) - */ + Mix_Music* loadMusic(const char* fileName); /*! * \brief Loads sound effects from a file (wav) * \returns a pointer to Mix_Chunk * \sa AssetManager::AddSound(std::string id, const char* path) - */ - Mix_Chunk* loadSound(const char* fileName); + Mix_Chunk* loadSound(const char* fileName); + */ /*! * \brief Handles playing of sound effects * * Handles if sounds can overlap, how often they can loop, as well as the volume at which the specified sound effect should play * and on which channel the soundeffect should play. */ - static void playSound(GameInternal* game, std::string sound, bool canOverlap, int loops, int volume, int channel); + static void playSound(SoundEffects sound, bool canOverlap, int loops, int volume, int channel); /*! * \brief Handles playing of music * * Handles how often track can loop, as well as the volume at which the specified track should play and if it fades in. */ - static void playMusic(GameInternal* game, std::string sound, int loops, int volume, int ms); + static void playMusic(BackgroundMusic sound, int loops, int volume, int milliseconds); static void setSoundVolume(int volume, int channel); //!< Volume handling for sound effects (either all or on a specific channel) static void setMusicVolume(int volume); //!< Volume handling for music track @@ -73,5 +81,29 @@ class SoundManager static void fadeOutMusic(int ms); //!< Handles fading out a music track + /*! + * \brief Initializes sound-effects and adds them to a cache + * + */ + static void addSoundEffects(const std::map &effects); + + /*! + * \brief Initializes background-music and adds them to a cache + * + */ + static void addBackgroundMusic(const std::map &backgroundMusic); + + static SoundManager* getInstance() { + return this_instance; + } + + private: + + std::map music_cache; + std::map sound_cache; + static SoundManager* this_instance; + + static void addSingleBackgroundMusic(BackgroundMusic backgroundMusic, const char* path); + static void addSingleSoundEffect(SoundEffects soundEffect, const char* path); }; \ No newline at end of file diff --git a/src/AssetManager.cpp b/src/AssetManager.cpp index 75e78ec..a7789fc 100644 --- a/src/AssetManager.cpp +++ b/src/AssetManager.cpp @@ -22,32 +22,13 @@ AssetManager::AssetManager(Manager* manager) : man(manager) {} AssetManager::~AssetManager() {} -void AssetManager::addSoundEffect(std::string id, const char* path) -{ - soundEffects.emplace(id, this->man->getGame()->soundManager->loadSound(path)); -} -void AssetManager::addMusic(std::string id, const char* path) -{ - music.emplace(id, this->man->getGame()->soundManager->loadMusic(path)); -} - - -Mix_Chunk* AssetManager::getSound(std::string id) { - return soundEffects.at(id); -} - -Mix_Music* AssetManager::getMusic(std::string id) -{ - return music.at(id); -} - -void AssetManager::createProjectile(Vector2D pos, Vector2D velocity, int scale, int range, float speed, Textures textureEnum, Entity* owner) { +void AssetManager::createProjectile(Vector2D pos, Vector2D velocity, int scale, int range, float speed, Textures textureEnum, Entity* owner, SoundEffects soundEffect) { auto& projectile(man->addEntity()); projectile.addComponent(pos.x, pos.y, 32, 32, scale); //32x32 is standard size for objects projectile.addComponent(textureEnum, 4); - projectile.addComponent(range, speed, velocity, owner); + projectile.addComponent(range, speed, velocity, owner, soundEffect); projectile.addComponent("projectile", 0.6f); projectile.addGroup((size_t)Entity::GroupLabel::PROJECTILE); } diff --git a/src/ProjectileComponent.cpp b/src/ProjectileComponent.cpp index e1df015..3f5f13c 100644 --- a/src/ProjectileComponent.cpp +++ b/src/ProjectileComponent.cpp @@ -14,7 +14,7 @@ void ProjectileComponent::init() { transformComponent = &entity->getComponent(); transformComponent->direction = direction; - SoundManager::playSound(this->entity->getManager().getGame(), "throw_egg", true, PLAY_ONCE, MAX_VOLUME, -1); + SoundManager::playSound(this->soundEffect, true, PLAY_ONCE, MAX_VOLUME, -1); } void ProjectileComponent::update(uint_fast16_t diffTime) diff --git a/src/SoundManager.cpp b/src/SoundManager.cpp index 6775725..80c5567 100644 --- a/src/SoundManager.cpp +++ b/src/SoundManager.cpp @@ -8,9 +8,10 @@ #include "GameInternal.h" #include "AssetManager.h" +/* Mix_Music* SoundManager::loadMusic(const char* fileName) { - auto it = this->music_cache.find(fileName); + //auto it = this->music_cache.find(fileName); if (it != this->music_cache.end()) { return it->second; @@ -48,14 +49,21 @@ Mix_Chunk* SoundManager::loadSound(const char* fileName) return sound; } -void SoundManager::playSound(GameInternal* game, std::string sound, bool canOverlap, int loops, int volume, int channel) +*/ + +void SoundManager::playSound(SoundEffects sound, bool canOverlap, int loops, int volume, int channel) { + if (!this_instance->sound_cache.contains(sound)) { + std::cerr << "Error playing Sound-Effect: sound effect not found" << std::endl; + return; + } + if(!canOverlap) { // dev needs to specify a channel for this check to work, if they set it to -1 and let sdl pick the first available // channel mix_getchunk() won't work if (Mix_Playing(channel) != 0 && - Mix_GetChunk(channel) == game->assets->getSound(sound) && + Mix_GetChunk(channel) == this_instance->sound_cache.at(sound) && channel != -1) { return; @@ -64,25 +72,30 @@ void SoundManager::playSound(GameInternal* game, std::string sound, bool canOver Mix_HaltChannel(channel); } - if(Mix_VolumeChunk(game->assets->getSound(sound), volume) == -1) + if(Mix_VolumeChunk(this_instance->sound_cache.at(sound), volume) == -1) { std::cerr << "Error adjusting volume: " << SDL_GetError() << std::endl; } - if (Mix_PlayChannel(channel, game->assets->getSound(sound), loops) == -1) + if (Mix_PlayChannel(channel, this_instance->sound_cache.at(sound), loops) == -1) { - std::cerr << "Error playing sound '" << sound << "': " << SDL_GetError() << std::endl; + std::cerr << "Error playing sound " << ": " << SDL_GetError() << std::endl; } } -void SoundManager::playMusic(GameInternal* game, std::string music, int loops, int volume, int ms) +void SoundManager::playMusic(BackgroundMusic music, int loops, int volume, int milliseconds) { + if (!this_instance->music_cache.contains(music)) { + std::cerr << "Error playing music: music not found" << std::endl; + return; + } + if (Mix_PlayingMusic() != 0 || Mix_Fading() == Mix_Fading::MIX_FADING_IN) return; - if(ms > 0) + if(milliseconds > 0) { - Mix_FadeInMusic(game->assets->getMusic(music), loops, ms); + Mix_FadeInMusic(this_instance->music_cache.at(music), loops, milliseconds); return; } @@ -90,11 +103,6 @@ void SoundManager::playMusic(GameInternal* game, std::string music, int loops, i { std::cerr << "Error adjusting volume: " << SDL_GetError() << std::endl; } - - if (Mix_PlayMusic(game->assets->getMusic(music), loops) == -1) - { - std::cerr << "Error playing music '" << music << "': " << SDL_GetError() << std::endl; - } } void SoundManager::setSoundVolume(int volume, int channel) @@ -134,3 +142,51 @@ void SoundManager::fadeOutMusic(int ms) Mix_FadeOutMusic(ms); } + +void SoundManager::addSingleSoundEffect(SoundEffects soundEffect, const char *path) { + if (this_instance->sound_cache.contains(soundEffect)) { + std::cerr << "Error when adding Sound-Effect: sound-effect with that key already in cache" << std::endl; + return; + } + + Mix_Chunk* sound = Mix_LoadWAV(path); + + if (sound == nullptr) { + std::cerr << "Error when loading Sound-Effect: could not load sound effect from " << path << std::endl; + return; + } + + this_instance->sound_cache.emplace(soundEffect, sound); +} + +void SoundManager::addSingleBackgroundMusic(BackgroundMusic backgroundMusic, const char *path) { + if (this_instance->music_cache.contains(backgroundMusic)) { + std::cerr << "Error when adding Sound-Effect: sound-effect with that key already in cache" << std::endl; + return; + } + + Mix_Music* music = Mix_LoadMUS(path); + + if (music == nullptr) { + std::cerr << "Error when loading Sound-Effect: could not load sound effect from " << path << std::endl; + return; + } + + this_instance->music_cache.emplace(backgroundMusic, music); +} + +void SoundManager::addSoundEffects(const std::map &effects) { + for (auto effect : effects) + addSingleSoundEffect(effect.first, effect.second); +} + +void SoundManager::addBackgroundMusic(const std::map &backgroundMusic) { + for (auto track : backgroundMusic) + addSingleBackgroundMusic(track.first, track.second); +} + +SoundManager* SoundManager::this_instance = nullptr; + + + +