diff --git a/CMakeLists.txt b/CMakeLists.txt index fc6cda92..dd1ec71f 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,10 +3,7 @@ project(bomberman) set(CMAKE_CXX_STANDARD 20) - -# Find Lua -find_package(Lua REQUIRED) #-> CHANGE - +find_package(Lua REQUIRED) include_directories(bomberman ${LUA_INCLUDE_DIR}) include_directories(bomberman lib/Ray/sources) include_directories(bomberman lib/wal/sources) @@ -16,14 +13,12 @@ include_directories(bomberman sources) add_subdirectory(${PROJECT_SOURCE_DIR}/lib/wal) add_subdirectory(${PROJECT_SOURCE_DIR}/lib/Ray) -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2") - if (EMSCRIPTEN) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -s USE_GLFW=3 -s ASSERTIONS=1 -s WASM=1 -s ASYNCIFY") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s USE_GLFW=3 -s ASSERTIONS=1 -s WASM=1 -s ASYNCIFY") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -s NO_DISABLE_EXCEPTION_CATCHING --shell-file ../sources/wasm/frontend.html --preload-file ../assets") set(CMAKE_EXECUTABLE_SUFFIX ".html") -endif () +endif() set(SOURCES sources/Models/GameState.hpp @@ -37,6 +32,8 @@ set(SOURCES sources/Component/Movable/MovableComponent.hpp sources/Component/Controllable/ControllableComponent.hpp sources/Component/Controllable/ControllableComponent.cpp + sources/Component/BombHolder/BombHolderComponent.cpp + sources/Component/BombHolder/BombHolderComponent.hpp sources/Component/Gamepad/GamepadComponent.cpp sources/Component/Gamepad/GamepadComponent.hpp sources/Component/Keyboard/KeyboardComponent.cpp @@ -67,6 +64,14 @@ set(SOURCES sources/System/Renderer/RenderSystem.cpp sources/Component/Renderer/CameraComponent.cpp sources/Component/Renderer/CameraComponent.hpp + sources/System/BombHolder/BombHolderSystem.cpp + sources/System/BombHolder/BombHolderSystem.hpp + sources/Component/Timer/TimerComponent.cpp + sources/Component/Timer/TimerComponent.hpp + sources/System/Timer/TimerSystem.cpp + sources/System/Timer/TimerSystem.hpp + sources/System/Event/EventSystem.cpp + sources/System/Event/EventSystem.hpp sources/Component/Animation/AnimationsComponent.cpp sources/Component/Animation/AnimationsComponent.hpp sources/System/Animation/AnimationsSystem.cpp @@ -79,29 +84,42 @@ set(SOURCES sources/Component/IAControllable/IAControllableComponent.cpp sources/System/IAControllable/IAControllableSystem.hpp sources/System/IAControllable/IAControllableSystem.cpp - sources/Component/Tag/TagComponent.cpp - sources/Component/Tag/TagComponent.hpp sources/Map/MapInfo.hpp sources/Map/MapInfo.cpp + sources/Component/Animator/AnimatorComponent.cpp + sources/Component/Animator/AnimatorComponent.hpp + sources/System/Animator/AnimatorSystem.cpp + sources/System/Animator/AnimatorSystem.hpp + sources/Component/Tag/TagComponent.hpp + sources/Component/Music/MusicComponent.cpp + sources/Component/Music/MusicComponent.hpp + sources/Component/Sound/SoundComponent.hpp + sources/Component/Sound/SoundComponent.cpp + sources/System/Sound/PlayerSoundManagerSystem.cpp + sources/System/Sound/PlayerSoundManagerSystem.hpp + sources/System/Music/MusicSystem.hpp + sources/System/Music/MusicSystem.cpp ) add_executable(bomberman sources/main.cpp ${SOURCES} ) + target_include_directories(bomberman PUBLIC sources ${LUA_INCLUDE_DIR} lib/LuaBridge) target_link_libraries(bomberman PUBLIC wal ray ${LUA_LIBRARIES}) add_executable(unit_tests EXCLUDE_FROM_ALL - ${SOURCES} - tests/EntityTests.cpp - tests/MainTest.cpp - tests/EngineTests.cpp - tests/CallbackTest.cpp - tests/MoveTests.cpp - tests/ViewTest.cpp - tests/CollisionTest.cpp -) + ${SOURCES} + tests/CacheTest.cpp + tests/EntityTests.cpp + tests/MainTest.cpp + tests/EngineTests.cpp + tests/CallbackTest.cpp + tests/MoveTests.cpp + tests/ViewTest.cpp + tests/CollisionTest.cpp + ) target_include_directories(unit_tests PUBLIC sources) target_link_libraries(unit_tests PUBLIC wal ray lua) diff --git a/assets/map/bumper.png b/assets/map/bumper.png index a86b67f2..63632844 100644 Binary files a/assets/map/bumper.png and b/assets/map/bumper.png differ diff --git a/assets/musics/music_win.ogg b/assets/musics/music_win.ogg index eadd8eff..ee5195e3 100644 Binary files a/assets/musics/music_win.ogg and b/assets/musics/music_win.ogg differ diff --git a/assets/sounds/bomb_drop.ogg b/assets/sounds/bomb_drop.ogg new file mode 100644 index 00000000..40288f0e Binary files /dev/null and b/assets/sounds/bomb_drop.ogg differ diff --git a/assets/sounds/death.ogg b/assets/sounds/death.ogg new file mode 100644 index 00000000..b5822604 Binary files /dev/null and b/assets/sounds/death.ogg differ diff --git a/assets/sounds/fuse.ogg b/assets/sounds/fuse.ogg new file mode 100644 index 00000000..1d3007e8 Binary files /dev/null and b/assets/sounds/fuse.ogg differ diff --git a/assets/sounds/jump.wav b/assets/sounds/jump.wav new file mode 100644 index 00000000..642ae89a Binary files /dev/null and b/assets/sounds/jump.wav differ diff --git a/assets/sounds/move.ogg b/assets/sounds/move.ogg new file mode 100644 index 00000000..fc035509 Binary files /dev/null and b/assets/sounds/move.ogg differ diff --git a/lib/Ray/sources/Audio/Music.cpp b/lib/Ray/sources/Audio/Music.cpp index b397c04e..0a9b2660 100644 --- a/lib/Ray/sources/Audio/Music.cpp +++ b/lib/Ray/sources/Audio/Music.cpp @@ -8,57 +8,56 @@ #include "Audio/Music.hpp" #include -RAY::Audio::Music::Music(const std::string &path): - _music(LoadMusicStream(path.c_str())) -{ -} +RAY::Cache<::Music> RAY::Audio::Music::_musicsCache(LoadMusicStream, UnloadMusicStream); -RAY::Audio::Music::Music() +RAY::Audio::Music::Music(const std::string &path, bool lonely): + _music(this->_musicsCache.fetch(path, lonely)) { } -RAY::Audio::Music::~Music() -{ - UnloadMusicStream(_music); -} - bool RAY::Audio::Music::isPlaying(void) { - return IsMusicStreamPlaying(_music); + return IsMusicStreamPlaying(*_music); } RAY::Audio::Music &RAY::Audio::Music::play(void) { - PlayMusicStream(_music); + PlayMusicStream(*_music); return *this; } RAY::Audio::Music &RAY::Audio::Music::stop(void) { - StopMusicStream(_music); + StopMusicStream(*_music); return *this; } RAY::Audio::Music &RAY::Audio::Music::pause(void) { - PauseMusicStream(_music); + PauseMusicStream(*_music); return *this; } RAY::Audio::Music &RAY::Audio::Music::resume(void) { - ResumeMusicStream(_music); + ResumeMusicStream(*_music); return *this; } RAY::Audio::Music &RAY::Audio::Music::setVolume(float volume) { - SetMusicVolume(_music, volume); + SetMusicVolume(*_music, volume); return *this; } RAY::Audio::Music &RAY::Audio::Music::setPitch(float pitch) { - SetMusicPitch(_music, pitch); + SetMusicPitch(*_music, pitch); + return *this; +} + +RAY::Audio::Music &RAY::Audio::Music::updateMusicStream(void) +{ + UpdateMusicStream(*_music); return *this; } diff --git a/lib/Ray/sources/Audio/Music.hpp b/lib/Ray/sources/Audio/Music.hpp index 85f31c52..1aca0cc3 100644 --- a/lib/Ray/sources/Audio/Music.hpp +++ b/lib/Ray/sources/Audio/Music.hpp @@ -9,9 +9,8 @@ #define MUSIC_HPP_ #include "Audio/IAudio.hpp" - #include - +#include "Utils/Cache.hpp" namespace RAY::Audio { @@ -20,13 +19,11 @@ namespace RAY::Audio public: //! @brief Load Music stream from file - Music(const std::string &path); - - //! @brief Default constructor - Music(); + //! @param lonely: should be set to true if the entity's loaded data must be independant from others + Music(const std::string &path, bool lonely = false); //! @brief Default destructor - ~Music(); + ~Music() = default; //! @brief A copy constructor constructor Music(const Music &Music) = default; @@ -55,8 +52,12 @@ namespace RAY::Audio // Set pitch for a Music (1.0 is base level) Music &setPitch(float pitch) override; + Music &updateMusicStream(void); + private: - ::Music _music; + std::shared_ptr<::Music> _music; + + static RAY::Cache<::Music> _musicsCache; }; } diff --git a/lib/Ray/sources/Audio/Sound.cpp b/lib/Ray/sources/Audio/Sound.cpp index 4bfcb95a..de1002bc 100644 --- a/lib/Ray/sources/Audio/Sound.cpp +++ b/lib/Ray/sources/Audio/Sound.cpp @@ -7,58 +7,51 @@ #include "Audio/Sound.hpp" -RAY::Audio::Sound::Sound(const std::string &path): - _sound(LoadSound(path.c_str())) +RAY::Cache<::Sound> RAY::Audio::Sound::_soundsCache(LoadSound, UnloadSound); + +RAY::Audio::Sound::Sound(const std::string &path, bool lonely): + _sound(_soundsCache.fetch(path, lonely)) { } -RAY::Audio::Sound::Sound() -{ -} - -RAY::Audio::Sound::~Sound() -{ - UnloadSound(_sound); -} - bool RAY::Audio::Sound::isPlaying(void) { - return IsSoundPlaying(_sound); + return IsSoundPlaying(*_sound); } RAY::Audio::Sound &RAY::Audio::Sound::play(void) { - PlaySound(_sound); + PlaySound(*_sound); return *this; } RAY::Audio::Sound &RAY::Audio::Sound::stop(void) { - StopSound(_sound); + StopSound(*_sound); return *this; } RAY::Audio::Sound &RAY::Audio::Sound::pause(void) { - PauseSound(_sound); + PauseSound(*_sound); return *this; } RAY::Audio::Sound &RAY::Audio::Sound::resume(void) { - ResumeSound(_sound); + ResumeSound(*_sound); return *this; } RAY::Audio::Sound &RAY::Audio::Sound::setVolume(float volume) { - SetSoundVolume(_sound, volume); + SetSoundVolume(*_sound, volume); return *this; } RAY::Audio::Sound &RAY::Audio::Sound::setPitch(float pitch) { - SetSoundPitch(_sound, pitch); + SetSoundPitch(*_sound, pitch); return *this; } diff --git a/lib/Ray/sources/Audio/Sound.hpp b/lib/Ray/sources/Audio/Sound.hpp index 32dd8cb0..0f7a7ff5 100644 --- a/lib/Ray/sources/Audio/Sound.hpp +++ b/lib/Ray/sources/Audio/Sound.hpp @@ -9,7 +9,7 @@ #define SOUND_HPP_ #include "Audio/IAudio.hpp" - +#include "Utils/Cache.hpp" #include @@ -20,13 +20,11 @@ namespace RAY::Audio public: //! @brief Load Sound stream from file - Sound(const std::string &path); - - //! @brief Default constructor - Sound(); + //! @param lonely: should be set to true if the entity's loaded data must be independant from others + Sound(const std::string &path, bool lonely = false); //! @brief Default destructor - ~Sound(); + ~Sound() = default; //! @brief A copy constructor constructor Sound(const Sound &sound) = default; @@ -56,7 +54,9 @@ namespace RAY::Audio Sound &setPitch(float pitch) override; private: - ::Sound _sound; + std::shared_ptr<::Sound> _sound; + + static RAY::Cache<::Sound> _soundsCache; }; } diff --git a/lib/Ray/sources/Controllers/Gamepad.cpp b/lib/Ray/sources/Controllers/Gamepad.cpp index b51bcc95..7845411e 100644 --- a/lib/Ray/sources/Controllers/Gamepad.cpp +++ b/lib/Ray/sources/Controllers/Gamepad.cpp @@ -42,3 +42,8 @@ void RAY::Controller::GamePad::setID(int id) { this->_id = id; } + +float RAY::Controller::GamePad::getAxisValue(int index) +{ + return GetGamepadAxisMovement(this->_id, index); +} \ No newline at end of file diff --git a/lib/Ray/sources/Controllers/Gamepad.hpp b/lib/Ray/sources/Controllers/Gamepad.hpp index 893c674f..9f17acc8 100644 --- a/lib/Ray/sources/Controllers/Gamepad.hpp +++ b/lib/Ray/sources/Controllers/Gamepad.hpp @@ -17,6 +17,7 @@ namespace RAY::Controller { class GamePad { public: typedef ::GamepadButton Button; + typedef ::GamepadAxis Axis; //! @brief A default constructor //! @param The id of the controller @@ -44,6 +45,9 @@ namespace RAY::Controller { //! @param Button The keycode of the button bool isReleased(Button); + //! @brief Get the value of an axis + float getAxisValue(int index); + //! @brief Returns true if Button is up on the gamepad //! @param Button The keycode of the button bool isUp(Button); diff --git a/lib/Ray/sources/Drawables/Image.cpp b/lib/Ray/sources/Drawables/Image.cpp index 9676bc95..685aa376 100644 --- a/lib/Ray/sources/Drawables/Image.cpp +++ b/lib/Ray/sources/Drawables/Image.cpp @@ -12,9 +12,9 @@ namespace RAY { Cache<::Image> Image::_imagesCache(LoadImage, UnloadImage); - Image::Image(const std::string &filename): + Image::Image(const std::string &filename, bool lonely): Rectangle(Vector2(0, 0), Vector2(0, 0), WHITE), - _image(_imagesCache.fetch(filename)) + _image(_imagesCache.fetch(filename, lonely)) { this->_dimensions = Vector2(this->_image->width, this->_image->height); } diff --git a/lib/Ray/sources/Drawables/Image.hpp b/lib/Ray/sources/Drawables/Image.hpp index 840be518..911f1a96 100644 --- a/lib/Ray/sources/Drawables/Image.hpp +++ b/lib/Ray/sources/Drawables/Image.hpp @@ -21,7 +21,8 @@ namespace RAY public: //! @brief Create an image, loading a file //! @param filename: path to file to load - Image(const std::string &filename); + //! @param lonely: should be set to true if the entity's loaded data must be independant from others + Image(const std::string &filename, bool lonely = false); //! @brief A default copy constructor Image(const Image &image) = default; diff --git a/lib/Ray/sources/Drawables/Texture.cpp b/lib/Ray/sources/Drawables/Texture.cpp index befe8579..821a743d 100644 --- a/lib/Ray/sources/Drawables/Texture.cpp +++ b/lib/Ray/sources/Drawables/Texture.cpp @@ -11,8 +11,8 @@ namespace RAY { Cache<::Texture> Texture::_texturesCache(LoadTexture, UnloadTexture); - Texture::Texture(const std::string &filename): - _texture(_texturesCache.fetch(filename)), + Texture::Texture(const std::string &filename, bool lonely): + _texture(_texturesCache.fetch(filename, lonely)), _resourcePath(filename) { } diff --git a/lib/Ray/sources/Drawables/Texture.hpp b/lib/Ray/sources/Drawables/Texture.hpp index 6fb2be66..2952b58d 100644 --- a/lib/Ray/sources/Drawables/Texture.hpp +++ b/lib/Ray/sources/Drawables/Texture.hpp @@ -19,7 +19,8 @@ namespace RAY public: //! @brief Create an texture, loading a file //! @param filename: path to file to load - Texture(const std::string &filename); + //! @param lonely: should be set to true if the entity's loaded data must be independant from others + Texture(const std::string &filename, bool lonely = false); //! @brief A texture is copy constructable Texture(const Texture &) = default; diff --git a/lib/Ray/sources/Font.cpp b/lib/Ray/sources/Font.cpp index c4288463..89bf9517 100644 --- a/lib/Ray/sources/Font.cpp +++ b/lib/Ray/sources/Font.cpp @@ -9,8 +9,8 @@ RAY::Cache<::Font> RAY::Font::_fontsCache(LoadFont, UnloadFont); -RAY::Font::Font(const std::string &filename): - _font(_fontsCache.fetch(filename)) +RAY::Font::Font(const std::string &filename, bool lonely): + _font(_fontsCache.fetch(filename, lonely)) { } diff --git a/lib/Ray/sources/Font.hpp b/lib/Ray/sources/Font.hpp index a403dcb3..1aaeb173 100644 --- a/lib/Ray/sources/Font.hpp +++ b/lib/Ray/sources/Font.hpp @@ -19,7 +19,8 @@ namespace RAY public: //! @brief Create an font, loading a file //! @param filename: path to file to load - Font(const std::string &filename); + //! @param lonely: should be set to true if the entity's loaded data must be independant from others + Font(const std::string &filename, bool lonely = false); //! @brief A default copy constructor Font(const Font &) = default; diff --git a/lib/Ray/sources/Model/Model.cpp b/lib/Ray/sources/Model/Model.cpp index aab5fdc6..77951483 100644 --- a/lib/Ray/sources/Model/Model.cpp +++ b/lib/Ray/sources/Model/Model.cpp @@ -19,9 +19,9 @@ namespace RAY::Drawables::Drawables3D { const RAY::Vector3 &scale, const RAY::Vector3 &position, const RAY::Vector3 &rotationAxis, - float rotationAngle) + float rotationAngle, bool lonely) : ADrawable3D(position, WHITE), - _model(_modelsCache.fetch(filename)), + _model(_modelsCache.fetch(filename, lonely)), _rotationAxis(rotationAxis), _rotationAngle(rotationAngle), _scale(scale) diff --git a/lib/Ray/sources/Model/Model.hpp b/lib/Ray/sources/Model/Model.hpp index 7a7e3fdf..40c9a9dd 100644 --- a/lib/Ray/sources/Model/Model.hpp +++ b/lib/Ray/sources/Model/Model.hpp @@ -25,12 +25,13 @@ namespace RAY::Drawables::Drawables3D { //! @brief Create an model, loading a file //! @param filePath: path to file to load + //! @param lonely: should be set to true if the entity's loaded data must be independant from others Model(const std::string &filePath, std::optional> texture = std::nullopt, const RAY::Vector3 &scale = RAY::Vector3(1, 1, 1), const RAY::Vector3 &position = {0, 0, 0}, const RAY::Vector3 &rotationAxis = RAY::Vector3(0, 1, 0), - float rotationAngle = 0); + float rotationAngle = 0, bool lonely = false); //! @brief Create an model, loading a file //! @param mesh: mesh to load diff --git a/lib/Ray/sources/Utils/Cache.hpp b/lib/Ray/sources/Utils/Cache.hpp index 7f041853..cea5dd71 100644 --- a/lib/Ray/sources/Utils/Cache.hpp +++ b/lib/Ray/sources/Utils/Cache.hpp @@ -9,6 +9,11 @@ #include #include #include +#include +#include +#include +#include +#include namespace RAY { //! @brief A templated class used to cache ressources, indexed with a string @@ -30,16 +35,28 @@ namespace RAY { Cache &operator=(const Cache &) = default; //! @param path path of the file + //! @param lonely: should be set to true if the loaded data must be held by no other active entites //! @return a newly loaded ressource if it hasn't be previously loaded, or one from cache - std::shared_ptrfetch(const std::string &path) + std::shared_ptrfetch(const std::string &path, bool lonely = false) { - if (this->_cache.find(path) == this->_cache.end()) - this->_cache.emplace(path, std::shared_ptr( - new T(this->_dataLoader(path.c_str())), [this](T *p) { - this->_dataUnloader(*p); - delete p; - })); - return _cache[path]; + if (!this->_cache.contains(path)) + this->_cache.emplace(path, std::vector>()); + std::vector> &matchingDataVector = this->_cache.at(path); + + if (matchingDataVector.size()) { + for (std::shared_ptr &i: matchingDataVector) { + if (!lonely) + return i; + if (lonely && i.use_count() == 1) + return i; + } + } + matchingDataVector.push_back(std::shared_ptr( + new T(this->_dataLoader(path.c_str())), [this](T *p) { + this->_dataUnloader(*p); + delete p; + })); + return matchingDataVector.back(); }; private: //! @brief function to call to load data @@ -49,7 +66,7 @@ namespace RAY { std::function _dataUnloader; //! @brief map storing shared ptr of caches - std::unordered_map> _cache; + std::unordered_map>> _cache; }; template<> diff --git a/lib/Ray/sources/Window.cpp b/lib/Ray/sources/Window.cpp index df332bb6..a9a1d9bf 100644 --- a/lib/Ray/sources/Window.cpp +++ b/lib/Ray/sources/Window.cpp @@ -49,6 +49,7 @@ bool RAY::Window::open(void) } InitWindow(this->_dimensions.x, this->_dimensions.y, this->_title.c_str()); this->_isOpen = true; + InitAudioDevice(); return true; } @@ -60,6 +61,7 @@ bool RAY::Window::shouldClose(void) const void RAY::Window::close(void) { CloseWindow(); + CloseAudioDevice(); } bool RAY::Window::isFocused(void) const diff --git a/lib/wal/sources/Entity/Entity.cpp b/lib/wal/sources/Entity/Entity.cpp index 35fa2c53..8e4ff0f1 100644 --- a/lib/wal/sources/Entity/Entity.cpp +++ b/lib/wal/sources/Entity/Entity.cpp @@ -11,17 +11,19 @@ namespace WAL { unsigned Entity::nextID = 0; - Entity::Entity(Scene &scene, std::string name) + Entity::Entity(Scene &scene, std::string name, bool notifyScene) : _uid(Entity::nextID++), _scene(scene), - _name(std::move(name)) + _name(std::move(name)), + _notifyScene(notifyScene) { } Entity::Entity(const Entity &other) : _uid(Entity::nextID++), _scene(other._scene), _name(other._name), - _disabled(other._disabled) + _disabled(other._disabled), + _notifyScene(other._notifyScene) { for (const auto &cmp : other._components) this->addComponent(*cmp.second); @@ -50,21 +52,27 @@ namespace WAL Entity &Entity::addComponent(const Component &component) { const std::type_index &type = typeid(component); - if (this->hasComponent(type)) + if (this->hasComponent(type, false)) throw DuplicateError("A component of the type \"" + std::string(type.name()) + "\" already exists."); this->_components.emplace(type, component.clone(*this)); - this->_scene._componentAdded(*this, type); + if (this->_notifyScene) + this->_scene._componentAdded(*this, type); return *this; } - bool Entity::hasComponent(const std::type_info &type) const + bool Entity::hasComponent(const std::type_info &type, bool skipDisabled) const { - return this->hasComponent(static_cast(type)); + return this->hasComponent(static_cast(type), skipDisabled); } - bool Entity::hasComponent(const std::type_index &type) const + bool Entity::hasComponent(const std::type_index &type, bool skipDisabled) const { - return this->_components.contains(type); + auto cmp = this->_components.find(type); + if (cmp == this->_components.end()) + return false; + if (skipDisabled) + return !cmp->second->isDisabled(); + return true; } void Entity::_componentAdded(const std::type_index &type) @@ -76,4 +84,14 @@ namespace WAL { this->_scene._componentRemoved(*this, type); } + + bool Entity::shouldDelete() const + { + return this->_shouldDelete; + } + + void Entity::scheduleDeletion() + { + this->_shouldDelete = true; + } } // namespace WAL \ No newline at end of file diff --git a/lib/wal/sources/Entity/Entity.hpp b/lib/wal/sources/Entity/Entity.hpp index 25234f31..9eab09a4 100644 --- a/lib/wal/sources/Entity/Entity.hpp +++ b/lib/wal/sources/Entity/Entity.hpp @@ -26,6 +26,10 @@ namespace WAL std::string _name; //! @brief Is this entity enabled? bool _disabled = false; + //! @brief Has this entity been scheduled for deletion? + bool _shouldDelete = false; + //! @brief Should this entity notify the scene of component changes? + bool _notifyScene; //! @brief The list of the components of this entity std::unordered_map> _components = {}; @@ -38,6 +42,8 @@ namespace WAL //! @brief Callback called when a component is removed //! @param type The type of component void _componentRemoved(const std::type_index &type); + + friend Scene; protected: //! @brief A reference to the ECS. Scene &_scene; @@ -49,10 +55,14 @@ namespace WAL //! @brief Used if the entity is disabled bool isDisable() const; - //! @brief Disable this entity. void setDisable(bool disabled); + //! @brief Has this entity been scheduled for deletion? + bool shouldDelete() const; + //! @brief Schedule this entity for deletion + void scheduleDeletion(); + //! @brief Get a component of a specific type //! @tparam The type of the component //! @throw NotFoundError if the component could not be found @@ -106,21 +116,24 @@ namespace WAL } //! @brief Check if this entity has a component. + //! @param skipDisabled True if you want to skip disabled components (consider them non present), false otherwise. //! @tparam T The type of the component template - bool hasComponent() const + bool hasComponent(bool skipDisabled = true) const { const std::type_info &type = typeid(T); - return this->hasComponent(type); + return this->hasComponent(type, skipDisabled); } //! @brief Check if this entity has a component. + //! @param skipDisabled True if you want to skip disabled components (consider them non present), false otherwise. //! @param type The type of the component - bool hasComponent(const std::type_info &type) const; + bool hasComponent(const std::type_info &type, bool skipDisabled = true) const; //! @brief Check if this entity has a component. + //! @param skipDisabled True if you want to skip disabled components (consider them non present), false otherwise. //! @param type The type of the component - bool hasComponent(const std::type_index &type) const; + bool hasComponent(const std::type_index &type, bool skipDisabled = true) const; //! @brief Add a component to this entity. The component is constructed in place. //! @throw DuplicateError is thrown if a component with the same type already exist. @@ -132,7 +145,8 @@ namespace WAL if (this->hasComponent(type)) throw DuplicateError("A component of the type \"" + std::string(type.name()) + "\" already exists."); this->_components[type] = std::make_unique(*this, TypeHolder()..., std::forward(params)...); - this->_componentAdded(type); + if (this->_notifyScene) + this->_componentAdded(type); return *this; } @@ -151,12 +165,13 @@ namespace WAL if (existing == this->_components.end()) throw NotFoundError("No component could be found with the type \"" + std::string(type.name()) + "\"."); this->_components.erase(existing); - this->_componentRemoved(type); + if (this->_notifyScene) + this->_componentRemoved(type); return *this; } //! @brief A default constructor - explicit Entity(Scene &wal, std::string name); + explicit Entity(Scene &wal, std::string name, bool notifyScene = true); //! @brief An entity is copyable Entity(const Entity &); //! @brief An entity is movable. diff --git a/lib/wal/sources/Scene/Scene.cpp b/lib/wal/sources/Scene/Scene.cpp index 77526662..34ca940c 100644 --- a/lib/wal/sources/Scene/Scene.cpp +++ b/lib/wal/sources/Scene/Scene.cpp @@ -24,6 +24,11 @@ namespace WAL return this->_entities.emplace_back(*this, name); } + Entity &Scene::scheduleNewEntity(const std::string &name) + { + return this->_newEntities.emplace_back(*this, name, false); + } + void Scene::_componentAdded(Entity &entity, const std::type_index &type) { for (auto &view : this->_views) { @@ -45,4 +50,31 @@ namespace WAL view->erase(entity); } } + + void Scene::_entityRemoved(const Entity &entity) + { + for (auto &view : this->_views) + view->erase(entity); + } + + void Scene::applyChanges() + { + this->_entities.remove_if([this](auto &entity) { + if (!entity.shouldDelete()) + return false; + this->_entityRemoved(entity); + return true; + }); + for (auto &entity : this->_newEntities) { + for (auto &view : this->_views) { + bool valid = std::all_of(view->getTypes().begin(), view->getTypes().end(), [&entity](const auto &type){ + return entity.hasComponent(type); + }); + if (valid) + view->emplace_back(entity); + } + entity._notifyScene = true; + } + this->_entities.splice(this->_entities.end(), this->_newEntities); + } } // namespace WAL \ No newline at end of file diff --git a/lib/wal/sources/Scene/Scene.hpp b/lib/wal/sources/Scene/Scene.hpp index aab47566..3d7f702a 100644 --- a/lib/wal/sources/Scene/Scene.hpp +++ b/lib/wal/sources/Scene/Scene.hpp @@ -23,6 +23,8 @@ namespace WAL //! @brief The list of registered entities std::list _entities = {}; + //! @brief The list of entities to add on the next call to applyChanges. + std::list _newEntities = {}; //! @brief The list of cached views to update. std::vector> _views = {}; @@ -34,6 +36,9 @@ namespace WAL //! @param entity The entity with the removed component //! @param type The type of the component removed. void _componentRemoved(const Entity &entity, const std::type_index &type); + //! @brief Remove an entity from every views. + //! @param entity The entity to remove. + void _entityRemoved(const Entity &entity); public: //! @brief Get the list of entities. std::list &getEntities(); @@ -43,6 +48,11 @@ namespace WAL //! @return The created entity is returned. Entity &addEntity(const std::string &name); + //! @brief Add a new entity to the scene, this entity will be added on the next call to applyChanges. + //! @param name The name of the created entity. + //! @return The created entity is returned. + Entity &scheduleNewEntity(const std::string &name); + template View &view() { @@ -56,6 +66,9 @@ namespace WAL return *view; } + //! @brief Delete entities marked as deleted and create scheduled entities. + void applyChanges(); + //! @brief A default constructor Scene() = default; //! @brief A scene is copy constructable diff --git a/lib/wal/sources/View/View.hpp b/lib/wal/sources/View/View.hpp index 15b31e09..50726a82 100644 --- a/lib/wal/sources/View/View.hpp +++ b/lib/wal/sources/View/View.hpp @@ -178,9 +178,9 @@ namespace WAL void erase(const Entity &entity) override { - this->_entities.erase(std::remove_if(this->_entities.begin(), this->_entities.end(), [&entity](const auto &ref){ - return &std::get<0>(ref).get() == &entity; - })); + this->_entities.erase(std::remove_if(this->_entities.begin(), this->_entities.end(), [&entity](const auto &ref) { + return std::get<0>(ref).get().getUid() == entity.getUid(); + }), this->_entities.end()); } //! @brief Construct a view from a list of entities. diff --git a/lib/wal/sources/Wal.hpp b/lib/wal/sources/Wal.hpp index de6bb394..4748e84e 100644 --- a/lib/wal/sources/Wal.hpp +++ b/lib/wal/sources/Wal.hpp @@ -52,6 +52,7 @@ namespace WAL } for (auto &system : this->_systems) system->update(dtime); + this->scene->applyChanges(); callback(*this, state); } } @@ -75,6 +76,7 @@ namespace WAL } for (auto &system : wal._systems) system->update(dtime); + wal.scene->applyChanges(); callback(wal, state); } #endif diff --git a/sources/Component/Animator/AnimatorComponent.cpp b/sources/Component/Animator/AnimatorComponent.cpp new file mode 100644 index 00000000..fa5d8cc2 --- /dev/null +++ b/sources/Component/Animator/AnimatorComponent.cpp @@ -0,0 +1,16 @@ +// +// Created by hbenjamin on 03/06/2021. +// + +#include "AnimatorComponent.hpp" + +namespace BBM { + AnimatorComponent::AnimatorComponent(WAL::Entity &entity) + : WAL::Component(entity) + {} + + WAL::Component *AnimatorComponent::clone(WAL::Entity &entity) const + { + return new AnimatorComponent(entity); + } +} \ No newline at end of file diff --git a/sources/Component/Animator/AnimatorComponent.hpp b/sources/Component/Animator/AnimatorComponent.hpp new file mode 100644 index 00000000..0c31b576 --- /dev/null +++ b/sources/Component/Animator/AnimatorComponent.hpp @@ -0,0 +1,28 @@ +// +// Created by hbenjamin on 03/06/2021. +// + +#pragma once + +#include + +namespace BBM { + class AnimatorComponent : public WAL::Component + { + public: + //! @inherit + WAL::Component *clone(WAL::Entity &entity) const override; + + //! @brief An Animator component can't be instantiated, it should be derived. + explicit AnimatorComponent(WAL::Entity &entity); + + //! @brief An Animator component can't be instantiated, it should be derived. + AnimatorComponent(const AnimatorComponent &) = default; + + //! @brief default destructor + ~AnimatorComponent() override = default; + + //! @brief An Animator component can't be assigned + AnimatorComponent &operator=(const AnimatorComponent &) = delete; + }; +} \ No newline at end of file diff --git a/sources/Component/BombHolder/BombHolderComponent.cpp b/sources/Component/BombHolder/BombHolderComponent.cpp new file mode 100644 index 00000000..9f75b8ae --- /dev/null +++ b/sources/Component/BombHolder/BombHolderComponent.cpp @@ -0,0 +1,24 @@ +// +// Created by Tom Augier on 2021-05-20. +// Edited by Benjamin Henry on 2021-05-20. +// Edited by Louis Auzuret on 2021-05-20. +// + +#include "BombHolderComponent.hpp" + +namespace BBM +{ + BombHolderComponent::BombHolderComponent(WAL::Entity &entity) + : WAL::Component(entity) + {} + + BombHolderComponent::BombHolderComponent(WAL::Entity &entity, unsigned int maxBombCount) + : WAL::Component(entity), + maxBombCount(maxBombCount) + {} + + WAL::Component *BombHolderComponent::clone(WAL::Entity &entity) const + { + return new BombHolderComponent(entity, this->maxBombCount); + } +} \ No newline at end of file diff --git a/sources/Component/BombHolder/BombHolderComponent.hpp b/sources/Component/BombHolder/BombHolderComponent.hpp new file mode 100644 index 00000000..03906e84 --- /dev/null +++ b/sources/Component/BombHolder/BombHolderComponent.hpp @@ -0,0 +1,47 @@ +// +// Created by Tom Augier on 2021-05-20. +// Edited by Benjamin Henry on 2021-05-20. +// Edited by Louis Auzuret on 2021-05-20. +// + +#pragma once + +#include "Component/Component.hpp" +#include "Entity/Entity.hpp" +#include + +using namespace std::chrono_literals; + +namespace BBM +{ + class BombHolderComponent : public WAL::Component + { + public: + //! @brief The number of bomb that this entity hold. + unsigned int bombCount = 1; + //! @brief The max number of bomb that this entity can have. + unsigned int maxBombCount = 3; + //! @brief The number of seconds of each refill. This variable is used to reset the nextBombRefill value. + std::chrono::nanoseconds refillRate = 5000ms; + //! @brief The number of nanosecond before the next bomb refill. + std::chrono::nanoseconds nextBombRefill = refillRate; + + //! @inherit + WAL::Component *clone(WAL::Entity &entity) const override; + + //! @brief A component can't be instantiated, it should be derived. + explicit BombHolderComponent(WAL::Entity &entity); + + //! @brief Constructor + BombHolderComponent(WAL::Entity &entity, unsigned int maxBombCount); + + //! @brief A component can't be instantiated, it should be derived. + BombHolderComponent(const BombHolderComponent &) = default; + + //! @brief default destructor + ~BombHolderComponent() override = default; + + //! @brief A component can't be assigned + BombHolderComponent &operator=(const BombHolderComponent &) = delete; + }; +} \ No newline at end of file diff --git a/sources/Component/Collision/CollisionComponent.cpp b/sources/Component/Collision/CollisionComponent.cpp index df727b2d..652e6727 100644 --- a/sources/Component/Collision/CollisionComponent.cpp +++ b/sources/Component/Collision/CollisionComponent.cpp @@ -4,31 +4,54 @@ #include "Component/Collision/CollisionComponent.hpp" - -namespace BBM +namespace BBM { CollisionComponent::CollisionComponent(WAL::Entity &entity) - : WAL::Component(entity) - { } + : WAL::Component(entity) + {} WAL::Component *CollisionComponent::clone(WAL::Entity &entity) const { return new CollisionComponent(entity); } - CollisionComponent::CollisionComponent(WAL::Entity &entity, WAL::Callback onCollide, WAL::Callback onCollided, Vector3f bound) - : WAL::Component(entity), onCollide(onCollide), onCollided(onCollided), bound(bound) - { } + CollisionComponent::CollisionComponent(WAL::Entity &entity, + const WAL::Callback &onCollide, + const WAL::Callback &onCollided, + Vector3f positionOffset, + Vector3f bound) + : WAL::Component(entity), + onCollide(onCollide), + onCollided(onCollided), + bound(bound), + positionOffset(positionOffset) + {} - CollisionComponent::CollisionComponent(WAL::Entity &entity, WAL::Callback onCollide, WAL::Callback onCollided, float boundSize) - : WAL::Component(entity), onCollide(onCollide), onCollided(onCollided), bound({boundSize, boundSize, boundSize}) - { } + CollisionComponent::CollisionComponent(WAL::Entity &entity, + const WAL::Callback &onCollide, + const WAL::Callback &onCollided, + float positionOffset, + float boundSize) + : WAL::Component(entity), + onCollide(onCollide), + onCollided(onCollided), + bound({boundSize, boundSize, boundSize}), + positionOffset({positionOffset, positionOffset, positionOffset}) + {} - CollisionComponent::CollisionComponent(WAL::Entity &entity, Vector3f bound) - : WAL::Component(entity), onCollide(), onCollided(), bound(bound) - { } + CollisionComponent::CollisionComponent(WAL::Entity &entity, Vector3f positionOffset, Vector3f bound) + : WAL::Component(entity), + onCollide(), + onCollided(), + bound(bound), + positionOffset(positionOffset) + {} - CollisionComponent::CollisionComponent(WAL::Entity &entity, float boundSize) - : WAL::Component(entity), onCollide(), onCollided(), bound({boundSize, boundSize, boundSize}) - { } + CollisionComponent::CollisionComponent(WAL::Entity &entity, float positionOffset, float boundSize) + : WAL::Component(entity), + onCollide(), + onCollided(), + bound({boundSize, boundSize, boundSize}), + positionOffset({positionOffset, positionOffset, positionOffset}) + {} } \ No newline at end of file diff --git a/sources/Component/Collision/CollisionComponent.hpp b/sources/Component/Collision/CollisionComponent.hpp index 5bfe7e16..06878a76 100644 --- a/sources/Component/Collision/CollisionComponent.hpp +++ b/sources/Component/Collision/CollisionComponent.hpp @@ -9,43 +9,61 @@ #include "Component/Component.hpp" #include "Entity/Entity.hpp" -namespace BBM +namespace BBM { class CollisionComponent : public WAL::Component { - private: - public: - //! @brief onCollide functions to be called - WAL::Callback onCollide; - //! @brief onCollided functions to be called - WAL::Callback onCollided; - //! @brief Bound size on all axis - Vector3f bound; - //! @inherit - WAL::Component *clone(WAL::Entity &entity) const override; + public: + //! @brief Used to tell the collided axis + //! @note Usage: (collidedAxis (int given by callback)) & CollidedAxis::X + enum CollidedAxis { + X = 1, + Y = 2, + Z = 4 + }; - //! @brief A component can't be instantiated, it should be derived. - explicit CollisionComponent(WAL::Entity &entity); + //! @brief onCollide functions to be called + WAL::Callback onCollide; + //! @brief onCollided functions to be called + WAL::Callback onCollided; + //! @brief Bound size on all axis + Vector3f bound; + //! @brief Offset from the position component + Vector3f positionOffset; - //! @brief Constructor with a WAL::Callback - CollisionComponent(WAL::Entity &entity, WAL::Callback onCollide, WAL::Callback onCollided,Vector3f bound); + //! @inherit + WAL::Component *clone(WAL::Entity &entity) const override; - //! @brief Constructor with a WAL::Callback, same boundSize for all axis - CollisionComponent(WAL::Entity &entity, WAL::Callback onCollide, WAL::Callback onCollided, float boundSize = 0); + //! @brief A component can't be instantiated, it should be derived. + explicit CollisionComponent(WAL::Entity &entity); - //! @brief Constructor of collider with no callback - CollisionComponent(WAL::Entity &entity, Vector3f bound); + //! @brief Constructor with a WAL::Callback + CollisionComponent(WAL::Entity &entity, + const WAL::Callback &onCollide, + const WAL::Callback &onCollided, + Vector3f positionOffset, + Vector3f bound); - //! @brief Constructor no callback, same boundSize for all axis - CollisionComponent(WAL::Entity &entity, float boundSize); + //! @brief Constructor with a WAL::Callback, same boundSize for all axis + CollisionComponent(WAL::Entity &entity, + const WAL::Callback &onCollide, + const WAL::Callback &onCollided, + float positionOffset, + float boundSize); - //! @brief Default copy constructor - CollisionComponent(const CollisionComponent &) = default; + //! @brief Constructor of collider with no callback + CollisionComponent(WAL::Entity &entity, Vector3f positionOffset, Vector3f bound); - //! @brief default destructor - ~CollisionComponent() override = default; + //! @brief Constructor no callback, same boundSize & positionOffset for all axis + CollisionComponent(WAL::Entity &entity, float positionOffset, float boundSize); - //! @brief A component can't be assigned - CollisionComponent &operator=(const CollisionComponent &) = delete; + //! @brief Default copy constructor + CollisionComponent(const CollisionComponent &) = default; + + //! @brief default destructor + ~CollisionComponent() override = default; + + //! @brief A component can't be assigned + CollisionComponent &operator=(const CollisionComponent &) = delete; }; } \ No newline at end of file diff --git a/sources/Component/Gamepad/GamepadComponent.hpp b/sources/Component/Gamepad/GamepadComponent.hpp index be00a49b..3825645d 100644 --- a/sources/Component/Gamepad/GamepadComponent.hpp +++ b/sources/Component/Gamepad/GamepadComponent.hpp @@ -10,6 +10,7 @@ #include "Entity/Entity.hpp" using Button = RAY::Controller::GamePad::Button; +using Axis = RAY::Controller::GamePad::Axis; using Gamepad = RAY::Controller::GamePad; namespace BBM @@ -35,6 +36,11 @@ namespace BBM //! @brief move down key Button keyDown = GAMEPAD_BUTTON_LEFT_FACE_DOWN; + Axis LeftStickX = GAMEPAD_AXIS_LEFT_X; + Axis LeftStickY = GAMEPAD_AXIS_LEFT_Y; + Axis RightStickX = GAMEPAD_AXIS_RIGHT_X; + Axis RightStickY = GAMEPAD_AXIS_RIGHT_Y; + //! @inherit WAL::Component *clone(WAL::Entity &entity) const override; diff --git a/sources/Component/Health/HealthComponent.cpp b/sources/Component/Health/HealthComponent.cpp index fe81fabb..8901ab31 100644 --- a/sources/Component/Health/HealthComponent.cpp +++ b/sources/Component/Health/HealthComponent.cpp @@ -6,21 +6,19 @@ #include "HealthComponent.hpp" +#include + namespace BBM { - HealthComponent::HealthComponent(WAL::Entity &entity) + HealthComponent::HealthComponent(WAL::Entity &entity, unsigned int healthPoint, const WAL::Callback &onDeath) : WAL::Component(entity), - _healthPoint() - {} - - HealthComponent::HealthComponent(WAL::Entity &entity, unsigned int healthPoint) - : WAL::Component(entity), - _healthPoint(healthPoint) + _healthPoint(healthPoint), + onDeath(onDeath) {} WAL::Component *HealthComponent::clone(WAL::Entity &entity) const { - return new HealthComponent(entity); + return new HealthComponent(entity, this->_healthPoint, this->onDeath); } void HealthComponent::addHealthPoint(unsigned int healthPoint) diff --git a/sources/Component/Health/HealthComponent.hpp b/sources/Component/Health/HealthComponent.hpp index 2eadafc5..29c202d4 100644 --- a/sources/Component/Health/HealthComponent.hpp +++ b/sources/Component/Health/HealthComponent.hpp @@ -34,12 +34,9 @@ namespace BBM //! @inherit WAL::Component *clone(WAL::Entity &entity) const override; - - //! @brief A Health component can't be instantiated, it should be derived. - explicit HealthComponent(WAL::Entity &entity); //! @brief Constructor - HealthComponent(WAL::Entity &entity, unsigned int healthPoint); + HealthComponent(WAL::Entity &entity, unsigned int healthPoint, const WAL::Callback &onDeath = WAL::Callback()); //! @brief A Health component can't be instantiated, it should be derived. HealthComponent(const HealthComponent &) = default; diff --git a/sources/Component/Keyboard/KeyboardComponent.hpp b/sources/Component/Keyboard/KeyboardComponent.hpp index bd0f2ab7..2ad2e6f2 100644 --- a/sources/Component/Keyboard/KeyboardComponent.hpp +++ b/sources/Component/Keyboard/KeyboardComponent.hpp @@ -23,9 +23,9 @@ namespace BBM //! @brief pause key Key keyPause = KEY_ESCAPE; //! @brief move right key - Key keyRight = KEY_A; + Key keyRight = KEY_D; //! @brief move left key - Key keyLeft = KEY_D; + Key keyLeft = KEY_A; //! @brief move up key Key keyUp = KEY_W; //! @brief move down key diff --git a/sources/Component/Music/MusicComponent.cpp b/sources/Component/Music/MusicComponent.cpp new file mode 100644 index 00000000..40dc33b1 --- /dev/null +++ b/sources/Component/Music/MusicComponent.cpp @@ -0,0 +1,65 @@ +// +// Created by Tom Augier on 05/06/2021 +// + +#include +#include "MusicComponent.hpp" + +namespace BBM +{ + float MusicComponent::volume = 0.75; + + MusicComponent::MusicComponent(WAL::Entity &entity, const std::string &musicPath) + : WAL::Component(entity), + _musicPath(musicPath), + _music(RAY::Audio::Music(musicPath)) + { + } + + WAL::Component *MusicComponent::clone(WAL::Entity &entity) const + { + return new MusicComponent(entity, this->_musicPath); + } + + void MusicComponent::playMusic(void) + { + if (!this->_music.isPlaying()) { + this->_music.play(); + } + } + + void MusicComponent::stopMusic(void) + { + if (this->_music.isPlaying()) + this->_music.stop(); + } + + void MusicComponent::pauseMusic(void) + { + this->_music.pause(); + } + + void MusicComponent::setVolume(float &volumeUpdate) + { + if (volumeUpdate >= 0) { + this->volume = volumeUpdate; + this->_music.setVolume(this->volume); + } + } + + void MusicComponent::setPitch(float &pitch) + { + this->_music.setPitch(pitch); + } + + bool MusicComponent::isPlaying(void) + { + return (this->_music.isPlaying()); + } + + void MusicComponent::updateMusicStream(void) + { + this->_music.updateMusicStream(); + } + +} // namespace WAL diff --git a/sources/Component/Music/MusicComponent.hpp b/sources/Component/Music/MusicComponent.hpp new file mode 100644 index 00000000..7898fd6e --- /dev/null +++ b/sources/Component/Music/MusicComponent.hpp @@ -0,0 +1,55 @@ +// +// Created by Tom Augier on 05/06/2021 +// + +#pragma once + +#include "Component/Component.hpp" +#include +#include "Audio/Music.hpp" + +namespace BBM +{ + //! @brief A basic Music component + class MusicComponent : public WAL::Component + { + public: + //! @brief start music + void playMusic(); + + //! @brief stop music + void stopMusic(); + + //! @brief put music on hold + void pauseMusic(); + + //! @brief set music volume + void setVolume(float &); + + //! @brief set pitch volume + void setPitch(float &); + + //! @brief is music playing + bool isPlaying(void); + //! @brief update music stream + void updateMusicStream(void); + //! @inherit + WAL::Component *clone(WAL::Entity &entity) const override; + //! @brief Create a new MusicComponent at a certain Music + explicit MusicComponent(WAL::Entity &entity, const std::string &musicPath); + //! @brief A Music component is copy constructable + MusicComponent(const MusicComponent &) = default; + //! @brief A default destructor + ~MusicComponent() override = default; + //! @brief A Music component is not assignable + MusicComponent &operator=(const MusicComponent &) = delete; + //! @brief Volume of the muisc + static float volume; + private: + //! @brief music of this entity + RAY::Audio::Music _music; + //! @brief patht to the music assets + const std::string _musicPath; + }; + +} // namespace BBM \ No newline at end of file diff --git a/sources/Component/Sound/SoundComponent.cpp b/sources/Component/Sound/SoundComponent.cpp new file mode 100644 index 00000000..a2dde1db --- /dev/null +++ b/sources/Component/Sound/SoundComponent.cpp @@ -0,0 +1,93 @@ +// +// Created by Tom Augier on 05/06/2021 +// + +#include +#include +#include "SoundComponent.hpp" + +namespace BBM +{ + float SoundComponent::volume = 0.75; + + SoundComponent::SoundComponent(WAL::Entity &entity, + const std::map &soundPath, + bool isLonely) + : WAL::Component(entity), + _soundIndex(IDLE), + _soundPath(soundPath), + _isLonely(isLonely) + { + for (int i = 0; i <= DEATH; i++) { + this->_isSoundLoad[static_cast(i)] = false; + } + for (auto &soundPath : soundPath) + { + this->_isSoundLoad[soundPath.first] = true; + this->_soundList[soundPath.first] = std::make_unique(soundPath.second, this->_isLonely); + } + } + + WAL::Component *SoundComponent::clone(WAL::Entity &entity) const + { + return new SoundComponent(entity, this->_soundPath); + } + + void SoundComponent::playSound() + { + if (!this->_isSoundLoad.at(this->_soundIndex)) + return; + if (!this->_soundList[this->_soundIndex].get()->isPlaying()) + this->_soundList[this->_soundIndex].get()->play(); + } + + void SoundComponent::stopSound() + { + if (!this->_isSoundLoad.at(this->_soundIndex)) + return; + if (this->_soundList[this->_soundIndex].get()->isPlaying()) + this->_soundList[this->_soundIndex].get()->stop(); + } + + void SoundComponent::pauseSound() + { + if (!this->_isSoundLoad.at(this->_soundIndex)) + return; + this->_soundList[this->_soundIndex].get()->pause(); + } + + void SoundComponent::setVolume(float &volumeUpdate) + { + if (!this->_isSoundLoad.at(this->_soundIndex)) + return; + if (volumeUpdate >= 0) { + this->volume = volumeUpdate; + this->_soundList[this->_soundIndex].get()->setVolume(this->volume); + } + } + + void SoundComponent::setPitch(float &pitch) + { + if (!this->_isSoundLoad.at(this->_soundIndex)) + return; + this->_soundList[this->_soundIndex].get()->setPitch(pitch); + } + + bool SoundComponent::isPlaying() + { + if (!this->_isSoundLoad.at(this->_soundIndex)) + return (false); + return (this->_soundList[this->_soundIndex].get()->isPlaying()); + } + + void SoundComponent::setIndex(SoundIndex index) + { + this->_soundIndex = index; + } + + SoundComponent::SoundIndex SoundComponent::getIndex() + { + return (this->_soundIndex); + } + +} // namespace WAL diff --git a/sources/Component/Sound/SoundComponent.hpp b/sources/Component/Sound/SoundComponent.hpp new file mode 100644 index 00000000..926d02cc --- /dev/null +++ b/sources/Component/Sound/SoundComponent.hpp @@ -0,0 +1,82 @@ +// +// Created by Tom Augier on 05/06/2021 +// + +#pragma once + +#include "Component/Component.hpp" +#include +#include "Audio/Sound.hpp" + +namespace BBM +{ + //! @brief A basic Sound component + class SoundComponent : public WAL::Component + { + public: + + //! @brief All sounds of the player + enum SoundIndex { + IDLE, + JUMP, + BOMB, + MOVE, + HURT, + THROW, + DEATH + }; + + //! @brief to set what sound should be played + void setIndex(SoundIndex index); + + //! @brief to know which sound is selected + SoundIndex getIndex(); + + //! @brief start sound + void playSound(); + + //! @brief stop sound + void stopSound(); + + //! @brief put Sound on hold + void pauseSound(); + + //! @brief set Sound volume + void setVolume(float &); + + //! @brief set pitch volume + void setPitch(float &); + + //! @brief is Sound playing + bool isPlaying(); + + //! @inherit + WAL::Component *clone(WAL::Entity &entity) const override; + //! @brief Create a new SoundComponent at a certain Sound + explicit SoundComponent(WAL::Entity &entity, + const std::map &, + bool isLonely = false); + //! @brief A Sound component is copy constructable + SoundComponent(const SoundComponent &) = default; + //! @brief A default destructor + ~SoundComponent() override = default; + //! @brief A Sound component is not assignable + SoundComponent &operator=(const SoundComponent &) = delete; + //! @brief Volume of the sounds + static float volume; + + private: + //! @brief Sounds of this entity + std::map> _soundList; + //! @brief map to know if sound is loaded + std::map _isSoundLoad; + //! @brief to know if cache is needed + bool _isLonely; + //! @brief All sounds path + const std::map _soundPath; + //! SoundIndex + SoundIndex _soundIndex; + + }; + +} // namespace BBM \ No newline at end of file diff --git a/sources/Component/Tag/TagComponent.cpp b/sources/Component/Tag/TagComponent.cpp deleted file mode 100644 index 14308654..00000000 --- a/sources/Component/Tag/TagComponent.cpp +++ /dev/null @@ -1,17 +0,0 @@ -// -// Created By Louis Auzuret on 07/06/21 -// - -#include "Component/Tag/TagComponent.hpp" - -namespace BBM -{ - WAL::Component *TagComponent::clone(WAL::Entity &entity) const - { - return new TagComponent(entity, tag); - } - - TagComponent::TagComponent(WAL::Entity &entity, std::string tag) - : Component(entity), tag(tag) - { } -} \ No newline at end of file diff --git a/sources/Component/Tag/TagComponent.hpp b/sources/Component/Tag/TagComponent.hpp index 082a5504..00fa27d5 100644 --- a/sources/Component/Tag/TagComponent.hpp +++ b/sources/Component/Tag/TagComponent.hpp @@ -1,34 +1,54 @@ // -// Created by Tom Augier on 2021-05-20. -// Edited by Benjamin Henry on 2021-05-20. +// Created by Zoe Roux on 6/9/21. // #pragma once -#include "Component/Component.hpp" -#include "Entity/Entity.hpp" +#include +#include namespace BBM { + template + struct StringLiteral + { + public: + char value[I]; + + //! @brief Implicitly convert an array of char to a string literal. + constexpr StringLiteral(const char (&str)[I]) // NOLINT(google-explicit-constructor) + : value() + { + std::copy_n(str, I, value); + } + //! @brief A string literal is copy constructable. + constexpr StringLiteral(const StringLiteral &) = default; + //! @brief A default destructor + constexpr ~StringLiteral() = default; + //! @brief A string literal is assignable. + constexpr StringLiteral &operator=(const StringLiteral &) = default; + }; + + template class TagComponent : public WAL::Component { - public: - //! @brief tag held by the component - std::string tag; + public: + Component *clone(WAL::Entity &entity) const override + { + return new TagComponent(entity); + } - //! @inherit - WAL::Component *clone(WAL::Entity &entity) const override; - - //! @brief Create a new tag Component with a tag - explicit TagComponent(WAL::Entity &entity, std::string tag); - - //! @brief A Tag component is copy constructable. - TagComponent(const TagComponent &) = default; - - //! @brief default destructor - ~TagComponent() override = default; - - //! @brief A Tag component can't be assigned - TagComponent &operator=(const TagComponent &) = delete; + //! @brief Create a new empty tag component. + explicit TagComponent(WAL::Entity &entity) + : WAL::Component(entity) + {} + //! @brief A default copy constructor. + TagComponent(const TagComponent &) = default; + //! @brief A default destructor + ~TagComponent() override = default; + //! @brief A tag component is not assignable. + TagComponent &operator=(const TagComponent &) = delete; }; -} \ No newline at end of file + + constexpr const char Blowable[] = "Blowable"; +} diff --git a/sources/Component/Timer/TimerComponent.cpp b/sources/Component/Timer/TimerComponent.cpp new file mode 100644 index 00000000..1695ee39 --- /dev/null +++ b/sources/Component/Timer/TimerComponent.cpp @@ -0,0 +1,26 @@ +// +// Created by Zoe Roux on 5/31/21. +// + +#include "TimerComponent.hpp" + +#include + +namespace BBM +{ + TimerComponent::TimerComponent(WAL::Entity &entity, std::chrono::nanoseconds delay) + : WAL::Component(entity), + ringIn(delay) + {} + + TimerComponent::TimerComponent(WAL::Entity &entity, std::chrono::nanoseconds delay, const WAL::Callback &callback) + : WAL::Component(entity), + ringIn(delay), + callback(callback) + {} + + WAL::Component *TimerComponent::clone(WAL::Entity &entity) const + { + return new TimerComponent(entity, this->ringIn, this->callback); + } +} \ No newline at end of file diff --git a/sources/Component/Timer/TimerComponent.hpp b/sources/Component/Timer/TimerComponent.hpp new file mode 100644 index 00000000..b0ad2454 --- /dev/null +++ b/sources/Component/Timer/TimerComponent.hpp @@ -0,0 +1,36 @@ +// +// Created by Zoe Roux on 5/31/21. +// + +#pragma once + +#include +#include +#include +#include "Models/Callback.hpp" + +namespace BBM +{ + //! @brief + class TimerComponent : public WAL::Component + { + public: + //! @brief The callback to call when the timer ring. + WAL::Callback callback; + //! @brief The ring delay of this timer component. + std::chrono::nanoseconds ringIn; + + Component *clone(WAL::Entity &entity) const override; + + //! @brief A default constructor + TimerComponent(WAL::Entity &entity, std::chrono::nanoseconds delay); + //! @brief Create a timer with a callback. + TimerComponent(WAL::Entity &entity, std::chrono::nanoseconds delay, const WAL::Callback &callback); + //! @brief A timer component is copy constructable + TimerComponent(const TimerComponent &) = default; + //! @brief A default destructor + ~TimerComponent() override = default; + //! @brief A component is not assignable. + TimerComponent &operator=(const TimerComponent &) = delete; + }; +} diff --git a/sources/Map/Map.cpp b/sources/Map/Map.cpp index 8d14e585..b5ca0268 100644 --- a/sources/Map/Map.cpp +++ b/sources/Map/Map.cpp @@ -3,34 +3,36 @@ // Edited by Benjamin Henry on 5/26/21. // -#include "Component/Tag/TagComponent.hpp" -#include -#include +#include "Component/Collision/CollisionComponent.hpp" +#include "System/Collision/CollisionSystem.hpp" #include "Map.hpp" +#include namespace RAY3D = RAY::Drawables::Drawables3D; namespace BBM { - void MapGenerator::wallCollide(WAL::Entity &entity, const WAL::Entity &wall) + void MapGenerator::wallCollide(WAL::Entity &entity, + const WAL::Entity &wall, + CollisionComponent::CollidedAxis collidedAxis) { auto *mov = entity.tryGetComponent(); + if (!mov) return; - auto &pos = entity.getComponent(); - const auto &wallPos = wall.getComponent(); - auto diff = pos.position + mov->getVelocity() - wallPos.position; -// mov->_velocity = Vector3f(); - if (diff.x <= 0 && mov->_velocity.x < 0) + if (collidedAxis & CollisionComponent::CollidedAxis::X) mov->_velocity.x = 0; - if (diff.x >= 0 && mov->_velocity.x > 0) - mov->_velocity.x = 0; - if (diff.z <= 0 && mov->_velocity.z < 0) - mov->_velocity.z = 0; - if (diff.z >= 0 && mov->_velocity.z > 0) + if (collidedAxis & CollisionComponent::CollidedAxis::Y) + mov->_velocity.y = 0; + if (collidedAxis & CollisionComponent::CollidedAxis::Z) mov->_velocity.z = 0; } + void MapGenerator::wallDestroyed(WAL::Entity &entity) + { + entity.scheduleDeletion(); + } + const std::string MapGenerator::assetsPath = "./assets/"; const std::string MapGenerator::wallAssetsPath = MapGenerator::assetsPath + "map/"; const std::string MapGenerator::imageExtension = ".png"; @@ -54,9 +56,12 @@ namespace BBM if (!(i % 2) && !(j % 2)) { scene->addEntity("Unbreakable Wall") .addComponent(i, 0, j) - .addComponent(WAL::Callback(), &MapGenerator::wallCollide, .75) - .addComponent(unbreakableObj, std::make_pair(MAP_DIFFUSE, unbreakablePng)) - .addComponent("UNBREAKABLE");; + .addComponent>() + .addComponent( + WAL::Callback(), + &MapGenerator::wallCollide, 0.25, .75) + .addComponent(unbreakableObj, + std::make_pair(MAP_DIFFUSE, unbreakablePng)); } } } @@ -69,25 +74,36 @@ namespace BBM scene->addEntity("Bottom Wall") .addComponent(Vector3f((width + 1) / 2, 0, -1)) - .addComponent(WAL::Callback(), &MapGenerator::wallCollide, .75) + .addComponent>() + .addComponent( + WAL::Callback(), + &MapGenerator::wallCollide, Vector3f(-(width + 1) / 2 , 0.25, 0.25), Vector3f(width + 1, 2, 0.75)) .addComponent(unbreakableObj, std::make_pair(MAP_DIFFUSE, unbreakablePnj), RAY::Vector3(width + 3, 1, 1)); scene->addEntity("Upper Wall") .addComponent(Vector3f((width + 1) / 2, 0, height + 1)) - .addComponent(WAL::Callback(), &MapGenerator::wallCollide, .75) + .addComponent>() + .addComponent( + WAL::Callback(), + &MapGenerator::wallCollide, Vector3f(-(width + 1) / 2 , 0.25, 0.25), Vector3f(width + 1, 2, 0.75)) .addComponent(unbreakableObj, std::make_pair(MAP_DIFFUSE, unbreakablePnj), RAY::Vector3(width + 3, 1, 1)); scene->addEntity("Left Wall") .addComponent(Vector3f(width + 1, 0, height / 2)) - .addComponent(WAL::Callback(), &MapGenerator::wallCollide, .75) + .addComponent>() + .addComponent( + WAL::Callback(), + &MapGenerator::wallCollide, Vector3f(0.25, 0.25, -(height + 1) / 2 ), Vector3f(0.75, 2, height + 1)) .addComponent(unbreakableObj, std::make_pair(MAP_DIFFUSE, unbreakablePnj), RAY::Vector3(1, 1, height + 1)); scene->addEntity("Right Wall") .addComponent(Vector3f(-1, 0, height / 2)) - .addComponent(WAL::Callback(), &MapGenerator::wallCollide, .75) + .addComponent( + WAL::Callback(), + &MapGenerator::wallCollide, Vector3f(0.25, 0.25, -(height + 1) / 2 ), Vector3f(0.75, 2, height + 1)) .addComponent(unbreakableObj, std::make_pair(MAP_DIFFUSE, unbreakablePnj), RAY::Vector3(1, 1, height + 1)); @@ -104,8 +120,7 @@ namespace BBM scene->addEntity("Unbreakable Wall") .addComponent(Vector3f(i, -1, j)) .addComponent(floorObj, - std::make_pair(MAP_DIFFUSE, floorPng)) - .addComponent("UNBREAKABLE");; + std::make_pair(MAP_DIFFUSE, floorPng)); } } } @@ -118,7 +133,6 @@ namespace BBM {HOLE, &createHole}, {FLOOR, &createFloor}, {BUMPER, &createBumper}, - {STAIRS, &createStairs}, {UPPERFLOOR, &createUpperFloor}, }; @@ -137,10 +151,12 @@ namespace BBM scene->addEntity("Breakable Block") .addComponent(coords) - .addComponent(1) - .addComponent(WAL::Callback(), &MapGenerator::wallCollide, .75) - .addComponent(breakableObj, std::make_pair(MAP_DIFFUSE, breakablePng)) - .addComponent("BREAKABLE"); + .addComponent>() + .addComponent(1, &MapGenerator::wallDestroyed) + .addComponent( + WAL::Callback(), + &MapGenerator::wallCollide, 0.25, .75) + .addComponent(breakableObj, std::make_pair(MAP_DIFFUSE, breakablePng)); } void MapGenerator::createFloor(Vector3f coords, std::shared_ptr scene) @@ -172,10 +188,12 @@ namespace BBM scene->addEntity("Unbreakable Block") .addComponent(coords) - .addComponent(WAL::Callback(), &MapGenerator::wallCollide, .75) + .addComponent>() + .addComponent( + WAL::Callback(), + &MapGenerator::wallCollide, 0.25, .75) .addComponent(UnbreakableObj, - std::make_pair(MAP_DIFFUSE, UnbreakablePng)) - .addComponent("UNBREAKABLE");; + std::make_pair(MAP_DIFFUSE, UnbreakablePng)); } void MapGenerator::createHole(Vector3f coords, std::shared_ptr scene) @@ -187,13 +205,13 @@ namespace BBM WAL::Entity &holeEntity = scene->addEntity("Hole Block"); - holeEntity.addComponent(Vector3f(coords.x, coords.y - 1, coords.z)) - .addComponent("HOLE");; + holeEntity.addComponent(Vector3f(coords.x, coords.y - 1, coords.z)); if (coords.y == 0) holeEntity.addComponent(holeObj, std::make_pair(MAP_DIFFUSE, holePng)); else - holeEntity.addComponent(secondFloorObj, std::make_pair(MAP_DIFFUSE, secondFloorPng)); + holeEntity.addComponent(secondFloorObj, + std::make_pair(MAP_DIFFUSE, secondFloorPng)); /*.addComponent([](WAL::Entity &other, const WAL::Entity &entity) { if (other.hasComponent()) { auto &health = other.getComponent(); @@ -209,8 +227,7 @@ namespace BBM scene->addEntity("Bumper Block") .addComponent(Vector3f(coords.x, coords.y, coords.z)) - .addComponent(bumperObj, std::make_pair(MAP_DIFFUSE, bumperPng)) - .addComponent("BUMPER");; + .addComponent(bumperObj, std::make_pair(MAP_DIFFUSE, bumperPng)); /* .addComponent([](const WAL::Entity &entity, WAL::Entity &other) { if (other.hasComponent()) { auto &movable = other.getComponent(); @@ -219,18 +236,6 @@ namespace BBM }); */ } - void MapGenerator::createStairs(Vector3f coords, std::shared_ptr scene) - { - static const std::string stairsObj = stairsPath + objExtension; - static const std::string stairsPng = stairsPath + imageExtension; - - scene->addEntity("Stairs Block") - .addComponent(coords) - //.addComponent(1) - .addComponent(stairsObj, std::make_pair(MAP_DIFFUSE, stairsPng)) - .addComponent("STAIRS");; - } - bool MapGenerator::isCloseToBlockType(std::map, BlockType> map, int x, int y, int z, BlockType blockType) { @@ -262,10 +267,10 @@ namespace BBM map[std::make_tuple(i, 1, 0)] = map[std::make_tuple(i, 0, 0)]; map[std::make_tuple(i, 0, 0)] = UPPERFLOOR; } - map[std::make_tuple(0, 0, height - 1)] = STAIRS; - map[std::make_tuple(0, 0, 1)] = STAIRS; - map[std::make_tuple(width, 0, height - 1)] = STAIRS; - map[std::make_tuple(width, 0, 1)] = STAIRS; + map[std::make_tuple(0, -1, height - 1)] = BUMPER; + map[std::make_tuple(0, -1, 1)] = BUMPER; + map[std::make_tuple(width, -1, height - 1)] = BUMPER; + map[std::make_tuple(width, -1, 1)] = BUMPER; map[std::make_tuple(width / 2, -1, height - 1)] = BUMPER; map[std::make_tuple(width / 2, -1, 1)] = BUMPER; } @@ -278,10 +283,10 @@ namespace BBM map[std::make_tuple(i, 0, j)] = UPPERFLOOR; } } - map[std::make_tuple(width / 2 - width / 8, 0, height / 2 + height / 4 + 1)] = STAIRS; - map[std::make_tuple(width / 2 + width / 8, 0, height / 2 - height / 4 - 1)] = STAIRS; - map[std::make_tuple(width / 2 - width / 4 - 1, 0, height / 2 - height / 8)] = STAIRS; - map[std::make_tuple(width / 2 + width / 4 + 1, 0, height / 2 + height / 8)] = STAIRS; + map[std::make_tuple(width / 2 - width / 8, -1, height / 2 + height / 4 + 1)] = BUMPER; + map[std::make_tuple(width / 2 + width / 8, -1, height / 2 - height / 4 - 1)] = BUMPER; + map[std::make_tuple(width / 2 - width / 4 - 1, -1, height / 2 - height / 8)] = BUMPER; + map[std::make_tuple(width / 2 + width / 4 + 1, -1, height / 2 + height / 8)] = BUMPER; } return map; } @@ -300,8 +305,6 @@ namespace BBM { for (int i = 0; i < width + 1; i++) for (int j = 0; j < height; j++) { - if (map[std::make_tuple(i, 0, j)] == BREAKABLE && isCloseToBlockType(map, i, 0, j, STAIRS)) - map[std::make_tuple(i, 0, j)] = NOTHING; if (map[std::make_tuple(i, 0, j)] == BREAKABLE && map[std::make_tuple(i, -1, j)] == BUMPER) map[std::make_tuple(i, 0, j)] = NOTHING; } @@ -340,7 +343,7 @@ namespace BBM return (map); } - void MapGenerator::loadMap(int width, int height, MapBlock map, std::shared_ptr scene) + void MapGenerator::loadMap(int width, int height, MapBlock map, const std::shared_ptr &scene) { generateWall(width, height, scene); generateFloor(map, width, height, scene); diff --git a/sources/Map/Map.hpp b/sources/Map/Map.hpp index d0191ddc..71277055 100644 --- a/sources/Map/Map.hpp +++ b/sources/Map/Map.hpp @@ -27,149 +27,148 @@ namespace BBM class MapGenerator { - public: - //! @brief Enum of the block available. - enum BlockType { - NOTHING, - BREAKABLE, - HOLE, - UPPERFLOOR, - FLOOR, - BUMPER, - STAIRS, - SPAWNER, - UNBREAKABLE - }; - using MapElem = std::function scene)>; - using MapBlock = std::map, BlockType>; + public: + //! @brief Enum of the block available. + enum BlockType + { + NOTHING, + BREAKABLE, + HOLE, + UPPERFLOOR, + FLOOR, + BUMPER, + SPAWNER, + UNBREAKABLE + }; - static void wallCollide(WAL::Entity &entity, const WAL::Entity &wall); + using MapElem = std::function scene)>; + using MapBlock = std::map, BlockType>; + static void wallCollide(WAL::Entity &entity, + const WAL::Entity &wall, + CollisionComponent::CollidedAxis collidedAxis); + static void wallDestroyed(WAL::Entity &entity); - //! @param width Width of the map - //! @param height Height of the map - //! @brief Generate map of block to be loaded - static MapBlock createMap(int width, int height); + //! @param width Width of the map + //! @param height Height of the map + //! @brief Generate map of block to be loaded + static MapBlock createMap(int width, int height); - //! @param width Width of the map - //! @param height Height of the map - //! @param map Map to load with block declared inside - //! @param scene Scene where the map is instanced - //! @brief Generate the map - static void loadMap(int width, int height, MapBlock map, std::shared_ptr scene); - - private: + //! @param width Width of the map + //! @param height Height of the map + //! @param map Map to load with block declared inside + //! @param scene Scene where the map is instanced + //! @brief Generate the map + static void loadMap(int width, int height, MapBlock map, const std::shared_ptr &scene); + private: - //! @brief Generate random block type - static BlockType getRandomBlockType(); + //! @brief Generate random block type + static BlockType getRandomBlockType(); - //! @param map ASCII map - //! @param x x index on the block - //! @param z z index on the block - //! @param blockType blockType to compare with position - static bool isCloseToBlockType(std::map, BlockType> map, int x, int y, int z, BlockType blockType); + //! @param map ASCII map + //! @param x x index on the block + //! @param z z index on the block + //! @param blockType blockType to compare with position + static bool isCloseToBlockType(std::map, BlockType> map, + int x, int y, int z, + BlockType blockType); - //! @param width Width of the map - //! @param height Height of the map - //! @param scene Scene where the map is instanced - //! @brief Generate the unbreakable block of the map - static void generateUnbreakableBlock(int width, int height, std::shared_ptr scene); + //! @param width Width of the map + //! @param height Height of the map + //! @param scene Scene where the map is instanced + //! @brief Generate the unbreakable block of the map + static void generateUnbreakableBlock(int width, int height, std::shared_ptr scene); - //! @param width Width of the map - //! @param height Height of the map - //! @param scene Scene where the map is instanced - //! @brief Generate the wall of the map - static void generateWall(int width, int height, std::shared_ptr scene); + //! @param width Width of the map + //! @param height Height of the map + //! @param scene Scene where the map is instanced + //! @brief Generate the wall of the map + static void generateWall(int width, int height, std::shared_ptr scene); - //! @param width Width of the map - //! @param height Height of the map - //! @param scene Scene where the map is instanced - //! @brief Generate the floor of the map - static void generateFloor(MapBlock map, int width, int height, std::shared_ptr scene); + //! @param width Width of the map + //! @param height Height of the map + //! @param scene Scene where the map is instanced + //! @brief Generate the floor of the map + static void generateFloor(MapBlock map, int width, int height, std::shared_ptr scene); - //! @param coords coords of the element - //! @param scene Scene where the map is instanced - //! @brief Create element of the map - static void createElement(Vector3f coords, std::shared_ptr scene, BlockType blockType); + //! @param coords coords of the element + //! @param scene Scene where the map is instanced + //! @brief Create element of the map + static void createElement(Vector3f coords, std::shared_ptr scene, BlockType blockType); - //! @param coords coords of the element - //! @param scene Scene where the map is instanced - //! @brief Create breakable of the map - static void createBreakable(Vector3f coords, std::shared_ptr scene); + //! @param coords coords of the element + //! @param scene Scene where the map is instanced + //! @brief Create breakable of the map + static void createBreakable(Vector3f coords, std::shared_ptr scene); - //! @param coords coords of the element - //! @param scene Scene where the map is instanced - //! @brief Create unbreakable of the map - static void createUnbreakable(Vector3f coords, std::shared_ptr scene); + //! @param coords coords of the element + //! @param scene Scene where the map is instanced + //! @brief Create unbreakable of the map + static void createUnbreakable(Vector3f coords, std::shared_ptr scene); - //! @param coords coords of the element - //! @param scene Scene where the map is instanced - //! @brief Create hole of the map - static void createHole(Vector3f coords, std::shared_ptr scene); + //! @param coords coords of the element + //! @param scene Scene where the map is instanced + //! @brief Create hole of the map + static void createHole(Vector3f coords, std::shared_ptr scene); - //! @param coords coords of the element - //! @param scene Scene where the map is instanced - //! @brief Create bumper of the map - static void createBumper(Vector3f coords, std::shared_ptr scene); + //! @param coords coords of the element + //! @param scene Scene where the map is instanced + //! @brief Create bumper of the map + static void createBumper(Vector3f coords, std::shared_ptr scene); - //! @param coords coords of the element - //! @param scene Scene where the map is instanced - //! @brief Create floor of the map - static void createFloor(Vector3f coords, std::shared_ptr scene); + //! @param coords coords of the element + //! @param scene Scene where the map is instanced + //! @brief Create floor of the map + static void createFloor(Vector3f coords, std::shared_ptr scene); - //! @param coords coords of the element - //! @param scene Scene where the map is instanced - //! @brief Create upper floor of the map - static void createUpperFloor(Vector3f coords, std::shared_ptr scene); + //! @param coords coords of the element + //! @param scene Scene where the map is instanced + //! @brief Create upper floor of the map + static void createUpperFloor(Vector3f coords, std::shared_ptr scene); + + //! @param map Map to load with block declared inside + //! @param width Width of the map + //! @param height Height of the map + //! @brief Generate map of block to be loaded + static MapBlock createSpawner(MapBlock map, int width, int height); + + //! @param map Map to load with block declared inside + //! @param width Width of the map + //! @param height Height of the map + //! @brief Generate height for the map + static MapBlock createHeight(MapBlock map, int width, int height); + + //! @param map Map to load with block declared inside + //! @param width Width of the map + //! @param height Height of the map + //! @brief Clean breakable on stairs, bumpers, etc.. + static MapBlock cleanBreakable(MapBlock map, int width, int height); - //! @param coords coords of the element - //! @param scene Scene where the map is instanced - //! @brief Create stair of the map - static void createStairs(Vector3f coords, std::shared_ptr scene); - - //! @param map Map to load with block declared inside - //! @param width Width of the map - //! @param height Height of the map - //! @brief Generate map of block to be loaded - static MapBlock createSpawner(MapBlock map, int width, int height); + static const std::string assetsPath; - //! @param map Map to load with block declared inside - //! @param width Width of the map - //! @param height Height of the map - //! @brief Generate height for the map - static MapBlock createHeight(MapBlock map, int width, int height); + static const std::string wallAssetsPath; - //! @param map Map to load with block declared inside - //! @param width Width of the map - //! @param height Height of the map - //! @brief Clean breakable on stairs, bumpers, etc.. - static MapBlock cleanBreakable(MapBlock map, int width, int height); + static const std::string imageExtension; - - static const std::string assetsPath; + static const std::string objExtension; - static const std::string wallAssetsPath; + static const std::string unbreakableWallPath; - static const std::string imageExtension; + static const std::string breakableWallPath; - static const std::string objExtension; + static const std::string floorPath; - static const std::string unbreakableWallPath; + static const std::string stairsPath; - static const std::string breakableWallPath; + static const std::string bumperPath; - static const std::string floorPath; + static const std::string secondFloorPath; - static const std::string stairsPath; + static const std::string holePath; - static const std::string bumperPath; - - static const std::string secondFloorPath; - - static const std::string holePath; - - static const std::string secondFloorHolePath; + static const std::string secondFloorHolePath; }; + } // namespace BBM \ No newline at end of file diff --git a/sources/Models/Vector2.hpp b/sources/Models/Vector2.hpp index 629a11b8..b3dacf2b 100644 --- a/sources/Models/Vector2.hpp +++ b/sources/Models/Vector2.hpp @@ -9,6 +9,8 @@ #include #include "Vector/Vector2.hpp" +#define PI_NUMBER 3.14159265359 + namespace BBM { //! @brief A Vector2 data type. (templated to allow any kind of vector2) @@ -120,6 +122,13 @@ namespace BBM return std::sqrt(std::pow(this->x - o.x, 2) + std::pow(this->y - o.y, 2)); } + double angle(const Vector2 &o) const + { + float dot = this->x * o.x + this->y * o.y; + float det = this->x * o.y - this->y * o.x; + return (std::atan2(det, dot) * (180.0f / PI_NUMBER)); + } + double magnitude() const { return std::sqrt(std::pow(this->x, 2) + std::pow(this->y, 2)); diff --git a/sources/Models/Vector3.hpp b/sources/Models/Vector3.hpp index d4ba7337..a2266e07 100644 --- a/sources/Models/Vector3.hpp +++ b/sources/Models/Vector3.hpp @@ -168,6 +168,11 @@ namespace BBM return (point * this) / std::pow(this->magnitude(), 2) * this; } + Vector3 round() const requires(std::is_floating_point_v) + { + return Vector3(std::round(this->x), std::round(this->y), std::round(this->z)); + } + operator RAY::Vector3() const requires(std::is_same_v) { return RAY::Vector3(this->x, this->y, this->z); diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index 9765cf90..9fb1fbd7 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -9,10 +9,13 @@ #include #include #include -#include -#include +#include "System/Keyboard/KeyboardSystem.hpp" +#include "System/Controllable/ControllableSystem.hpp" +#include "Component/Movable/MovableComponent.hpp" +#include "Component/Controllable/ControllableComponent.hpp" +#include "Component/Keyboard/KeyboardComponent.hpp" +#include "System/Gamepad/GamepadSystem.hpp" #include -#include #include #include #include @@ -23,10 +26,21 @@ #include "Runner.hpp" #include "Models/GameState.hpp" #include +#include +#include +#include +#include +#include +#include +#include #include "Component/Animation/AnimationsComponent.hpp" #include "System/Animation/AnimationsSystem.hpp" #include "Map/Map.hpp" #include "System/IAControllable/IAControllableSystem.hpp" +#include "Component/Music/MusicComponent.hpp" +#include "Component/Sound/SoundComponent.hpp" +#include "System/Sound/PlayerSoundManagerSystem.hpp" +#include "System/Music/MusicSystem.hpp" namespace RAY3D = RAY::Drawables::Drawables3D; @@ -44,12 +58,18 @@ namespace BBM void addSystems(WAL::Wal &wal) { - wal.addSystem() + wal.addSystem() + .addSystem() .addSystem() .addSystem() .addSystem() + .addSystem() + .addSystem() + .addSystem() .addSystem() - .addSystem(); + .addSystem() + .addSystem() + .addSystem(); } void enableRaylib(WAL::Wal &wal) @@ -57,41 +77,48 @@ namespace BBM RAY::TraceLog::setLevel(LOG_WARNING); RAY::Window &window = RAY::Window::getInstance(600, 400, "Bomberman", FLAG_WINDOW_RESIZABLE); wal.addSystem() + .addSystem() .addSystem(window); } std::shared_ptr loadGameScene() { auto scene = std::make_shared(); + std::map soundPath ={ + {SoundComponent::JUMP, "assets/sounds/jump.wav"}, + {SoundComponent::MOVE, "assets/sounds/move.ogg"}, + {SoundComponent::BOMB, "assets/sounds/bomb_drop.ogg"}, + //{SoundComponent::DEATH, "assets/sounds/death.ogg"} + }; scene->addEntity("player") .addComponent() .addComponent("assets/player/player.iqm", std::make_pair(MAP_DIFFUSE, "assets/player/blue.png")) .addComponent() + .addComponent() .addComponent() - .addComponent(RAY::ModelAnimations("assets/player/player.iqm"), 1) - .addComponent(2) + .addComponent>() + //.addComponent(0) + .addComponent(RAY::ModelAnimations("assets/player/player.iqm"), 3) + .addComponent(BBM::Vector3f{0.25, 0, 0.25}, BBM::Vector3f{.75, 2, .75}) .addComponent() - .addComponent("./ai_scripts/john.lua"); - scene->addEntity("cube") - .addComponent(-5, 0, -5) - .addComponent(Vector3f(-5, 0, -5), Vector3f(3, 3, 3), RED) - .addComponent() - .addComponent() - .addComponent([](WAL::Entity &, const WAL::Entity &){}, - [](WAL::Entity &actual, const WAL::Entity &) { - }, 3); - + .addComponent(soundPath) + .addComponent() + .addComponent(1, [](WAL::Entity &entity) { + auto &animation = entity.getComponent(); + animation.setAnimIndex(5); + }); scene->addEntity("camera") .addComponent(8, 20, 7) .addComponent(Vector3f(8, 0, 8)); -// scene->addEntity("cube") -// .addComponent(5, 0, 5) -// .addComponent(Vector3f(-5, 0, -5), Vector3f(3, 3, 3), RED) -// .addComponent() -// .addComponent() -// .addComponent(WAL::Callback(), &MapGenerator::wallCollide, 3); + /*scene->addEntity("cube") + .addComponent(-5, 0, -5) + .addComponent(Vector3f(0, 0, 0), Vector3f(3, 3, 3), RED) + .addComponent() + .addComponent() + .addComponent(WAL::Callback(), &MapGenerator::wallCollide, -1, 3);*/ std::srand(std::time(nullptr)); MapGenerator::loadMap(16, 16, MapGenerator::createMap(16, 16), scene); + return scene; } diff --git a/sources/System/Animator/AnimatorSystem.cpp b/sources/System/Animator/AnimatorSystem.cpp new file mode 100644 index 00000000..f03aeb9b --- /dev/null +++ b/sources/System/Animator/AnimatorSystem.cpp @@ -0,0 +1,37 @@ +// +// Created by hbenjamin on 03/06/2021. +// + +#include +#include +#include +#include +#include +#include +#include "AnimatorSystem.hpp" +#include "Component/Renderer/Drawable3DComponent.hpp" + +using Keyboard = RAY::Controller::Keyboard; +namespace RAY3D = RAY::Drawables::Drawables3D; +using Key = RAY::Controller::Keyboard::Key; + +namespace BBM +{ + AnimatorSystem::AnimatorSystem(WAL::Wal &wal) + : System(wal) + {} + + void AnimatorSystem::onFixedUpdate(WAL::ViewEntity &entity) + { + const auto &controllable = entity.get(); + auto drawable = entity.get().drawable.get(); + auto &animation = entity.get(); + auto anim = dynamic_cast(drawable); + if (anim && controllable.move != Vector2f(0, 0)) { + anim->setRotationAngle(controllable.move.angle(Vector2f(-1, 0))); + animation.setAnimIndex(0); + return; + } + animation.setAnimIndex(1); + } +} \ No newline at end of file diff --git a/sources/System/Animator/AnimatorSystem.hpp b/sources/System/Animator/AnimatorSystem.hpp new file mode 100644 index 00000000..fcddfc13 --- /dev/null +++ b/sources/System/Animator/AnimatorSystem.hpp @@ -0,0 +1,29 @@ +// +// Created by hbenjamin on 03/06/2021. +// + +#pragma once + +#include +#include "Component/Animation/AnimationsComponent.hpp" +#include "System/System.hpp" + +namespace BBM +{ + //! @brief A system to handle Animator entities. + class AnimatorSystem : public WAL::System + { + public: + //! @inherit + void onFixedUpdate(WAL::ViewEntity &entity) override; + + //! @brief A default constructor + AnimatorSystem(WAL::Wal &wal); + //! @brief An Animator system is copy constructable + AnimatorSystem(const AnimatorSystem &) = default; + //! @brief A default destructor + ~AnimatorSystem() override = default; + //! @brief An Animator system is assignable. + AnimatorSystem &operator=(const AnimatorSystem &) = default; + }; +} \ No newline at end of file diff --git a/sources/System/BombHolder/BombHolderSystem.cpp b/sources/System/BombHolder/BombHolderSystem.cpp new file mode 100644 index 00000000..0ccd396b --- /dev/null +++ b/sources/System/BombHolder/BombHolderSystem.cpp @@ -0,0 +1,81 @@ +// +// Created by Zoe Roux on 5/31/21. +// + +#include "Component/Timer/TimerComponent.hpp" +#include "System/Event/EventSystem.hpp" +#include "Component/Renderer/Drawable3DComponent.hpp" +#include "BombHolderSystem.hpp" +#include "Component/Health/HealthComponent.hpp" +#include +#include +#include "Component/Collision/CollisionComponent.hpp" +#include "Component/Tag/TagComponent.hpp" + +using namespace std::chrono_literals; +namespace RAY3D = RAY::Drawables::Drawables3D; + +namespace BBM +{ + std::chrono::nanoseconds BombHolderSystem::explosionTimer = 3s; + + BombHolderSystem::BombHolderSystem(WAL::Wal &wal) + : System(wal) + {} + + void BombHolderSystem::_dispatchExplosion(Vector3f position, WAL::Wal &wal, int count) + { + if (count <= 0) + return; + wal.getSystem().dispatchEvent([position, count](WAL::Wal &wal) { + for (auto &[entity, pos, _] : wal.scene->view>()) { + if (pos.position.round() == position) { + if (auto *health = entity.tryGetComponent()) + health->takeDmg(1); + return; + } + } + _dispatchExplosion(position + Vector3f(1, 0, 0), wal, count - 1); + _dispatchExplosion(position + Vector3f(-1, 0, 0), wal, count - 1); + _dispatchExplosion(position + Vector3f(0, 0, 1), wal, count - 1); + _dispatchExplosion(position + Vector3f(0, 0, -1), wal, count - 1); + }); + } + + void BombHolderSystem::_bombExplosion(WAL::Entity &bomb, WAL::Wal &wal) + { + bomb.scheduleDeletion(); + auto position = bomb.getComponent().position.round(); + _dispatchExplosion(position, wal, 3); + } + + void BombHolderSystem::_spawnBomb(Vector3f position) + { + this->_wal.scene->scheduleNewEntity("Bomb") + .addComponent(position.round()) + .addComponent(BombHolderSystem::explosionTimer, &BombHolderSystem::_bombExplosion) +// .addComponent(WAL::Callback(), +// &MapGenerator::wallCollide, 0.25, .75) + .addComponent("assets/bombs/bomb.obj", + std::make_pair(MAP_DIFFUSE, "assets/bombs/bomb_normal.png")); + } + + void BombHolderSystem::onUpdate(WAL::ViewEntity &entity, std::chrono::nanoseconds dtime) + { + auto &holder = entity.get(); + auto &position = entity.get(); + auto &controllable = entity.get(); + + if (controllable.bomb && holder.bombCount > 0) { + holder.bombCount--; + this->_spawnBomb(position.position); + } + if (holder.bombCount < holder.maxBombCount) { + holder.nextBombRefill -= dtime; + if (holder.nextBombRefill <= 0ns) { + holder.nextBombRefill = holder.refillRate; + holder.bombCount++; + } + } + } +} \ No newline at end of file diff --git a/sources/System/BombHolder/BombHolderSystem.hpp b/sources/System/BombHolder/BombHolderSystem.hpp new file mode 100644 index 00000000..105f9139 --- /dev/null +++ b/sources/System/BombHolder/BombHolderSystem.hpp @@ -0,0 +1,46 @@ +// +// Created by Zoe Roux on 5/31/21. +// + +#pragma once + +#include +#include +#include "Models/Vector3.hpp" +#include "Component/Position/PositionComponent.hpp" +#include "Component/BombHolder/BombHolderComponent.hpp" +#include "Component/Controllable/ControllableComponent.hpp" + +namespace BBM +{ + //! @brief The system that allow one to place bombs. + class BombHolderSystem : public WAL::System + { + private: + //! @brief Spawn a bomb at the specified position. + void _spawnBomb(Vector3f position); + + //! @brief Spawn a bomb at the specified position. + static void _dispatchExplosion(Vector3f position, WAL::Wal &, int count); + + //! @brief The method triggered when the bomb explode. + static void _bombExplosion(WAL::Entity &bomb, WAL::Wal &); + public: + //! @brief The explosion time of new bombs. + static std::chrono::nanoseconds explosionTimer; + //! @brief The radius of the explosion. + static float explosionRadius; + + //! @inherit + void onUpdate(WAL::ViewEntity &entity, std::chrono::nanoseconds dtime) override; + + //! @brief A default constructor + explicit BombHolderSystem(WAL::Wal &wal); + //! @brief A bomb holder system is copy constructable + BombHolderSystem(const BombHolderSystem &) = default; + //! @brief A default destructor + ~BombHolderSystem() override = default; + //! @brief A bomb holder system is not assignable. + BombHolderSystem &operator=(const BombHolderSystem &) = delete; + }; +} diff --git a/sources/System/Collision/CollisionSystem.cpp b/sources/System/Collision/CollisionSystem.cpp index 6a3e36cd..db68e3c0 100644 --- a/sources/System/Collision/CollisionSystem.cpp +++ b/sources/System/Collision/CollisionSystem.cpp @@ -14,7 +14,7 @@ namespace BBM : System(wal) { } - bool CollisionSystem::collide(Vector3f minA, Vector3f maxA, Vector3f minB, Vector3f maxB) + bool CollisionSystem::boxesCollide(Vector3f minA, Vector3f maxA, Vector3f minB, Vector3f maxB) { bool overlapX = (minA.x <= maxB.x && maxA.x >= minB.x) || (minB.x <= maxA.x && maxB.x >= minA.x); bool overlapY = (minA.y <= maxB.y && maxA.y >= minB.y) || (minB.y <= maxA.y && maxB.y >= minA.y); @@ -26,20 +26,51 @@ namespace BBM void CollisionSystem::onFixedUpdate(WAL::ViewEntity &entity) { auto &posA = entity.get(); - auto &col = entity.get(); - Vector3f position = posA.position; - if (auto *movable = entity->tryGetComponent()) - position += movable->getVelocity(); - Vector3f minA = Vector3f::min(position, position + col.bound); - Vector3f maxA = Vector3f::max(position, position + col.bound); + auto &colA = entity.get(); + Vector3f pointA = posA.position + colA.positionOffset; + Vector3f pointAx = pointA; + Vector3f pointAy = pointA; + Vector3f pointAz = pointA; + + if (auto *movable = entity->tryGetComponent()) { + auto vel = movable->getVelocity(); + pointAx.x += vel.x; + pointAy.y += vel.y; + pointAz.z += vel.z; + } + + Vector3f minAx = Vector3f::min(pointAx, pointAx + colA.bound); + Vector3f maxAx = Vector3f::max(pointAx, pointAx + colA.bound); + + Vector3f minAy = Vector3f::min(pointAy, pointAy + colA.bound); + Vector3f maxAy = Vector3f::max(pointAy, pointAy + colA.bound); + + Vector3f minAz = Vector3f::min(pointAz, pointAz + colA.bound); + Vector3f maxAz = Vector3f::max(pointAz, pointAz + colA.bound); + for (auto &[other, posB, colB] : this->getView()) { if (other.getUid() == entity->getUid()) continue; - Vector3f minB = Vector3f::min(posB.position, posB.position + colB.bound); - Vector3f maxB = Vector3f::max(posB.position, posB.position + colB.bound); - if (collide(minA, maxA, minB, maxB)) { - col.onCollide(entity, other); - colB.onCollided(entity, other); + + auto pointB = posB.position + colB.positionOffset; + int collidedAxis = 0; + + // TODO if B is also a movable we don't check with it's changing position + Vector3f minB = Vector3f::min(pointB, pointB + colB.bound); + Vector3f maxB = Vector3f::max(pointB, pointB + colB.bound); + + if (boxesCollide(minAx, maxAx, minB, maxB)) { + collidedAxis += CollisionComponent::CollidedAxis::X; + } + if (boxesCollide(minAy, maxAy, minB, maxB)) { + collidedAxis += CollisionComponent::CollidedAxis::Y; + } + if (boxesCollide(minAz, maxAz, minB, maxB)) { + collidedAxis += CollisionComponent::CollidedAxis::Z; + } + if (collidedAxis) { + colA.onCollide(entity, other, static_cast(collidedAxis)); + colB.onCollided(entity, other, static_cast(collidedAxis)); } } } diff --git a/sources/System/Collision/CollisionSystem.hpp b/sources/System/Collision/CollisionSystem.hpp index 2c0f5491..e1e75ede 100644 --- a/sources/System/Collision/CollisionSystem.hpp +++ b/sources/System/Collision/CollisionSystem.hpp @@ -31,6 +31,6 @@ namespace BBM CollisionSystem &operator=(const CollisionSystem &) = delete; //! @brief check AABB collision - static bool collide(Vector3f minA, Vector3f maxA, Vector3f minB, Vector3f maxB); + static bool boxesCollide(Vector3f minA, Vector3f maxA, Vector3f minB, Vector3f maxB); }; } \ No newline at end of file diff --git a/sources/System/Event/EventSystem.cpp b/sources/System/Event/EventSystem.cpp new file mode 100644 index 00000000..da683dec --- /dev/null +++ b/sources/System/Event/EventSystem.cpp @@ -0,0 +1,36 @@ +// +// Created by Zoe Roux on 6/1/21. +// + +#include "EventSystem.hpp" + +namespace BBM +{ + EventSystem::EventSystem(WAL::Wal &wal) + : System(wal) + {} + + void EventSystem::dispatchEvent(const std::function &event) + { + this->_events.emplace_back(event); + } + + void EventSystem::dispatchEvent(const std::function &event) + { + this->_globalEvents.emplace_back(event); + } + + void EventSystem::onUpdate(WAL::ViewEntity<> &entity, std::chrono::nanoseconds) + { + for (auto &event : this->_events) + event(entity); + } + + void EventSystem::onSelfUpdate() + { + for (auto &event : this->_globalEvents) + event(this->_wal); + this->_events.clear(); + this->_globalEvents.clear(); + } +} \ No newline at end of file diff --git a/sources/System/Event/EventSystem.hpp b/sources/System/Event/EventSystem.hpp new file mode 100644 index 00000000..bcdb14c0 --- /dev/null +++ b/sources/System/Event/EventSystem.hpp @@ -0,0 +1,41 @@ +// +// Created by Zoe Roux on 6/1/21. +// + +#pragma once + +#include +#include +#include + +namespace BBM +{ + class EventSystem : public WAL::System<> + { + private: + //! @brief The list of events that occurred in the last update. + std::list> _events; + //! @brief The list of events that occurred in the last update. + std::list> _globalEvents; + public: + //! @brief Inform the system that a new event has occurred and it should run the given method on every entities. + void dispatchEvent(const std::function& event); + + //! @brief Inform the system that a new event has occurred and it should run the given method on every entities. + void dispatchEvent(const std::function& event); + + //! @inherit + void onUpdate(WAL::ViewEntity<> &entity, std::chrono::nanoseconds dtime) override; + //! @inherit + void onSelfUpdate() override; + + //! @brief A default constructor + explicit EventSystem(WAL::Wal &wal); + //! @brief An event system is copy constructable. + EventSystem(const EventSystem &) = default; + //! @brief A default destructor + ~EventSystem() override = default; + //! @brief An event system is not assignable. + EventSystem &operator=(const EventSystem &) = delete; + }; +} diff --git a/sources/System/Gamepad/GamepadSystem.cpp b/sources/System/Gamepad/GamepadSystem.cpp index f6d67d99..ee4b8767 100644 --- a/sources/System/Gamepad/GamepadSystem.cpp +++ b/sources/System/Gamepad/GamepadSystem.cpp @@ -31,10 +31,11 @@ namespace BBM for (auto key : keyPressedMap) key.second = gamepad.isPressed(key.first); - controllable.move = Vector2f(); - controllable.move.x += gamepad.isPressed(gamepadComponent.keyRight); - controllable.move.x -= gamepad.isPressed(gamepadComponent.keyLeft); - controllable.move.y += gamepad.isPressed(gamepadComponent.keyUp); - controllable.move.y -= gamepad.isPressed(gamepadComponent.keyDown); + controllable.move.x = gamepad.getAxisValue(gamepadComponent.LeftStickX) * -1; + controllable.move.y = gamepad.getAxisValue(gamepadComponent.LeftStickY) * -1; + controllable.move.x -= gamepad.isDown(gamepadComponent.keyRight); + controllable.move.x += gamepad.isDown(gamepadComponent.keyLeft); + controllable.move.y += gamepad.isDown(gamepadComponent.keyUp); + controllable.move.y -= gamepad.isDown(gamepadComponent.keyDown); } } \ No newline at end of file diff --git a/sources/System/Health/HealthSystem.cpp b/sources/System/Health/HealthSystem.cpp index 29e0db1f..4419e9e1 100644 --- a/sources/System/Health/HealthSystem.cpp +++ b/sources/System/Health/HealthSystem.cpp @@ -3,6 +3,7 @@ // Edited by Benjamin Henry on 2021-05-20. // +#include #include "HealthSystem.hpp" #include "Component/Health/HealthComponent.hpp" #include "Component/Controllable/ControllableComponent.hpp" @@ -18,7 +19,8 @@ namespace BBM { auto &health = entity.get(); - if (health.getHealthPoint() == 0) + if (health.getHealthPoint() == 0) { health.onDeath(entity); + } } } \ No newline at end of file diff --git a/sources/System/IAControllable/IAControllableSystem.cpp b/sources/System/IAControllable/IAControllableSystem.cpp index 9e20998c..83e52a68 100644 --- a/sources/System/IAControllable/IAControllableSystem.cpp +++ b/sources/System/IAControllable/IAControllableSystem.cpp @@ -55,13 +55,13 @@ namespace BBM if (res.hasFailed() || res.size() != 4) return; - if (res[3].isBool()) - controllable.bomb = res[3]; - if (res[2].isBool()) - controllable.jump = res[2]; - if (res[1].isNumber()) - controllable.move.y = res[1]; if (res[0].isNumber()) controllable.move.x = res[0]; + if (res[1].isNumber()) + controllable.move.y = res[1]; + if (res[2].isBool()) + controllable.jump = res[2]; + if (res[3].isBool()) + controllable.bomb = res[3]; } } \ No newline at end of file diff --git a/sources/System/Keyboard/KeyboardSystem.cpp b/sources/System/Keyboard/KeyboardSystem.cpp index ccc207ab..0f2a0cef 100644 --- a/sources/System/Keyboard/KeyboardSystem.cpp +++ b/sources/System/Keyboard/KeyboardSystem.cpp @@ -16,7 +16,7 @@ namespace BBM : System(wal) {} - void KeyboardSystem::onFixedUpdate(WAL::ViewEntity &entity) + void KeyboardSystem::onUpdate(WAL::ViewEntity &entity, std::chrono::nanoseconds) { const auto &keyboard = entity.get(); auto &controllable = entity.get(); @@ -28,12 +28,12 @@ namespace BBM }; for (auto key : keyPressedMap) - key.second = Keyboard::isDown(key.first); + key.second = Keyboard::isPressed(key.first); controllable.move = Vector2f(); if (Keyboard::isDown(keyboard.keyRight)) - controllable.move.x += 1; - if (Keyboard::isDown(keyboard.keyLeft)) controllable.move.x -= 1; + if (Keyboard::isDown(keyboard.keyLeft)) + controllable.move.x += 1; if (Keyboard::isDown(keyboard.keyUp)) controllable.move.y += 1; if (Keyboard::isDown(keyboard.keyDown)) diff --git a/sources/System/Keyboard/KeyboardSystem.hpp b/sources/System/Keyboard/KeyboardSystem.hpp index cf7309e1..e95bfcda 100644 --- a/sources/System/Keyboard/KeyboardSystem.hpp +++ b/sources/System/Keyboard/KeyboardSystem.hpp @@ -17,7 +17,7 @@ namespace BBM { public: //! @inherit - void onFixedUpdate(WAL::ViewEntity &entity) override; + void onUpdate(WAL::ViewEntity &entity, std::chrono::nanoseconds) override; //! @brief A default constructor explicit KeyboardSystem(WAL::Wal &wal); diff --git a/sources/System/Music/MusicSystem.cpp b/sources/System/Music/MusicSystem.cpp new file mode 100644 index 00000000..ea909d9a --- /dev/null +++ b/sources/System/Music/MusicSystem.cpp @@ -0,0 +1,24 @@ +// +// Created by Tom Augier on 05/06/2021 +// + +#include "MusicSystem.hpp" +#include + +namespace BBM { + + MusicSystem::MusicSystem(WAL::Wal &wal) + : System(wal) + {} + + void MusicSystem::onFixedUpdate(WAL::ViewEntity &entity) + { + auto &music = entity.get(); + + music.setVolume(music.volume); + if (!music.isPlaying()) { + music.playMusic(); + } + music.updateMusicStream(); + } +} \ No newline at end of file diff --git a/sources/System/Music/MusicSystem.hpp b/sources/System/Music/MusicSystem.hpp new file mode 100644 index 00000000..d524d300 --- /dev/null +++ b/sources/System/Music/MusicSystem.hpp @@ -0,0 +1,31 @@ +// +// Created by Tom Augier on 05/06/2021 +// + +#pragma once + +#include "System/System.hpp" +#include "Window.hpp" +#include "Component/Music/MusicComponent.hpp" +#include "Component/Health/HealthComponent.hpp" +#include +#include "Wal.hpp" + +namespace BBM +{ + class MusicSystem : public WAL::System + { + public: + //! @inherit + void onFixedUpdate(WAL::ViewEntity &entity) override; + + //! @brief ctor + MusicSystem(WAL::Wal &wal); + //! @brief Default copy ctor + MusicSystem(const MusicSystem &) = default; + //! @brief Default dtor + ~MusicSystem() override = default; + //! @brief A MusicManager screen system can't be assigned. + MusicSystem &operator=(const MusicSystem &) = delete; + }; +} diff --git a/sources/System/Renderer/RenderSystem.cpp b/sources/System/Renderer/RenderSystem.cpp index cdabb452..e735c1e9 100644 --- a/sources/System/Renderer/RenderSystem.cpp +++ b/sources/System/Renderer/RenderSystem.cpp @@ -10,13 +10,16 @@ #include "Component/Renderer/Drawable2DComponent.hpp" #include "Drawables/ADrawable3D.hpp" + +#include "Component/Collision/CollisionComponent.hpp" + namespace BBM { RenderSystem::RenderSystem(WAL::Wal &wal, RAY::Window &window, bool debugMode) : System(wal), - _window(window), - _camera(Vector3f(), Vector3f(), Vector3f(0, 1, 0), 50, CAMERA_PERSPECTIVE), - _debugMode(debugMode) + _window(window), + _camera(Vector3f(), Vector3f(), Vector3f(0, 1, 0), 50, CAMERA_PERSPECTIVE), + _debugMode(debugMode) { this->_window.setFPS(this->FPS); } @@ -44,7 +47,8 @@ namespace BBM this->_window.endDrawing(); } - void RenderSystem::onUpdate(WAL::ViewEntity &entity, std::chrono::nanoseconds dtime) + void RenderSystem::onUpdate(WAL::ViewEntity &entity, + std::chrono::nanoseconds dtime) { const auto &pos = entity.get(); const auto &cam = entity.get(); diff --git a/sources/System/Sound/PlayerSoundManagerSystem.cpp b/sources/System/Sound/PlayerSoundManagerSystem.cpp new file mode 100644 index 00000000..dac45304 --- /dev/null +++ b/sources/System/Sound/PlayerSoundManagerSystem.cpp @@ -0,0 +1,34 @@ +// +// Created by Tom Augier on 05/06/2021 +// + +#include "PlayerSoundManagerSystem.hpp" +#include + +namespace BBM { + + PlayerSoundManagerSystem::PlayerSoundManagerSystem(WAL::Wal &wal) + : System(wal) + {} + + void PlayerSoundManagerSystem::onFixedUpdate(WAL::ViewEntity &entity) + { + const auto &controllable = entity.get(); + auto &sound = entity.get(); + auto &health = entity.get(); + + sound.setVolume(sound.volume); + std::map soundIndex = { + {health.getHealthPoint() <= 0, SoundComponent::DEATH}, + {controllable.bomb, SoundComponent::BOMB}, + {controllable.jump, SoundComponent::JUMP}, + {controllable.move.x != 0 || controllable.move.y != 0, SoundComponent::MOVE} + }; + for (auto &a : soundIndex) { + if (a.first) { + sound.setIndex(a.second); + sound.playSound(); + } + } + } +} \ No newline at end of file diff --git a/sources/System/Sound/PlayerSoundManagerSystem.hpp b/sources/System/Sound/PlayerSoundManagerSystem.hpp new file mode 100644 index 00000000..6e49763b --- /dev/null +++ b/sources/System/Sound/PlayerSoundManagerSystem.hpp @@ -0,0 +1,31 @@ +// +// Created by Tom Augier on 05/06/2021 +// + +#pragma once + +#include "System/System.hpp" +#include "Window.hpp" +#include "Component/Sound/SoundComponent.hpp" +#include "Component/Health/HealthComponent.hpp" +#include +#include "Wal.hpp" + +namespace BBM +{ + class PlayerSoundManagerSystem : public WAL::System + { + public: + //! @inherit + void onFixedUpdate(WAL::ViewEntity &entity) override; + + //! @brief ctor + PlayerSoundManagerSystem(WAL::Wal &wal); + //! @brief Default copy ctor + PlayerSoundManagerSystem(const PlayerSoundManagerSystem &) = default; + //! @brief Default dtor + ~PlayerSoundManagerSystem() override = default; + //! @brief A SoundManager screen system can't be assigned. + PlayerSoundManagerSystem &operator=(const PlayerSoundManagerSystem &) = delete; + }; +} diff --git a/sources/System/Timer/TimerSystem.cpp b/sources/System/Timer/TimerSystem.cpp new file mode 100644 index 00000000..f6c82c2b --- /dev/null +++ b/sources/System/Timer/TimerSystem.cpp @@ -0,0 +1,25 @@ +// +// Created by Zoe Roux on 5/31/21. +// + +#include "TimerSystem.hpp" +#include "Component/Timer/TimerComponent.hpp" + +using namespace std::chrono_literals; + +namespace BBM +{ + TimerSystem::TimerSystem(WAL::Wal &wal) + : System(wal) + {} + + void TimerSystem::onUpdate(WAL::ViewEntity &entity, std::chrono::nanoseconds dtime) + { + auto &timer = entity.get(); + timer.ringIn -= dtime; + if (timer.ringIn <= 0ns) { + timer.setDisable(true); + timer.callback(entity, this->_wal); + } + } +} \ No newline at end of file diff --git a/sources/System/Timer/TimerSystem.hpp b/sources/System/Timer/TimerSystem.hpp new file mode 100644 index 00000000..c7b20bc2 --- /dev/null +++ b/sources/System/Timer/TimerSystem.hpp @@ -0,0 +1,28 @@ +// +// Created by Zoe Roux on 5/31/21. +// + +#pragma once + +#include +#include +#include + +namespace BBM +{ + class TimerSystem : public WAL::System + { + public: + //! @inherit + void onUpdate(WAL::ViewEntity &entity, std::chrono::nanoseconds dtime) override; + + //! @brief A default constructor + TimerSystem(WAL::Wal &); + //! @brief A timer system is copy constructable. + TimerSystem(const TimerSystem &) = default; + //! @brief A default destructor + ~TimerSystem() override = default; + //! @breief A timer system is assignable. + TimerSystem &operator=(const TimerSystem &) = default; + }; +} diff --git a/tests/CacheTest.cpp b/tests/CacheTest.cpp new file mode 100644 index 00000000..7e30cd99 --- /dev/null +++ b/tests/CacheTest.cpp @@ -0,0 +1,57 @@ + +#include + +#define private public +#include +#include