diff --git a/CMakeLists.txt b/CMakeLists.txt index 12d719b..6c27dae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -34,8 +34,6 @@ add_executable(shooter ShooterConsts.h # 3d engine: engine/Consts.h - engine/utils/Time.h - engine/utils/Time.cpp engine/Point4D.h engine/Point4D.cpp engine/Vec3D.cpp @@ -52,6 +50,8 @@ add_executable(shooter engine/Mesh.cpp engine/utils/Log.h engine/utils/Log.cpp + engine/utils/Time.h + engine/utils/Time.cpp engine/ResourceManager.h engine/ResourceManager.cpp engine/World.h @@ -75,6 +75,7 @@ add_executable(shooter engine/animation/AScale.h engine/animation/ARotate.h engine/animation/AWait.h + engine/animation/AFunction.h engine/physics/RigidBody.cpp engine/physics/RigidBody.h engine/physics/Simplex.h @@ -96,8 +97,7 @@ add_executable(shooter engine/network/UDPConnection.h engine/network/UDPSocket.cpp engine/network/UDPSocket.h - engine/animation/AFunction.h - ) + engine/SoundController.cpp engine/SoundController.h) if(APPLE OR UNIX) include_directories(/usr/local/include) diff --git a/Client.cpp b/Client.cpp index 93ccbd4..2ffecf4 100644 --- a/Client.cpp +++ b/Client.cpp @@ -82,15 +82,15 @@ void Client::processCustomPacket(MsgType type, sf::Packet& packet) { _player->addDeath(); // respawn _player->translateToPoint(Vec3D{50.0*(-1 + 2.0*(double)rand()/RAND_MAX),30.0*(double)rand()/RAND_MAX,50.0*(-1 + 2.0*(double)rand()/RAND_MAX)}); - _player->playDeath(); _player->initWeapons(); _player->setFullAbility(); + SoundController::playSound(SoundTag("death"), ShooterConsts::DEATH_SOUND); } else _players[buffId[0]]->addDeath(); if(buffId[1] == _socket.ownId()) { _player->addKill(); - _player->playKill(); + SoundController::playSound(SoundTag("kill"), ShooterConsts::KILL_SOUND); } else _players[buffId[1]]->addKill(); diff --git a/Player.cpp b/Player.cpp index 3901ddb..1e9aa4f 100644 --- a/Player.cpp +++ b/Player.cpp @@ -14,11 +14,6 @@ Player::Player() { setVisible(false); setColor({240, 168, 168}); - _changeWeaponSound.setBuffer(*ResourceManager::loadSoundBuffer(ShooterConsts::CHANGE_WEAPON_SOUND)); - - _fullHealthSound.setBuffer(*ResourceManager::loadSoundBuffer(ShooterConsts::RESTORE_HEALTH_SOUND)); - _fullAbilitySound.setBuffer(*ResourceManager::loadSoundBuffer(ShooterConsts::RESTORE_ABILITY_SOUND)); - setCollisionCallBack([this](const ObjectNameTag& tag, std::shared_ptr obj) {collisionWithObject(tag, obj);}); } @@ -27,16 +22,6 @@ void Player::rotateWeaponsRelativePoint(const Vec3D& point4D, const Vec3D& v, do weapon->rotateRelativePoint(point4D, v, val); } -void Player::playDeath() { - _deathSound.setBuffer(*ResourceManager::loadSoundBuffer(ShooterConsts::DEATH_SOUND)); - _deathSound.play(); -} - -void Player::playKill() { - _killSound.setBuffer(*ResourceManager::loadSoundBuffer(ShooterConsts::KILL_SOUND)); - _killSound.play(); -} - void Player::collisionWithObject(const ObjectNameTag& tag, std::shared_ptr obj) { if(tag.str().find("Bonus_gun") != std::string::npos) addWeapon(std::make_shared()); @@ -65,7 +50,7 @@ void Player::collisionWithObject(const ObjectNameTag& tag, std::shared_ptr weapon) { - _changeWeaponSound.play(); + SoundController::playSound(SoundTag("changeWeapon"), ShooterConsts::CHANGE_WEAPON_SOUND); for(auto& w : _weapons) { if (w->name() == weapon->name()) { @@ -106,7 +91,7 @@ void Player::nextWeapon() { _selectedWeapon = (_selectedWeapon + 1) % _weapons.size(); _addWeaponCallBack(_weapons[_selectedWeapon]); Log::log("selectedWeapon " + std::to_string(_selectedWeapon)); - _changeWeaponSound.play(); + SoundController::playSound(SoundTag("changeWeapon"), ShooterConsts::CHANGE_WEAPON_SOUND); } } @@ -120,7 +105,7 @@ void Player::previousWeapon() { _selectedWeapon = _weapons.size() - 1; _addWeaponCallBack(_weapons[_selectedWeapon]); Log::log("selectedWeapon " + std::to_string(_selectedWeapon)); - _changeWeaponSound.play(); + SoundController::playSound(SoundTag("changeWeapon"), ShooterConsts::CHANGE_WEAPON_SOUND); } } @@ -140,10 +125,10 @@ void Player::reload() { void Player::setFullHealth() { _health = ShooterConsts::HEALTH_MAX; - _fullHealthSound.play(); + SoundController::playSound(SoundTag("addHealth"), ShooterConsts::RESTORE_HEALTH_SOUND); } void Player::setFullAbility() { _ability = ShooterConsts::ABILITY_MAX; - _fullAbilitySound.play(); + SoundController::playSound(SoundTag("addAbility"), ShooterConsts::RESTORE_ABILITY_SOUND); } diff --git a/Player.h b/Player.h index 8248a8d..f73fe1b 100644 --- a/Player.h +++ b/Player.h @@ -27,13 +27,6 @@ private: int _kills = 0; int _deaths = 0; - // sounds - sf::Sound _killSound; - sf::Sound _deathSound; - sf::Sound _changeWeaponSound; - sf::Sound _fullHealthSound; - sf::Sound _fullAbilitySound; - std::vector> _weapons; size_t _selectedWeapon = 0; @@ -48,12 +41,8 @@ private: public: Player(); - void setHealth(double h) { - _health = h; - } - void setAbility(double a) { - _ability = a; - } + void setHealth(double h) { _health = h; } + void setAbility(double a) { _ability = a; } [[nodiscard]] double health() const { return _health; } [[nodiscard]] double ability() const { return _ability; } @@ -73,15 +62,12 @@ public: void rotateWeaponsRelativePoint(const Vec3D& point, const Vec3D& v, double val); - [[nodiscard]] int kills() const {return _kills;} - [[nodiscard]] int deaths() const {return _deaths;} + [[nodiscard]] int kills() const { return _kills; } + [[nodiscard]] int deaths() const { return _deaths; } void addKill() { _kills++; } void addDeath() { _deaths++; } - void playDeath(); - void playKill(); - void setDamagePlayerCallBack(std::function hit) { _damagePlayerCallBack = std::move(hit); } diff --git a/PlayerController.cpp b/PlayerController.cpp index c87793b..0412452 100644 --- a/PlayerController.cpp +++ b/PlayerController.cpp @@ -13,10 +13,7 @@ PlayerController::PlayerController(std::shared_ptr player, std::shared_ptr keyboard, - std::shared_ptr mouse) : _player(player), _keyboard(keyboard), _mouse(mouse) { - _slowMoSound.setBuffer(*ResourceManager::loadSoundBuffer(ShooterConsts::SLOW_MO_SOUND)); - _unSlowMoSound.setBuffer(*ResourceManager::loadSoundBuffer(ShooterConsts::UN_SLOW_MO_SOUND)); -} + std::shared_ptr mouse) : _player(player), _keyboard(keyboard), _mouse(mouse) {} void PlayerController::update() { // friction @@ -31,8 +28,8 @@ void PlayerController::update() { _isInSlowMo = false; _player->setVelocity(_player->velocity() * ShooterConsts::SLOW_MO_COEFFICIENT); _player->setAcceleration(_player->acceleration() * ShooterConsts::SLOW_MO_COEFFICIENT * ShooterConsts::SLOW_MO_COEFFICIENT); - _slowMoSound.stop(); - _unSlowMoSound.play(); + SoundController::stopSound(SoundTag("slowMo")); + SoundController::playSound(SoundTag("unSlowMo"), ShooterConsts::UN_SLOW_MO_SOUND); } } @@ -100,14 +97,14 @@ void PlayerController::update() { _isInSlowMo = true; _player->setVelocity(_player->velocity() / ShooterConsts::SLOW_MO_COEFFICIENT); _player->setAcceleration(Vec3D(0, -ShooterConsts::GRAVITY / (ShooterConsts::SLOW_MO_COEFFICIENT * ShooterConsts::SLOW_MO_COEFFICIENT), 0)); - _unSlowMoSound.stop(); - _slowMoSound.play(); + SoundController::stopSound(SoundTag("unSlowMo")); + SoundController::playSound(SoundTag("slowMo"), ShooterConsts::SLOW_MO_SOUND); } else if (_isInSlowMo && !Keyboard::isKeyPressed(sf::Keyboard::LShift)) { _isInSlowMo = false; _player->setVelocity(_player->velocity() * ShooterConsts::SLOW_MO_COEFFICIENT); _player->setAcceleration(Vec3D(0, -ShooterConsts::GRAVITY, 0)); - _slowMoSound.stop(); - _unSlowMoSound.play(); + SoundController::stopSound(SoundTag("slowMo")); + SoundController::playSound(SoundTag("unSlowMo"), ShooterConsts::UN_SLOW_MO_SOUND); } if (Keyboard::isKeyPressed(sf::Keyboard::Space) && _player->inCollision()) { @@ -160,9 +157,8 @@ void PlayerController::update() { _player->reload(); } - if ((_inRunning || _player->velocity().sqrAbs() > 3) && _player->inCollision() && _walkSound.getStatus() != sf::Sound::Status::Playing) { + if ((_inRunning || _player->velocity().sqrAbs() > 3) && _player->inCollision() && SoundController::getStatus(SoundTag("walk")) != sf::Sound::Status::Playing) { int soundNum = (int)((double) rand() / RAND_MAX * 5) + 1; - _walkSound.setBuffer(*ResourceManager::loadSoundBuffer("sound/stonestep" + std::to_string(soundNum) + ".ogg")); - _walkSound.play(); + SoundController::playSound(SoundTag("walk"), "sound/stonestep" + std::to_string(soundNum) + ".ogg"); } } diff --git a/PlayerController.h b/PlayerController.h index 0a22be0..0130a60 100644 --- a/PlayerController.h +++ b/PlayerController.h @@ -19,10 +19,6 @@ private: bool _isSliding = false; bool _isInSlowMo = false; - sf::Sound _slowMoSound; - sf::Sound _unSlowMoSound; - sf::Sound _walkSound; - public: PlayerController(std::shared_ptr player, std::shared_ptr keyboard, std::shared_ptr mouse); void update(); diff --git a/Shooter.cpp b/Shooter.cpp index 1055a98..47b4260 100644 --- a/Shooter.cpp +++ b/Shooter.cpp @@ -9,6 +9,7 @@ #include "engine/animation/ARotate.h" #include "engine/animation/Timeline.h" #include "ShooterConsts.h" +#include "engine/SoundController.h" using namespace std; @@ -96,10 +97,10 @@ void Shooter::start() { mainMenu.title("Main menu"); mainMenu.setBackgroundTexture(ShooterConsts::MAIN_MENU_BACK, 1.1, 1.1, screen->width(), screen->height()); - mainMenu.addButton(screen->width()/2, 200, 200, 20, [this] () { this->play(); }, "Play", 5, 5, ShooterConsts::MAIN_MENU_GUI, {0, 66}, {0, 86}, {0, 46}, Consts::MEDIUM_FONT, {255, 255, 255}, ShooterConsts::CLICK_SOUND); - mainMenu.addButton(screen->width()/2, 350, 200, 20, [this] () { this->player->translateToPoint(Vec3D{0, 0, 0}); this->player->setVelocity({}); this->play(); }, "Respawn", 5, 5, ShooterConsts::MAIN_MENU_GUI, {0, 66}, {0, 86}, {0, 46}, Consts::MEDIUM_FONT, {255, 255, 255}, ShooterConsts::CLICK_SOUND); + mainMenu.addButton(screen->width()/2, 200, 200, 20, [this] () { this->play(); SoundController::playSound(SoundTag("click"), ShooterConsts::CLICK_SOUND);}, "Play", 5, 5, ShooterConsts::MAIN_MENU_GUI, {0, 66}, {0, 86}, {0, 46}, Consts::MEDIUM_FONT, {255, 255, 255}); + mainMenu.addButton(screen->width()/2, 350, 200, 20, [this] () { this->player->translateToPoint(Vec3D{0, 0, 0}); this->player->setVelocity({}); this->play(); SoundController::playSound(SoundTag("click"), ShooterConsts::CLICK_SOUND);}, "Respawn", 5, 5, ShooterConsts::MAIN_MENU_GUI, {0, 66}, {0, 86}, {0, 46}, Consts::MEDIUM_FONT, {255, 255, 255}); - mainMenu.addButton(screen->width()/2, 500, 200, 20, [this] () { client->disconnect(); server->stop(); this->exit();}, "Exit", 5, 5, ShooterConsts::MAIN_MENU_GUI, {0, 66}, {0, 86}, {0, 46}, Consts::MEDIUM_FONT, {255, 255, 255}, ShooterConsts::CLICK_SOUND); + mainMenu.addButton(screen->width()/2, 500, 200, 20, [this] () { client->disconnect(); server->stop(); this->exit();}, "Exit", 5, 5, ShooterConsts::MAIN_MENU_GUI, {0, 66}, {0, 86}, {0, 46}, Consts::MEDIUM_FONT, {255, 255, 255}); // connecting to the server InitNetwork(); @@ -144,10 +145,8 @@ void Shooter::update() { setUpdateWorld(inGame); // background sounds and music control - if(backgroundNoise.getStatus() != sf::Sound::Status::Playing) { - backgroundNoise.setBuffer(*ResourceManager::loadSoundBuffer(ShooterConsts::BACK_NOISE)); - backgroundNoise.play(); - } + if(SoundController::getStatus(SoundTag("background")) != sf::Sound::Status::Playing) + SoundController::playSound(SoundTag("background"), ShooterConsts::BACK_NOISE); } void Shooter::gui() { diff --git a/engine/Consts.h b/engine/Consts.h index eb0798f..3b223eb 100644 --- a/engine/Consts.h +++ b/engine/Consts.h @@ -24,6 +24,7 @@ namespace Consts { const std::string THIN_FONT = "engine/fonts/Roboto-Thin.ttf"; const std::string MEDIUM_FONT = "engine/fonts/Roboto-Medium.ttf"; + const double LARGEST_TIME_STEP = 1.0/15.0; const double TAP_DELAY = 0.2; const unsigned NETWORK_VERSION = 1U; diff --git a/engine/Engine.cpp b/engine/Engine.cpp index c280fa9..bc99ab1 100644 --- a/engine/Engine.cpp +++ b/engine/Engine.cpp @@ -7,8 +7,14 @@ #include #include "ResourceManager.h" #include "animation/Timeline.h" +#include "SoundController.h" Engine::Engine() { + Time::init(); + Timeline::init(); + ResourceManager::init(); + SoundController::init(); + screen = std::make_shared(); keyboard = std::make_shared(); mouse = std::make_shared(); @@ -64,14 +70,17 @@ void Engine::create(int screenWidth, int screenHeight, const std::string &name, screen->display(); } - exit(); } void Engine::exit() { if(screen->isOpen()) { screen->close(); } - ResourceManager::unloadAllResources(); + SoundController::free(); + ResourceManager::free(); + Timeline::free(); + Time::free(); + Log::log("Engine::exit(): exit engine (" + std::to_string(screen->width()) + "x" + std::to_string(screen->height()) + ") with title '" + screen->title() + "'."); } diff --git a/engine/ResourceManager.cpp b/engine/ResourceManager.cpp index 38556d5..60ce0e3 100644 --- a/engine/ResourceManager.cpp +++ b/engine/ResourceManager.cpp @@ -6,93 +6,100 @@ #include #include -namespace ResourceManager -{ - namespace - { - std::map> _textures; - std::map> _fonts; - std::map> _soundBuffers; - } +ResourceManager* ResourceManager::_instance = nullptr; - void unloadTextures() - { - for (auto & _texture : _textures) - _texture.second.reset(); - _textures.clear(); - } - - void unloadSoundBuffers() - { - for (auto & _soundBuffer : _soundBuffers) - _soundBuffer.second.reset(); - _soundBuffers.clear(); - } - - void unloadFonts() { - for (auto & _font : _fonts) - _font.second.reset(); - _fonts.clear(); - } - - void unloadAllResources() - { - unloadTextures(); - unloadSoundBuffers(); - unloadFonts(); - } - - std::shared_ptr loadTexture(const std::string& filename) - { - // If texture is already loaded - return pointer to it - auto it = _textures.find(filename); - if (it != _textures.end()) - return it->second; - - // Otherwise - try to load it. If failure - return zero - std::shared_ptr texture(new sf::Texture); - if (!texture->loadFromFile(filename)) - return nullptr; - - // If success - remember and return texture pointer - texture->setRepeated(true); - _textures.emplace(filename, texture); - - return texture; - } - - std::shared_ptr loadSoundBuffer(const std::string& filename) - { - // If sound buffer is already loaded - return pointer to it - auto it = _soundBuffers.find(filename); - if (it != _soundBuffers.end()) - return it->second; - - // Otherwise - try to load it. If failure - return zero - std::shared_ptr soundBuffer(new sf::SoundBuffer); - if (!soundBuffer->loadFromFile(filename)) - return nullptr; - - // If success - remember and return texture pointer - _soundBuffers.emplace(filename, soundBuffer); - - return soundBuffer; - } - - std::shared_ptr loadFont(const std::string& filename) { - // If font is already loaded - return pointer to it - auto it = _fonts.find(filename); - if (it != _fonts.end()) - return it->second; - - // Otherwise - try to load it. If failure - return zero - std::shared_ptr font(new sf::Font); - if (!font->loadFromFile(filename)) - return nullptr; - - // If success - remember and return texture pointer - _fonts.emplace(filename, font); - - return font; - } +void ResourceManager::init() { + _instance = new ResourceManager(); } + +void ResourceManager::unloadTextures() { + for (auto & _texture : _instance->_textures) + _texture.second.reset(); + _instance->_textures.clear(); +} + +void ResourceManager::unloadSoundBuffers() { + for (auto & _soundBuffer : _instance->_soundBuffers) + _soundBuffer.second.reset(); + _instance->_soundBuffers.clear(); +} + +void ResourceManager::unloadFonts() { + for (auto & _font : _instance->_fonts) + _font.second.reset(); + _instance->_fonts.clear(); +} + +void ResourceManager::unloadAllResources() { + unloadTextures(); + unloadSoundBuffers(); + unloadFonts(); +} + +std::shared_ptr ResourceManager::loadTexture(const std::string& filename) { + if(!_instance) + return nullptr; + + // If texture is already loaded - return pointer to it + auto it = _instance->_textures.find(filename); + if (it != _instance->_textures.end()) + return it->second; + + // Otherwise - try to load it. If failure - return zero + std::shared_ptr texture(new sf::Texture); + if (!texture->loadFromFile(filename)) + return nullptr; + + // If success - remember and return texture pointer + texture->setRepeated(true); + _instance->_textures.emplace(filename, texture); + + return texture; +} + +std::shared_ptr ResourceManager::loadSoundBuffer(const std::string& filename) { + if(!_instance) + return nullptr; + + // If sound buffer is already loaded - return pointer to it + auto it = _instance->_soundBuffers.find(filename); + if (it != _instance->_soundBuffers.end()) + return it->second; + + // Otherwise - try to load it. If failure - return zero + std::shared_ptr soundBuffer(new sf::SoundBuffer); + if (!soundBuffer->loadFromFile(filename)) + return nullptr; + + // If success - remember and return texture pointer + _instance->_soundBuffers.emplace(filename, soundBuffer); + + return soundBuffer; +} + +std::shared_ptr ResourceManager::loadFont(const std::string& filename) { + if(!_instance) + return nullptr; + + // If font is already loaded - return pointer to it + auto it = _instance->_fonts.find(filename); + if (it != _instance->_fonts.end()) + return it->second; + + // Otherwise - try to load it. If failure - return zero + std::shared_ptr font(new sf::Font); + if (!font->loadFromFile(filename)) + return nullptr; + + // If success - remember and return texture pointer + _instance->_fonts.emplace(filename, font); + + return font; +} + +void ResourceManager::free() { + unloadAllResources(); + delete _instance; + _instance = nullptr; +} + diff --git a/engine/ResourceManager.h b/engine/ResourceManager.h index 101a6bf..d500249 100644 --- a/engine/ResourceManager.h +++ b/engine/ResourceManager.h @@ -9,23 +9,36 @@ #include #include -namespace ResourceManager -{ - // Unloads all currently loaded textures. - void unloadTextures(); - void unloadSoundBuffers(); - void unloadFonts(); - void unloadShaders(); +class ResourceManager final { +private: + std::map> _textures; + std::map> _fonts; + std::map> _soundBuffers; - void unloadAllResources(); + static ResourceManager* _instance; + + ResourceManager() = default; +public: + ResourceManager(const ResourceManager&) = delete; + ResourceManager& operator=(ResourceManager&) = delete; + + // Unloads all currently loaded textures. + static void unloadTextures(); + static void unloadSoundBuffers(); + static void unloadFonts(); + static void unloadShaders(); + + static void unloadAllResources(); + + static void init(); + static void free(); // Try to load texture from file. // If success returns pointer to texture. // Otherwise returns nullptr. - std::shared_ptr loadTexture(const std::string& filename); - std::shared_ptr loadFont(const std::string& filename); - std::shared_ptr loadSoundBuffer(const std::string& filename); + static std::shared_ptr loadTexture(const std::string& filename); + static std::shared_ptr loadFont(const std::string& filename); + static std::shared_ptr loadSoundBuffer(const std::string& filename); }; - #endif //PSEUDO3DENGINE_RESOURCEMANAGER_H diff --git a/engine/SoundController.cpp b/engine/SoundController.cpp new file mode 100644 index 0000000..1580447 --- /dev/null +++ b/engine/SoundController.cpp @@ -0,0 +1,60 @@ +// +// Created by Иван Ильин on 17.10.2021. +// + +#include "SoundController.h" +#include "ResourceManager.h" + +SoundController* SoundController::_instance = nullptr; + +void SoundController::init() { + _instance = new SoundController(); +} + +void SoundController::playSound(const SoundTag& soundTag, const std::string& filename) { + if(!_instance) + return; + + stopSound(soundTag); + _instance->_sounds.emplace(soundTag, sf::Sound(*ResourceManager::loadSoundBuffer(filename))); + _instance->_sounds[soundTag].play(); +} + +void SoundController::pauseSound(const SoundTag& soundTag) { + if(!_instance) + return; + + if(_instance->_sounds.count(soundTag) > 0) { + _instance->_sounds[soundTag].pause(); + } +} + +void SoundController::stopSound(const SoundTag& soundTag) { + if(!_instance) + return; + + if(_instance->_sounds.count(soundTag) > 0) { + _instance->_sounds[soundTag].stop(); + } + _instance->_sounds.erase(soundTag); +} + +sf::Sound::Status SoundController::getStatus(const SoundTag& soundTag) { + if(_instance == nullptr) + return sf::Sound::Status::Stopped; + + if(_instance->_sounds.count(soundTag) > 0) + return _instance->_sounds[soundTag].getStatus(); + else + return sf::Sound::Status::Stopped; +} + +void SoundController::free() { + for(auto& [soundTag, sound] : _instance->_sounds) { + sound.stop(); + } + + _instance->_sounds.clear(); + delete _instance; + _instance = nullptr; +} diff --git a/engine/SoundController.h b/engine/SoundController.h new file mode 100644 index 0000000..673e92b --- /dev/null +++ b/engine/SoundController.h @@ -0,0 +1,45 @@ +// +// Created by Иван Ильин on 17.10.2021. +// + +#ifndef SHOOTER_SOUNDCONTROLLER_H +#define SHOOTER_SOUNDCONTROLLER_H + +#include +#include +#include + +class SoundTag final { +private: + const std::string _name; +public: + explicit SoundTag(std::string name = "") : _name(std::move(name)) {} + [[nodiscard]] std::string str() const { return _name; } + + bool operator==(const SoundTag& tag) const { return _name == tag._name; } + bool operator!=(const SoundTag& tag) const { return _name != tag._name; } + bool operator<(const SoundTag& tag) const { return _name < tag._name; } +}; + +class SoundController final { +private: + std::map _sounds; + + static SoundController* _instance; + + SoundController() = default; +public: + SoundController(const SoundController&) = delete; + SoundController& operator=(SoundController&) = delete; + + static void playSound(const SoundTag& soundTag, const std::string& filename); + static void pauseSound(const SoundTag& soundTag); + static void stopSound(const SoundTag& soundTag); + static sf::Sound::Status getStatus(const SoundTag& soundTag); + + static void init(); + static void free(); +}; + + +#endif //SHOOTER_SOUNDCONTROLLER_H diff --git a/engine/animation/Timeline.cpp b/engine/animation/Timeline.cpp index 3fbcde7..fa426eb 100644 --- a/engine/animation/Timeline.cpp +++ b/engine/animation/Timeline.cpp @@ -6,49 +6,77 @@ #include "Animation.h" #include "Timeline.h" -namespace Timeline { - namespace { - std::map> _animations; +Timeline* Timeline::_instance = nullptr; + +void Timeline::init() { + _instance = new Timeline(); +} + +void Timeline::animate(const AnimationListTag& listName, Animation* anim) { + if(!_instance) + return; + + _instance->_animations[listName].emplace_back(anim); +} + +void Timeline::deleteAllAnimations() { + if(!_instance) + return; + + for (auto& [listName, animationList] : _instance->_animations) { + auto it = animationList.begin(); + while(it != animationList.end()) + delete *(it++); + animationList.clear(); } + _instance->_animations.clear(); +} - void animate(const AnimationListTag& listName, Animation* anim) { - _animations[listName].emplace_back(anim); - } +void Timeline::deleteAnimationList(const AnimationListTag& listName) { + if(!_instance) + return; - void deleteAllAnimations() { - _animations.clear(); - } + _instance->_animations[listName].clear(); + _instance->_animations.erase(listName); +} - void deleteAnimationList(const AnimationListTag& listName) { - _animations[listName].clear(); - _animations.erase(listName); - } +[[nodiscard]] bool Timeline::isInAnimList(const AnimationListTag& listName) { + if(!_instance) + return false; - [[nodiscard]] bool isInAnimList(const AnimationListTag& listName) { - return !_animations[listName].empty(); - } + return !_instance->_animations[listName].empty(); +} - void update() { - for (auto& [listName, animationList] : _animations) { +void Timeline::update() { + if(!_instance) + return; - if (animationList.empty()) - continue; - auto it = animationList.begin(); - // If it the front animation is 'a_wait()' we should wait until waiting time is over + for (auto& [listName, animationList] : _instance->_animations) { - if (it.operator*()->waitFor()) { - if (!it.operator*()->update()) - animationList.erase(it); - continue; - } + if (animationList.empty()) + continue; + auto it = animationList.begin(); + // If it the front animation is 'a_wait()' we should wait until waiting time is over - // Otherwise we iterate over all animation until we meet animations.end() or wait animation - while (!animationList.empty() && (it != animationList.end()) && (!it.operator*()->waitFor())) { - if (!it.operator*()->update()) - animationList.erase(it++); - else - it++; - } + if (it.operator*()->waitFor()) { + if (!it.operator*()->update()) + animationList.erase(it); + continue; + } + + // Otherwise we iterate over all animation until we meet animations.end() or wait animation + while (!animationList.empty() && (it != animationList.end()) && (!it.operator*()->waitFor())) { + if (!it.operator*()->update()) + animationList.erase(it++); + else + it++; } } } + +void Timeline::free() { + Timeline::deleteAllAnimations(); + + delete _instance; + _instance = nullptr; +} diff --git a/engine/animation/Timeline.h b/engine/animation/Timeline.h index cc990d6..ab1458f 100644 --- a/engine/animation/Timeline.h +++ b/engine/animation/Timeline.h @@ -19,14 +19,27 @@ public: bool operator<(const AnimationListTag& tag) const { return _name < tag._name; } }; -namespace Timeline { - void update(); - void animate(const AnimationListTag& listName, Animation* anim); +class Timeline { +private: + std::map> _animations; - void deleteAllAnimations(); - void deleteAnimationList(const AnimationListTag& listName); + static Timeline* _instance; - [[nodiscard]] bool isInAnimList(const AnimationListTag& listName); -} + Timeline() = default; +public: + Timeline(const Timeline&) = delete; + Timeline& operator=(Timeline&) = delete; + + static void update(); + static void animate(const AnimationListTag& listName, Animation* anim); + + static void deleteAllAnimations(); + static void deleteAnimationList(const AnimationListTag& listName); + + [[nodiscard]] static bool isInAnimList(const AnimationListTag& listName); + + static void init(); + static void free(); +}; #endif //SHOOTER_TIMELINE_H diff --git a/engine/gui/Button.cpp b/engine/gui/Button.cpp index e692d9e..90f6a5c 100644 --- a/engine/gui/Button.cpp +++ b/engine/gui/Button.cpp @@ -32,7 +32,7 @@ void Button::press() _button.setTextureRect(sf::IntRect(_pressedState.tx, _pressedState.ty, _w, _h)); if(_checkBox) _pressed = true; - _clickSound.play(); + //_clickSound.play(); _click(); } else @@ -55,14 +55,14 @@ void Button::init() { _text.setFillColor(_textColor); _text.setPosition((float)(_x - _text.getLocalBounds().width / 2), (float)(_y - _h * _sy / 2 + _text.getLocalBounds().height / 4)); - _clickSound.setBuffer(*ResourceManager::loadSoundBuffer(_clickSoundName)); - _clickSound.setVolume(15); + //_clickSound.setBuffer(*ResourceManager::loadSoundBuffer(_clickSoundName)); + //_clickSound.setVolume(15); } Button::Button(int x, int y, int width, int height, std::function click, std::string text, double sx, double sy, std::string texture, tPos usualState, tPos selectedState, tPos pressedState, - std::string font, sf::Color textColor, std::string clickSound) : _x(x), _y(y), _w(width), _h(height), _click(std::move(click)), + std::string font, sf::Color textColor) : _x(x), _y(y), _w(width), _h(height), _click(std::move(click)), _textString(std::move(text)), _sx(sx), _sy(sy), _texture(std::move(texture)), _usualState(usualState), _selectedState(selectedState), _pressedState(pressedState), - _font(std::move(font)), _textColor(textColor), _clickSoundName(std::move(clickSound)){ + _font(std::move(font)), _textColor(textColor) { } diff --git a/engine/gui/Button.h b/engine/gui/Button.h index 21e4223..4e3b6be 100644 --- a/engine/gui/Button.h +++ b/engine/gui/Button.h @@ -9,9 +9,9 @@ #include #include -struct tPos { - int tx; - int ty; +struct tPos final { + const int tx; + const int ty; }; class Button final { @@ -37,11 +37,8 @@ private: std::string _font; sf::Color _textColor; - std::string _clickSoundName; - sf::Sprite _button; sf::Text _text; - sf::Sound _clickSound; bool _selected = false; bool _pressed = false; @@ -49,7 +46,7 @@ private: public: Button() = default; - Button(int x, int y, int width, int height, std::function click, std::string text, double sx, double sy, std::string texture, tPos usualState, tPos selectedState, tPos pressedState, std::string font, sf::Color textColor, std::string clickSound); + Button(int x, int y, int width, int height, std::function click, std::string text, double sx, double sy, std::string texture, tPos usualState, tPos selectedState, tPos pressedState, std::string font, sf::Color textColor); void select(); void unSelect(); diff --git a/engine/gui/Window.cpp b/engine/gui/Window.cpp index a250850..75a1b8d 100644 --- a/engine/gui/Window.cpp +++ b/engine/gui/Window.cpp @@ -9,8 +9,8 @@ void Window::addButton(int x, int y, int w, int h, std::function click, const std::string &text, double sx, double sy, const std::string &texture, tPos usualState, tPos selectedState, tPos pressedState, - const std::string& font, sf::Color textColor, const std::string& clickSound) { - _buttons.push_back(Button{x, y, w, h, std::move(click), text, sx, sy, texture, usualState, selectedState, pressedState, font, textColor, clickSound}); + const std::string& font, sf::Color textColor) { + _buttons.push_back(Button{x, y, w, h, std::move(click), text, sx, sy, texture, usualState, selectedState, pressedState, font, textColor}); _buttons.back().init(); } diff --git a/engine/gui/Window.h b/engine/gui/Window.h index ebc2d4e..ef87a5d 100644 --- a/engine/gui/Window.h +++ b/engine/gui/Window.h @@ -31,7 +31,7 @@ public: std::function click, const std::string& text = "_button", double sx = 1, double sy = 1, const std::string& texture = "", tPos usualState = {}, tPos selectedState = {}, tPos pressedState = {}, - const std::string& font = Consts::MEDIUM_FONT, sf::Color textColor = {255, 255, 255}, const std::string& clickSound = ""); + const std::string& font = Consts::MEDIUM_FONT, sf::Color textColor = {255, 255, 255}); [[nodiscard]] std::string title() const { return _name; } void title(const std::string& title) { _name = title; } diff --git a/engine/utils/Time.cpp b/engine/utils/Time.cpp index db50c35..24003d7 100644 --- a/engine/utils/Time.cpp +++ b/engine/utils/Time.cpp @@ -3,76 +3,65 @@ // #include "Time.h" -#include - -#define BIG_STEP (1.0/15.0) +#include "../Consts.h" using namespace std::chrono; -namespace Time -{ - namespace - { - // High precision time - high_resolution_clock::time_point _start = high_resolution_clock::now(); - high_resolution_clock::time_point _last = _start; +Time* Time::_instance = nullptr; - // FPS counter - high_resolution_clock::time_point _fpsStart; - milliseconds _fpsCountTime = milliseconds(1000); - int _fpsCounter = 0; - double _lastFps = 0; +void Time::init() { + _instance = new Time(); +} - // Compatibility - double _time; - double _deltaTime; - double _realDeltaTime; - } +double Time::time() { + if(!_instance) + return 0; - double time() - { - return _time; - } + return _instance->_time; +} - double deltaTime() - { - return _deltaTime; - } +double Time::deltaTime() { + if(!_instance) + return 0; - double realDeltaTime() - { - return _realDeltaTime; - } + return _instance->_deltaTime; +} - void update() - { - high_resolution_clock::time_point t = high_resolution_clock::now(); +void Time::update() { + if(!_instance) + return; + high_resolution_clock::time_point t = high_resolution_clock::now(); - _deltaTime = duration(t - _last).count(); - _time = duration(t - _start).count(); - // in case when fps < 10 it is useful to decrease _deltaTime (to avoid collision problems) - if(_deltaTime > BIG_STEP) - _deltaTime = BIG_STEP; + _instance->_deltaTime = duration(t - _instance->_last).count(); + _instance->_time = duration(t - _instance->_start).count(); + // in case when fps < 10 it is useful to decrease _deltaTime (to avoid collision problems) + if(_instance->_deltaTime > Consts::LARGEST_TIME_STEP) + _instance->_deltaTime = Consts::LARGEST_TIME_STEP; - _realDeltaTime = duration(t - _last).count(); - _last = t; + _instance->_last = t; - if(_deltaTime > 10000) - return; + if(_instance->_deltaTime > 10000) + return; - _fpsCounter++; - if (t - _fpsStart > _fpsCountTime) - { - _lastFps = _fpsCounter / duration(t - _fpsStart).count(); - _fpsCounter = 0; - _fpsStart = t; - } - } - - int fps() - { - // Cast is faster than floor and has the same behavior for positive numbers - return static_cast(_lastFps); + _instance->_fpsCounter++; + if (t - _instance->_fpsStart > _instance->_fpsCountTime) { + _instance->_lastFps = _instance->_fpsCounter / duration(t - _instance->_fpsStart).count(); + _instance->_fpsCounter = 0; + _instance->_fpsStart = t; } } + +int Time::fps() { + if(!_instance) + return 0; + // Cast is faster than floor and has the same behavior for positive numbers + return static_cast(_instance->_lastFps); +} + +void Time::free() { + Time* t = _instance; + + delete _instance; + _instance = nullptr; +} diff --git a/engine/utils/Time.h b/engine/utils/Time.h index ae305ea..f9624fd 100644 --- a/engine/utils/Time.h +++ b/engine/utils/Time.h @@ -5,14 +5,39 @@ #ifndef ENGINE_TIME_H #define ENGINE_TIME_H -namespace Time -{ - int fps(); - double time(); - double deltaTime(); - double realDeltaTime(); - void update(); -} +#include +class Time final { +private: + // High precision time + std::chrono::high_resolution_clock::time_point _start = std::chrono::high_resolution_clock::now(); + std::chrono::high_resolution_clock::time_point _last = _start; + + // FPS counter + std::chrono::high_resolution_clock::time_point _fpsStart{}; + std::chrono::milliseconds _fpsCountTime = std::chrono::milliseconds(1000); + int _fpsCounter = 0; + double _lastFps = 0; + + // Compatibility + double _time = 0; + double _deltaTime = 0; + + static Time* _instance; + + Time() = default; + +public: + Time(const Time&) = delete; + Time& operator=(Time&) = delete; + + static int fps(); + static double time(); + static double deltaTime(); + static void update(); + + static void init(); + static void free(); +}; #endif //INC_3DZAVR_TIME_H diff --git a/weapon/Ak47.cpp b/weapon/Ak47.cpp index c745262..d7b6496 100644 --- a/weapon/Ak47.cpp +++ b/weapon/Ak47.cpp @@ -9,8 +9,8 @@ using namespace std; Ak47::Ak47(int ammo, const std::string& weaponName) : Weapon(weaponName, ShooterConsts::AK47_OBJ, "obj/ak47_mat.txt", Vec3D{3, 3, 3}, Vec3D{-0.8, 1.3, 0.3}, Vec3D{0, Consts::PI, 0}) { - fireSound.setBuffer(*ResourceManager::loadSoundBuffer(ShooterConsts::AK47_FIRE_SOUND)); - reloadSound.setBuffer(*ResourceManager::loadSoundBuffer(ShooterConsts::AK47_RELOAD_SOUND)); + fireSound = ShooterConsts::AK47_FIRE_SOUND; + reloadSound = ShooterConsts::AK47_RELOAD_SOUND; _stockAmmo = ammo - _clipCapacity; diff --git a/weapon/Gold_Ak47.h b/weapon/Gold_Ak47.h index 61f9bd9..2ff2cda 100644 --- a/weapon/Gold_Ak47.h +++ b/weapon/Gold_Ak47.h @@ -11,8 +11,8 @@ class Gold_Ak47 final : public Weapon { public: explicit Gold_Ak47(int ammo = 200, const std::string& weaponName = "gold_ak47") : Weapon(weaponName, ShooterConsts::GOLD_AK47_OBJ, "obj/gold_ak47_mat.txt", Vec3D{3, 3, 3}, Vec3D{-0.8, 1.3, 0.3}, Vec3D{0, Consts::PI, 0}) { - fireSound.setBuffer(*ResourceManager::loadSoundBuffer(ShooterConsts::GOLD_AK47_FIRE_SOUND)); - reloadSound.setBuffer(*ResourceManager::loadSoundBuffer(ShooterConsts::GOLD_AK47_RELOAD_SOUND)); + fireSound = ShooterConsts::GOLD_AK47_FIRE_SOUND; + reloadSound = ShooterConsts::GOLD_AK47_RELOAD_SOUND; _initialPack = 200; _spreading = 1.0; diff --git a/weapon/Gun.cpp b/weapon/Gun.cpp index baf2110..3d363e3 100644 --- a/weapon/Gun.cpp +++ b/weapon/Gun.cpp @@ -9,8 +9,8 @@ using namespace std; Gun::Gun(int ammo, const std::string& weaponName) : Weapon(weaponName, ShooterConsts::GUN_OBJ, "obj/gun_mat.txt", Vec3D{3, 3, 3}, Vec3D{-0.8, 1.3, 0.3}, Vec3D{0, Consts::PI, 0}) { - fireSound.setBuffer(*ResourceManager::loadSoundBuffer(ShooterConsts::GUN_FIRE_SOUND)); - reloadSound.setBuffer(*ResourceManager::loadSoundBuffer(ShooterConsts::GUN_RELOAD_SOUND)); + fireSound = ShooterConsts::GUN_FIRE_SOUND; + reloadSound = ShooterConsts::GUN_RELOAD_SOUND; _initialPack = 30; _clipCapacity = 6; // how much ammo can be stored in one clip diff --git a/weapon/Rifle.cpp b/weapon/Rifle.cpp index ecb3e22..3a5263f 100644 --- a/weapon/Rifle.cpp +++ b/weapon/Rifle.cpp @@ -7,8 +7,8 @@ #include "../ShooterConsts.h" Rifle::Rifle(int ammo, const std::string &weaponName) : Weapon(weaponName, ShooterConsts::RIFLE_OBJ, "obj/rifle_mat.txt", Vec3D{3, 3, 3}, Vec3D{-1.2, 1, 0.3}, Vec3D{0, Consts::PI, 0}) { - fireSound.setBuffer(*ResourceManager::loadSoundBuffer(ShooterConsts::RIFLE_FIRE_SOUND)); - reloadSound.setBuffer(*ResourceManager::loadSoundBuffer(ShooterConsts::RIFLE_RELOAD_SOUND)); + fireSound = ShooterConsts::RIFLE_FIRE_SOUND; + reloadSound = ShooterConsts::RIFLE_RELOAD_SOUND; _initialPack = 5; _clipCapacity = 1; // how much ammo can be stored in one clip diff --git a/weapon/Shotgun.cpp b/weapon/Shotgun.cpp index 7544d3f..c24ae38 100644 --- a/weapon/Shotgun.cpp +++ b/weapon/Shotgun.cpp @@ -10,8 +10,8 @@ using namespace std; Shotgun::Shotgun(int ammo, const std::string& weaponName) : Weapon(weaponName, ShooterConsts::SHOTGUN_OBJ, "obj/shotgun_mat.txt", Vec3D{3, 3, 3}, Vec3D{-0.95, 1.3, -0.6}, Vec3D{0, Consts::PI, 0}) { - fireSound.setBuffer(*ResourceManager::loadSoundBuffer(ShooterConsts::SHOTGUN_FIRE_SOUND)); - reloadSound.setBuffer(*ResourceManager::loadSoundBuffer(ShooterConsts::SHOTGUN_RELOAD_SOUND)); + fireSound = ShooterConsts::SHOTGUN_FIRE_SOUND; + reloadSound = ShooterConsts::SHOTGUN_RELOAD_SOUND; //reloadSound.setVolume(30); _initialPack = 15; diff --git a/weapon/Weapon.cpp b/weapon/Weapon.cpp index 013e23f..150c299 100644 --- a/weapon/Weapon.cpp +++ b/weapon/Weapon.cpp @@ -19,15 +19,13 @@ Weapon::Weapon(const std::string& weaponName, const std::string& objFileName, co setCollider(false); rotate(r); translate(t); - - noAmmoSound.setBuffer(*ResourceManager::loadSoundBuffer(ShooterConsts::NO_AMMO_SOUND)); } std::map Weapon::fire(std::function(const Vec3D&, const Vec3D&)> rayCastFunction) { if(_clipAmmo == 0) { reload(); if(_clipAmmo == 0) - noAmmoSound.play(); + SoundController::playSound(SoundTag("noAmmo"), ShooterConsts::NO_AMMO_SOUND); } if(_clipAmmo <= 0 || std::abs(Time::time() - _lastFireTime) < _fireDelay || std::abs(Time::time() - _lastReloadTime) < _reloadTime) @@ -36,7 +34,7 @@ std::map Weapon::fire(std::function #include "../engine/Mesh.h" #include "../engine/utils/Time.h" - +#include "../engine/SoundController.h" #include "../engine/Consts.h" class Weapon : public RigidBody { @@ -34,11 +34,8 @@ protected: double _lastFireTime = std::numeric_limits::min(); double _lastReloadTime = std::numeric_limits::min(); - sf::Sound fireSound; - sf::Sound reloadSound; - sf::Sound noAmmoSound; - - int fireTraces = 0; + std::string fireSound; + std::string reloadSound; std::function _addTraceCallBack;