diff --git a/CMakeLists.txt b/CMakeLists.txt index 6110a686..a3af798d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -134,8 +134,15 @@ set(SOURCES sources/Runner/PauseMenuScene.cpp sources/Runner/SettingsMenuScene.cpp sources/Runner/CreditScene.cpp + sources/Component/Score/ScoreComponent.cpp + sources/Component/Score/ScoreComponent.hpp + sources/System/Score/ScoreSystem.cpp + sources/System/Score/ScoreSystem.hpp + sources/System/EndCondition/EndConditionSystem.hpp + sources/System/EndCondition/EndConditionSystem.cpp sources/Runner/LobbyScene.cpp sources/Runner/HowToPlayScene.cpp + sources/Runner/ScoreScene.cpp ) add_executable(bomberman sources/main.cpp diff --git a/assets/player/ui/blue.png b/assets/player/ui/blue.png new file mode 100644 index 00000000..5d7d4291 Binary files /dev/null and b/assets/player/ui/blue.png differ diff --git a/assets/player/ui/green.png b/assets/player/ui/green.png new file mode 100644 index 00000000..14fbb466 Binary files /dev/null and b/assets/player/ui/green.png differ diff --git a/assets/player/ui/red.png b/assets/player/ui/red.png new file mode 100644 index 00000000..b0b35db2 Binary files /dev/null and b/assets/player/ui/red.png differ diff --git a/assets/player/ui/yellow.png b/assets/player/ui/yellow.png new file mode 100644 index 00000000..f74d788d Binary files /dev/null and b/assets/player/ui/yellow.png differ diff --git a/lib/Ray/sources/Drawables/Texture.cpp b/lib/Ray/sources/Drawables/Texture.cpp index 7a70a459..ce16a6f1 100644 --- a/lib/Ray/sources/Drawables/Texture.cpp +++ b/lib/Ray/sources/Drawables/Texture.cpp @@ -42,6 +42,11 @@ namespace RAY { return *this; } + const std::string &Texture::getResourcePath() const + { + return this->_resourcePath; + } + Texture::operator ::Texture() const { return *this->_texture; diff --git a/lib/Ray/sources/Drawables/Texture.hpp b/lib/Ray/sources/Drawables/Texture.hpp index 74eab4c8..04518c57 100644 --- a/lib/Ray/sources/Drawables/Texture.hpp +++ b/lib/Ray/sources/Drawables/Texture.hpp @@ -44,6 +44,9 @@ namespace RAY //! @brief Load texture from file, lets one use one entity for multiple files Texture &use(const std::string &filename); + //! @return path of loaded texture + const std::string &getResourcePath() const; + protected: private: //! @brief Texture, really, that's just it... diff --git a/lib/Ray/sources/Model/Model.cpp b/lib/Ray/sources/Model/Model.cpp index fefa29ea..c758ba00 100644 --- a/lib/Ray/sources/Model/Model.cpp +++ b/lib/Ray/sources/Model/Model.cpp @@ -61,6 +61,11 @@ namespace RAY::Drawables::Drawables3D return true; } + Texture &Model::getTextureByMaterial(MaterialType materialType) + { + return this->_textureList[materialType]; + } + Model::operator ::Model() const { return *this->_model; diff --git a/lib/Ray/sources/Model/Model.hpp b/lib/Ray/sources/Model/Model.hpp index 2bf6cf47..16616fb8 100644 --- a/lib/Ray/sources/Model/Model.hpp +++ b/lib/Ray/sources/Model/Model.hpp @@ -90,6 +90,10 @@ namespace RAY::Drawables::Drawables3D { //! @brief Draw model's wires on window void drawWiresOn(RAY::Window &) override; + //! @param materialType type of material + //! @return texture + Texture &getTextureByMaterial(MaterialType materialType); + private: //! @brief Raw data from raylib std::shared_ptr<::Model> _model; diff --git a/sources/Component/Score/ScoreComponent.cpp b/sources/Component/Score/ScoreComponent.cpp new file mode 100644 index 00000000..b54a835d --- /dev/null +++ b/sources/Component/Score/ScoreComponent.cpp @@ -0,0 +1,16 @@ + +#include "ScoreComponent.hpp" + +namespace BBM +{ + ScoreComponent::ScoreComponent(WAL::Entity &entity) + : Component(entity), + aliveTime(std::chrono::nanoseconds::zero()) + {} + + WAL::Component *ScoreComponent::clone(WAL::Entity &entity) const + { + return new ScoreComponent(entity); + } + +} // namespace WAL \ No newline at end of file diff --git a/sources/Component/Score/ScoreComponent.hpp b/sources/Component/Score/ScoreComponent.hpp new file mode 100644 index 00000000..15da0650 --- /dev/null +++ b/sources/Component/Score/ScoreComponent.hpp @@ -0,0 +1,28 @@ + +#pragma once + +#include "Component/Component.hpp" +#include + +namespace BBM +{ + //! @brief A basic position component + class ScoreComponent : public WAL::Component + { + public: + //! @brief the score of the player + std::chrono::nanoseconds aliveTime; + + //! @inherit + WAL::Component *clone(WAL::Entity &entity) const override; + + //! @brief Create a new ScoreComponent linked to a specific entity + explicit ScoreComponent(WAL::Entity &entity); + //! @brief A position component is copy constructable + ScoreComponent(const ScoreComponent &) = default; + //! @brief A default destructor + ~ScoreComponent() override = default; + //! @brief A position component is not assignable + ScoreComponent &operator=(const ScoreComponent &) = delete; + }; +} // namespace WAL \ No newline at end of file diff --git a/sources/Models/GameState.hpp b/sources/Models/GameState.hpp index 2e7bdc11..b3d506be 100644 --- a/sources/Models/GameState.hpp +++ b/sources/Models/GameState.hpp @@ -27,6 +27,7 @@ namespace BBM TitleScreenScene, CreditScene, HowToPlayScene, + ScoreScene, }; diff --git a/sources/Runner/GameScene.cpp b/sources/Runner/GameScene.cpp index 3ef2e295..41029d9d 100644 --- a/sources/Runner/GameScene.cpp +++ b/sources/Runner/GameScene.cpp @@ -17,14 +17,18 @@ #include "Component/Shaders/ShaderComponent.hpp" #include "Component/Tag/TagComponent.hpp" #include "Component/Renderer/Drawable3DComponent.hpp" +#include "Component/Renderer/Drawable2DComponent.hpp" #include "Component/Button/ButtonComponent.hpp" -#include "Drawables/2D/Text.hpp" +#include "Drawables/Texture.hpp" #include "Component/Gravity/GravityComponent.hpp" #include "Component/BumperTimer/BumperTimerComponent.hpp" +#include "Component/Timer/TimerComponent.hpp" #include "Model/Model.hpp" #include "Map/Map.hpp" +#include "Component/Score/ScoreComponent.hpp" namespace RAY3D = RAY::Drawables::Drawables3D; +namespace RAY2D = RAY::Drawables::Drawables2D; namespace BBM { @@ -34,6 +38,10 @@ namespace BBM scene->addEntity("camera") .addComponent(8, 20, 7) .addComponent(Vector3f(8, 0, 8)); + scene->addEntity("Timer") + .addComponent(std::chrono::seconds(60), [](WAL::Entity &, WAL::Wal &) { + Runner::gameState.nextScene = GameState::ScoreScene; + }); MapGenerator::loadMap(16, 16, MapGenerator::createMap(16, 16), scene); return scene; } @@ -47,10 +55,11 @@ namespace BBM //{SoundComponent::DEATH, "assets/sounds/death.ogg"} }; - auto &player = scene.addEntity("player") + return scene.addEntity("player") .addComponent() .addComponent("assets/player/player.iqm", true) .addComponent() + .addComponent() .addComponent() .addComponent() .addComponent() @@ -67,11 +76,5 @@ namespace BBM auto &animation = entity.getComponent(); animation.setAnimIndex(5); }); - RAY3D::Model *model = dynamic_cast(player.getComponent().drawable.get()); - //std::string texturePath = model->get - auto &player = scene.addEntity("player") - .addComponent() - .addComponent("assets/player/player.iqm", true) - return player; } } \ No newline at end of file diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp index ca96ba16..04745b62 100644 --- a/sources/Runner/Runner.cpp +++ b/sources/Runner/Runner.cpp @@ -34,6 +34,8 @@ #include "System/BumperTimer/BumperTimerSystem.hpp" #include "System/Music/MusicSystem.hpp" #include "System/Lobby/LobbySystem.hpp" +#include "System/Score/ScoreSystem.hpp" +#include "System/EndCondition/EndConditionSystem.hpp" #include "Component/Lobby/LobbyComponent.hpp" namespace BBM @@ -58,6 +60,8 @@ namespace BBM } if (gameState.nextScene == gameState.currentScene) return; + if (gameState.nextScene == GameState::SceneID::ScoreScene) + gameState._loadedScenes[GameState::SceneID::ScoreScene] = Runner::loadScoreScene(*engine.getScene()); gameState._loadedScenes[gameState.currentScene] = engine.getScene(); engine.changeScene(gameState._loadedScenes[gameState.nextScene]); gameState.currentScene = gameState.nextScene; @@ -84,6 +88,8 @@ namespace BBM .addSystem() .addSystem() .addSystem() + .addSystem() + .addSystem() .addSystem(); } diff --git a/sources/Runner/Runner.hpp b/sources/Runner/Runner.hpp index 5c8872b7..f3a19bef 100644 --- a/sources/Runner/Runner.hpp +++ b/sources/Runner/Runner.hpp @@ -61,6 +61,10 @@ namespace BBM //! @brief load how to play screen static std::shared_ptr loadHowToPlayScene(); + //! @brief load all data related to score scene screen + //! @param gameScene scene containing players (to know the scores) + static std::shared_ptr loadScoreScene(WAL::Scene &gameScene); + //! @brief loads all scenes in the game state static void loadScenes(); diff --git a/sources/Runner/ScoreScene.cpp b/sources/Runner/ScoreScene.cpp new file mode 100644 index 00000000..a80f3caf --- /dev/null +++ b/sources/Runner/ScoreScene.cpp @@ -0,0 +1,93 @@ + +#include +#include "Runner.hpp" +#include +#include "Component/Button/ButtonComponent.hpp" +#include "Component/Music/MusicComponent.hpp" +#include "Component/Position/PositionComponent.hpp" +#include "Component/Renderer/Drawable2DComponent.hpp" +#include "Component/Renderer/Drawable3DComponent.hpp" +#include "Component/Sound/SoundComponent.hpp" +#include "Drawables/Texture.hpp" +#include "Drawables/2D/Text.hpp" +#include "Component/Score/ScoreComponent.hpp" +#include "Model/Model.hpp" + +namespace RAY2D = RAY::Drawables::Drawables2D; +namespace RAY3D = RAY::Drawables::Drawables3D; + +namespace BBM +{ + std::shared_ptr Runner::loadScoreScene(WAL::Scene &gameScene) + { + auto scene = std::make_shared(); + std::vector playersIconPath; + std::vector>players; + static const std::map sounds = { + {SoundComponent::JUMP, "assets/sounds/click.ogg"} + }; + static const std::vector tilesColor = { + GOLD, GRAY, BROWN, PURPLE + }; + static const std::vector rankName = { + "1st", "2nd", "3rd", "4th" + }; + + for (auto &[entity, score, drawable]: gameScene.view()) + players.push_back(entity); + std::sort(players.begin(), players.end(), [](WAL::Entity &entityA, WAL::Entity &entityB) { + return entityA.getComponent().aliveTime > entityB.getComponent().aliveTime; + }); + + for (auto &entity: players) { + RAY3D::Model *model = dynamic_cast(entity.get().getComponent().drawable.get()); + std::string path = model->getTextureByMaterial(MAP_DIFFUSE).getResourcePath(); + playersIconPath.push_back(path.replace(path.find("textures"), std::string("textures").size(), "icons")); + } + + addMenuControl(*scene); + scene->addEntity("Audio ressources") + .addComponent("assets/musics/music_result.ogg") + .addComponent(sounds); + scene->addEntity("background") + .addComponent() + .addComponent("assets/plain_menu_background.png"); + scene->addEntity("scene title text") + .addComponent(1920 / 3.25, 100, 0) + .addComponent("GAME OVER", 120, RAY::Vector2(), ORANGE); + scene->addEntity("scene title text") + .addComponent(1920 / 2.37, 250, 0) + .addComponent("CONGRATS", 50, RAY::Vector2(), ORANGE); + for (int i = 0; i < players.size(); i++) { + auto &playerTile = scene->addEntity("player tile") + .addComponent(224 * (i + 1) + 200 * i, 1080 / 2.5, 0) + .addComponent(RAY::Vector2(224 * (i + 1) + 200 * i, 1080 / 3), RAY::Vector2(200, 200),tilesColor[i]); + auto &playerRank = scene->addEntity("player rank name") + .addComponent(224 * (i + 1) + 200 * i, 1080 / 2.75, 0) + .addComponent(rankName[i], 30, RAY::Vector2(224 * (i + 1) + 200 * i, 1080 / 3), tilesColor[i]); + auto &player = scene->addEntity("player") + .addComponent(224 * (i + 1) + 200 * i, 1080 / 2.5, 0) + .addComponent(playersIconPath[i]); + } + scene->addEntity("back to main menu") + .addComponent(10, 1080 - 85, 0) + .addComponent("assets/buttons/button_back.png") + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + gameState.nextScene = BBM::GameState::SceneID::MainMenuScene; + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); + + texture->use("assets/buttons/button_back.png"); + }) + .addComponent([](WAL::Entity &entity, WAL::Wal &) + { + RAY::Texture *texture = dynamic_cast(entity.getComponent().drawable.get()); + + texture->use("assets/buttons/button_back_hovered.png"); + }); + return scene; + } +} \ No newline at end of file diff --git a/sources/System/EndCondition/EndConditionSystem.cpp b/sources/System/EndCondition/EndConditionSystem.cpp new file mode 100644 index 00000000..0403d3a1 --- /dev/null +++ b/sources/System/EndCondition/EndConditionSystem.cpp @@ -0,0 +1,25 @@ + +#include "EndConditionSystem.hpp" +#include +#include "Runner/Runner.hpp" +#include "Component/Score/ScoreComponent.hpp" + +namespace BBM { + + EndConditionSystem::EndConditionSystem(WAL::Wal &wal) + : System(wal) + {} + + void EndConditionSystem::onSelfUpdate() + { + unsigned int alivePlayersCount = 0; + auto &view = this->_wal.getScene()->view(); + + if (!view.size()) + return; + for (auto & [_ , scoreComponent, healthComponent]: view) + alivePlayersCount += (healthComponent.getHealthPoint() != 0); + if (alivePlayersCount <= 1) + Runner::gameState.nextScene = Runner::gameState.ScoreScene; + } +} \ No newline at end of file diff --git a/sources/System/EndCondition/EndConditionSystem.hpp b/sources/System/EndCondition/EndConditionSystem.hpp new file mode 100644 index 00000000..edd3a9d7 --- /dev/null +++ b/sources/System/EndCondition/EndConditionSystem.hpp @@ -0,0 +1,26 @@ + +#pragma once + +#include "System/System.hpp" +#include "Component/Score/ScoreComponent.hpp" +#include "Component/Health/HealthComponent.hpp" +#include "Wal.hpp" + +namespace BBM +{ + class EndConditionSystem : public WAL::System + { + public: + //! @inherit + void onSelfUpdate() override; + + //! @brief ctor + EndConditionSystem(WAL::Wal &wal); + //! @brief Default copy ctor + EndConditionSystem(const EndConditionSystem &) = default; + //! @brief Default dtor + ~EndConditionSystem() override = default; + //! @brief A SoundManager screen system can't be assigned. + EndConditionSystem &operator=(const EndConditionSystem &) = delete; + }; +} diff --git a/sources/System/Lobby/LobbySystem.cpp b/sources/System/Lobby/LobbySystem.cpp index 9c020625..2d41a51e 100644 --- a/sources/System/Lobby/LobbySystem.cpp +++ b/sources/System/Lobby/LobbySystem.cpp @@ -154,8 +154,10 @@ namespace BBM int mapWidth = 16; int mapHeight = 16; int playerCount = 0; + int playerID = 0; for (auto &[_, lobby] : wal.getScene()->view()) { + playerID++; if (lobby.layout == ControllableComponent::NONE) continue; auto &player = Runner::createPlayer(*scene); @@ -165,6 +167,12 @@ namespace BBM mapHeight * ((playerCount + 1) % 2)); auto *model = dynamic_cast(player.getComponent().drawable.get()); model->setTextureToMaterial(MAP_DIFFUSE, "assets/player/textures/" + _colors[lobby.color] + ".png"); + std::string texturePath = "assets/player/ui/" + _colors[lobby.color] + ".png"; + int x = (playerID % 2 == 0) ? 1920 - 10 - 320 : 10; + int y = playerID > 2 ? 1080 - 10 - 248 : 10; + scene->addEntity("player tile") + .addComponent(x, y, 0) + .addComponent(texturePath); playerCount++; } Runner::gameState._loadedScenes[GameState::SceneID::GameScene] = scene; diff --git a/sources/System/Score/ScoreSystem.cpp b/sources/System/Score/ScoreSystem.cpp new file mode 100644 index 00000000..4b32fda2 --- /dev/null +++ b/sources/System/Score/ScoreSystem.cpp @@ -0,0 +1,19 @@ +// +// Created by Tom Augier on 05/06/2021 +// + +#include "ScoreSystem.hpp" +#include + +namespace BBM { + + ScoreSystem::ScoreSystem(WAL::Wal &wal) + : System(wal) + {} + + void ScoreSystem::onUpdate(WAL::ViewEntity &entity, std::chrono::nanoseconds dtime) + { + if (entity.get().getHealthPoint()) + entity.get().aliveTime += dtime; + } +} \ No newline at end of file diff --git a/sources/System/Score/ScoreSystem.hpp b/sources/System/Score/ScoreSystem.hpp new file mode 100644 index 00000000..33ad3c95 --- /dev/null +++ b/sources/System/Score/ScoreSystem.hpp @@ -0,0 +1,26 @@ + +#pragma once + +#include "System/System.hpp" +#include "Component/Score/ScoreComponent.hpp" +#include "Component/Health/HealthComponent.hpp" +#include "Wal.hpp" + +namespace BBM +{ + class ScoreSystem : public WAL::System + { + public: + //! @inherit + void onUpdate(WAL::ViewEntity &entity, std::chrono::nanoseconds dtime) override; + + //! @brief ctor + ScoreSystem(WAL::Wal &wal); + //! @brief Default copy ctor + ScoreSystem(const ScoreSystem &) = default; + //! @brief Default dtor + ~ScoreSystem() override = default; + //! @brief A SoundManager screen system can't be assigned. + ScoreSystem &operator=(const ScoreSystem &) = delete; + }; +}