From eda3bc94aaf54239ead9e90f08b00bd359bbe6e3 Mon Sep 17 00:00:00 2001 From: Desousa Brice <91657273+KitetsuK@users.noreply.github.com> Date: Sat, 28 Oct 2023 18:42:37 +0200 Subject: [PATCH] Feature/rb 142 menu de connection (#129) * ECS: Add button that can change scene Merge MINOR * CLIENT-GAME/DOCUMENTATION: Add first functional version of menu + some docs MINOR * FORMAT-AUTO: automatic format on pull request #129 * CLIENT-GAME/DOCUMENTATION: Update client game and error management * FORMAT-AUTO: automatic format on pull request #129 * CLIENT-GAME: Fix coderabbit review PATCH * FORMAT-AUTO: automatic format on pull request #129 * CLIENT-GAME: Modif now menu can init entity with the singletone MenuFactory MINOR * FORMAT-AUTO: automatic format on pull request #129 * CLIENT-GAME: Update src/Client/Systems/Menu/ButtonCallbacks.cpp Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * CLIENT-GAME: Modif script to debug compil PATCH * CLIENT-GAME: Update code to make it cleaner PATCH * FORMAT-AUTO: automatic format on pull request #129 * CLIENT-GAME/DOCUMENTATION: Add some docs for menu builder class Modif some static method inside the menu.cpp file MINOR * FORMAT-AUTO: automatic format on pull request #129 * CLIENT-GAME: Update setAllInputBoxFalse to be more optimized PATCH * FORMAT-AUTO: automatic format on pull request #129 * CLIENT-GAME: Fix some bad includes PATCH * FORMAT-AUTO: automatic format on pull request #129 * CLIENT-GAME: Modif now use template Json function PATCH * FORMAT-AUTO: automatic format on pull request #129 * CLIENT-GAME: Modif now use template Json function PATCH * FORMAT-AUTO: automatic format on pull request #129 * CLIENT-GAME: Modif now use template Json function PATCH * FORMAT-AUTO: automatic format on pull request #129 * DOCUMENTATION: Update json doc Modif compil.ps1 to compil as before MINOR * SCRIPTS: Modif scripts to do the same things as before PATCH * ECS: Add button that can change scene Merge MINOR * CLIENT-GAME/DOCUMENTATION: Add first functional version of menu + some docs MINOR * FORMAT-AUTO: automatic format on pull request #129 * CLIENT-GAME/DOCUMENTATION: Update client game and error management * CLIENT-GAME: Fix coderabbit review PATCH * FORMAT-AUTO: automatic format on pull request #129 * CLIENT-GAME: Modif now menu can init entity with the singletone MenuFactory MINOR * FORMAT-AUTO: automatic format on pull request #129 * CLIENT-GAME: Update src/Client/Systems/Menu/ButtonCallbacks.cpp Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> * CLIENT-GAME: Modif script to debug compil PATCH * CLIENT-GAME: Update code to make it cleaner PATCH * CLIENT-GAME/DOCUMENTATION: Add some docs for menu builder class Modif some static method inside the menu.cpp file MINOR * FORMAT-AUTO: automatic format on pull request #129 * CLIENT-GAME: Update setAllInputBoxFalse to be more optimized PATCH * FORMAT-AUTO: automatic format on pull request #129 * CLIENT-GAME: Fix some bad includes PATCH * FORMAT-AUTO: automatic format on pull request #129 * CLIENT-GAME: Modif now use template Json function PATCH * FORMAT-AUTO: automatic format on pull request #129 * CLIENT-GAME: Modif now use template Json function PATCH * FORMAT-AUTO: automatic format on pull request #129 * CLIENT-GAME: Modif now use template Json function PATCH * FORMAT-AUTO: automatic format on pull request #129 * DOCUMENTATION: Update json doc Modif compil.ps1 to compil as before MINOR * FORMAT-AUTO: automatic format on pull request #129 * SCRIPTS: Modif scripts to do the same things as before PATCH * FORMAT-AUTO: automatic format on pull request #129 --------- Co-authored-by: Github Actions Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com> --- assets/Json/menu.json | 121 ++++++++++++ docs/developer-guide/client/graphic/text.md | 2 + docs/developer-guide/ecs/json/json.md | 7 +- src/Client/Raylib/Events/Inputs.hpp | 1 + src/Client/Raylib/Graphics/Graphics.cpp | 17 ++ src/Client/Raylib/Graphics/Graphics.hpp | 5 + src/Client/SceneManager.hpp | 7 +- src/Client/Systems/CMakeLists.txt | 1 + src/Client/Systems/ClientSystems.cpp | 6 +- src/Client/Systems/ClientSystems.hpp | 2 +- src/Client/Systems/CustomTypes.hpp | 48 +++++ src/Client/Systems/CustomTypes/AnimRect.hpp | 3 +- src/Client/Systems/Events/EventsSystems.cpp | 6 +- src/Client/Systems/Menu/ButtonCallbacks.cpp | 54 ++++++ src/Client/Systems/Menu/ButtonCallbacks.hpp | 16 ++ src/Client/Systems/Menu/CMakeLists.txt | 15 ++ src/Client/Systems/Menu/Menu.cpp | 188 +++++++++++++++++++ src/Client/Systems/Menu/Menu.hpp | 80 ++++++++ src/Client/Systems/Menu/MenuSystems.cpp | 192 ++++++++++++++++++++ src/Client/Systems/Menu/MenuSystems.hpp | 31 ++++ src/ECS/Json.cpp | 8 - src/ECS/Json.hpp | 7 +- src/main_client.cpp | 38 +--- 23 files changed, 789 insertions(+), 66 deletions(-) create mode 100644 assets/Json/menu.json create mode 100644 src/Client/Systems/Menu/ButtonCallbacks.cpp create mode 100644 src/Client/Systems/Menu/ButtonCallbacks.hpp create mode 100644 src/Client/Systems/Menu/CMakeLists.txt create mode 100644 src/Client/Systems/Menu/Menu.cpp create mode 100644 src/Client/Systems/Menu/Menu.hpp create mode 100644 src/Client/Systems/Menu/MenuSystems.cpp create mode 100644 src/Client/Systems/Menu/MenuSystems.hpp diff --git a/assets/Json/menu.json b/assets/Json/menu.json new file mode 100644 index 00000000..f59bfea3 --- /dev/null +++ b/assets/Json/menu.json @@ -0,0 +1,121 @@ +{ + "menu": { + "connect": { + "type": "button", + "spritePath": "assets/R-TypeSheet/r-typesheet1.gif", + "width": 500, + "height" : 500, + "rect": { + "x": 101.0, + "y": 0.0, + "width": 32.0, + "height": 19.0 + }, + "position" : { + "x": 1000, + "y": 1000 + }, + "collisionRect": { + "width": 500, + "height": 500 + }, + "animRect": [ + { + "type": "hover", + "time": 80, + "noIncr": true, + "list": [ + { + "x" : 233.0, + "y": 2.0, + "width": 32.0, + "height": 14.0 + } + ] + } + ] + }, + "ip": { + "name": "ip", + "type": "input", + "font": "assets/Fonts/soliden/SolidenTrial-Black.otf", + "spritePath": "assets/R-TypeSheet/r-typesheet1.gif", + "text": "localhost", + "color": "red", + "textSize": 3, + "maxChar": 10, + "width": 500, + "height" : 500, + "position" : { + "x": 2000, + "y": 2000 + }, + "rect": { + "x": 101.0, + "y": 0.0, + "width": 32.0, + "height": 19.0 + }, + "collisionRect": { + "width": 2000, + "height": 500 + }, + "animRect": [ + { + "type": "hover", + "time": 80, + "noIncr": true, + "list": [ + { + "x" : 233.0, + "y": 2.0, + "width": 32.0, + "height": 14.0 + } + ] + } + ] + }, + "host": { + "name": "port", + "type": "input", + "font": "assets/Fonts/soliden/SolidenTrial-Black.otf", + "spritePath": "assets/R-TypeSheet/r-typesheet1.gif", + "text": "4242", + "color": "red", + "textSize": 3, + "maxChar": 10, + "width": 20, + "height" : 5, + "position" : { + "x": 3700, + "y": 6000 + }, + "collisionRect": { + "width": 2000, + "height": 500 + }, + "rect": { + "x": 101.0, + "y": 0.0, + "width": 32.0, + "height": 19.0 + }, + "animRect": [ + { + "type": "hover", + "time": 80, + "noIncr": true, + "list": [ + { + "x" : 233.0, + "y": 2.0, + "width": 32.0, + "height": 14.0 + } + ] + } + ] + } + } +} diff --git a/docs/developer-guide/client/graphic/text.md b/docs/developer-guide/client/graphic/text.md index 01f87da2..a75c874b 100644 --- a/docs/developer-guide/client/graphic/text.md +++ b/docs/developer-guide/client/graphic/text.md @@ -26,6 +26,8 @@ void Raylib::Text::setFontSize(float fontSize); Raylib::Vector2 Raylib::Text::getPosition() const; void Raylib::Text::setPixelPosition(Raylib::Vector2 position); void Raylib::Text::setCurrentFontSize(float fontSize); +std::string &Text::getCurrentText(); +void Text::setCurrentText(const std::string &text) ``` getPosition is in percentage of the screen size. For each draw, we recommand to compute and set the position in pixel with setPixelPosition to have a responsive text. diff --git a/docs/developer-guide/ecs/json/json.md b/docs/developer-guide/ecs/json/json.md index e5a23969..6717aae4 100644 --- a/docs/developer-guide/ecs/json/json.md +++ b/docs/developer-guide/ecs/json/json.md @@ -34,11 +34,6 @@ This function is useful when you want to take a json list inside your json becau std::vector Json::getDatasByJsonType(const std::vector &indexes, JsonType dataType); ``` -- Get a data from an existing json data : -```cpp -nlohmann::json &Json::getDataFromJson(nlohmann::json jsonData, const std::string &index); -``` - - Get a data but precise the type of what you want with template : ```cpp template @@ -133,7 +128,7 @@ std::vector enemyData = And now you can iterate on your datas : ```cpp for (auto &data : enemyData) { - std::cout << Json::getInstance().getDataFromJson(elem, "spritePath") << + std::cout << Json::getInstance().getDataFromJson(elem, "spritePath") << std::endl; } ``` diff --git a/src/Client/Raylib/Events/Inputs.hpp b/src/Client/Raylib/Events/Inputs.hpp index 614bc254..fc73222b 100644 --- a/src/Client/Raylib/Events/Inputs.hpp +++ b/src/Client/Raylib/Events/Inputs.hpp @@ -114,4 +114,5 @@ namespace Raylib { MOUSE_BTN_FORWARD = MOUSE_BUTTON_FORWARD, MOUSE_BTN_BACK = MOUSE_BUTTON_BACK, }; + } // namespace Raylib diff --git a/src/Client/Raylib/Graphics/Graphics.cpp b/src/Client/Raylib/Graphics/Graphics.cpp index ef9ed7df..f4c3c248 100644 --- a/src/Client/Raylib/Graphics/Graphics.cpp +++ b/src/Client/Raylib/Graphics/Graphics.cpp @@ -243,6 +243,13 @@ namespace Raylib { TakeScreenshot(fileName.c_str()); } + // Collision check functions + + bool checkCollisionPointRec(Vector2 point, Rectangle rec) + { + return (CheckCollisionPointRec({point.x, point.y}, {rec.x, rec.y, rec.width, rec.height})); + } + // Input-related functions: keyboard bool isKeyPressed(KeyboardKey key) @@ -695,4 +702,14 @@ namespace Raylib { _currentFontSize = fontSize; } + std::string &Text::getCurrentText() + { + return (_text); + } + + void Text::setCurrentText(const std::string &text) + { + _text = text; + } + } // namespace Raylib diff --git a/src/Client/Raylib/Graphics/Graphics.hpp b/src/Client/Raylib/Graphics/Graphics.hpp index 7d00950c..7e30da92 100644 --- a/src/Client/Raylib/Graphics/Graphics.hpp +++ b/src/Client/Raylib/Graphics/Graphics.hpp @@ -89,6 +89,9 @@ namespace Raylib { // Misc. functions void takeScreenshot(const std::string &fileName); + // Collision check functions + bool checkCollisionPointRec(Vector2 point, Rectangle rec); + // Input-related functions: keyboard bool isKeyPressed(KeyboardKey key); bool isKeyDown(KeyboardKey key); @@ -192,6 +195,8 @@ namespace Raylib { Color getColor() const; void setColor(Color color); void setCurrentFontSize(float fontSize); + std::string &getCurrentText(); + void setCurrentText(const std::string &text); private: std::string _text; diff --git a/src/Client/SceneManager.hpp b/src/Client/SceneManager.hpp index 608ad7da..8c17818f 100644 --- a/src/Client/SceneManager.hpp +++ b/src/Client/SceneManager.hpp @@ -18,7 +18,7 @@ namespace Scene { enum class Scene { MENU, MAIN_GAME, SCENE_MAX }; - enum class SystemManagers { GAME, EVENTS, DISPLAY, NETWORK }; + enum class SystemManagers { GAME, EVENTS, DISPLAY, NETWORK, MENU }; class SceneManager { public: @@ -34,10 +34,7 @@ namespace Scene { Scene _currentScene; bool _stop; const std::array, 2> _scenes = { - {{SystemManagers::EVENTS, - SystemManagers::GAME, - SystemManagers::DISPLAY, - SystemManagers::NETWORK}, + {{SystemManagers::DISPLAY, SystemManagers::MENU}, {SystemManagers::EVENTS, SystemManagers::GAME, SystemManagers::DISPLAY, diff --git a/src/Client/Systems/CMakeLists.txt b/src/Client/Systems/CMakeLists.txt index cd46ae18..905975b6 100644 --- a/src/Client/Systems/CMakeLists.txt +++ b/src/Client/Systems/CMakeLists.txt @@ -22,3 +22,4 @@ add_subdirectory(Graphic) add_subdirectory(Events) add_subdirectory(Network) add_subdirectory(CustomTypes) +add_subdirectory(Menu) diff --git a/src/Client/Systems/ClientSystems.cpp b/src/Client/Systems/ClientSystems.cpp index db0e8883..44d60c54 100644 --- a/src/Client/Systems/ClientSystems.cpp +++ b/src/Client/Systems/ClientSystems.cpp @@ -9,15 +9,17 @@ #include "ClientNetwork.hpp" #include "EventsSystems.hpp" #include "GraphicSystems.hpp" +#include "MenuSystems.hpp" #include "Systems.hpp" namespace Systems { - std::array>, 4> getSystemsGroups() + std::array>, 5> getSystemsGroups() { return { getECSSystems(), EventsSystems::getEventSystems(), GraphicSystems::getGraphicsSystems(), - getNetworkSystems()}; + getNetworkSystems(), + Menu::getMenuSystems()}; } } // namespace Systems diff --git a/src/Client/Systems/ClientSystems.hpp b/src/Client/Systems/ClientSystems.hpp index 6196fefc..6c2ba4d3 100644 --- a/src/Client/Systems/ClientSystems.hpp +++ b/src/Client/Systems/ClientSystems.hpp @@ -13,5 +13,5 @@ #include namespace Systems { - std::array>, 4> getSystemsGroups(); + std::array>, 5> getSystemsGroups(); } // namespace Systems diff --git a/src/Client/Systems/CustomTypes.hpp b/src/Client/Systems/CustomTypes.hpp index 8a2fd1f1..e93784ba 100644 --- a/src/Client/Systems/CustomTypes.hpp +++ b/src/Client/Systems/CustomTypes.hpp @@ -43,10 +43,58 @@ namespace Types { float size; }; + struct Button { + Button(std::function &fct) : callback(fct) {}; + std::function callback; + }; + + struct InputBox { + InputBox( + std::string &textStr, + std::string &boxName, + std::size_t &maxCharacters, + bool isSelected = false) + : name(boxName), + text(textStr), + maxChar(maxCharacters), + selected(isSelected) {}; + std::string name; + std::string text; + std::size_t maxChar; + bool selected; + }; + #ifdef CLIENT struct Color { Raylib::Color color; }; + + static const std::unordered_map colorMatchStrings({ + {"darkgray", Raylib::DarkGray }, + {"yellow", Raylib::Yellow }, + {"gold", Raylib::Gold }, + {"orange", Raylib::Orange }, + {"pink", Raylib::Pink }, + {"red", Raylib::Red }, + {"maroon", Raylib::Maroon }, + {"green", Raylib::Green }, + {"lime", Raylib::Lime }, + {"darkgreen", Raylib::DarkGreen }, + {"skyblue", Raylib::SkyBlue }, + {"blue", Raylib::Blue }, + {"darkblue", Raylib::DarkBlue }, + {"purple", Raylib::Purple }, + {"violet", Raylib::Violet }, + {"darkpurple", Raylib::DarkPurple}, + {"beige", Raylib::Beige }, + {"brown", Raylib::Brown }, + {"darkbrown", Raylib::DarkBrown }, + {"white", Raylib::White }, + {"black", Raylib::Black }, + {"blank", Raylib::Blank }, + {"magenta", Raylib::Magenta }, + {"raywhite", Raylib::RayWhite } + }); #endif } // namespace Types diff --git a/src/Client/Systems/CustomTypes/AnimRect.hpp b/src/Client/Systems/CustomTypes/AnimRect.hpp index 71da557f..51d50965 100644 --- a/src/Client/Systems/CustomTypes/AnimRect.hpp +++ b/src/Client/Systems/CustomTypes/AnimRect.hpp @@ -32,7 +32,7 @@ namespace Types { {LEFT, "left" }, }); - enum RectListType { UNDEFINED, DEFAULT_RECT, MOVE, ATTACK, DEAD }; + enum RectListType { UNDEFINED, DEFAULT_RECT, MOVE, ATTACK, DEAD, HOVER }; NLOHMANN_JSON_SERIALIZE_ENUM( RectListType, @@ -42,6 +42,7 @@ namespace Types { {MOVE, "move" }, {ATTACK, "attack" }, {DEAD, "dead" }, + {HOVER, "hover" } }); class AnimRect { diff --git a/src/Client/Systems/Events/EventsSystems.cpp b/src/Client/Systems/Events/EventsSystems.cpp index 17a9106b..c3c1e4e3 100644 --- a/src/Client/Systems/Events/EventsSystems.cpp +++ b/src/Client/Systems/Events/EventsSystems.cpp @@ -204,11 +204,7 @@ namespace Systems { std::lock_guard lock(Registry::getInstance().mutex); if (Raylib::isKeyDown(Raylib::KeyboardKey::KB_J)) { auto &sceneManager = Scene::SceneManager::getInstance(); - if (sceneManager.getCurrentScene() == Scene::Scene::MAIN_GAME) { - sceneManager.changeScene(Scene::Scene::MENU); - } else { - sceneManager.changeScene(Scene::Scene::MAIN_GAME); - } + sceneManager.changeScene(Scene::Scene::MENU); } } diff --git a/src/Client/Systems/Menu/ButtonCallbacks.cpp b/src/Client/Systems/Menu/ButtonCallbacks.cpp new file mode 100644 index 00000000..357a0cdf --- /dev/null +++ b/src/Client/Systems/Menu/ButtonCallbacks.cpp @@ -0,0 +1,54 @@ +/* +** EPITECH PROJECT, 2023 +** R-Bus +** File description: +** ButtonCallbacks +*/ + +#include "ButtonCallbacks.hpp" +#include "CustomTypes.hpp" +#include "Logger.hpp" +#include "NitworkClient.hpp" +#include "SceneManager.hpp" + +namespace Menu { + namespace Callback { + + static void getIpAndPort(std::string &ip, std::string &port) + { + Registry::components arrInputBox = + Registry::getInstance().getComponents(); + std::vector ids = + Registry::getInstance().getEntitiesByComponents({typeid(Types::InputBox)}); + for (auto id : ids) { + if (arrInputBox[id].name == "ip") { + ip = arrInputBox[id].text; + } + if (arrInputBox[id].name == "port") { + port = arrInputBox[id].text; + } + } + } + + void defaultCallBack() + { + Logger::debug("Clicked"); + } + + void initConnection() + { + std::string ip(""); + std::string port(""); + + getIpAndPort(ip, port); + if (!Nitwork::NitworkClient::getInstance() + .startClient(std::stoi(port.c_str()), ip.c_str(), DEFAULT_THREAD_NB, TICKS)) { + Logger::error("Error network couldn't connect"); + return; + } + Nitwork::NitworkClient::getInstance().addInitMsg(); + Nitwork::NitworkClient::getInstance().addReadyMsg(); + Scene::SceneManager::getInstance().changeScene(Scene::Scene::MAIN_GAME); + } + } // namespace Callback +} // namespace Menu diff --git a/src/Client/Systems/Menu/ButtonCallbacks.hpp b/src/Client/Systems/Menu/ButtonCallbacks.hpp new file mode 100644 index 00000000..e5c9f17b --- /dev/null +++ b/src/Client/Systems/Menu/ButtonCallbacks.hpp @@ -0,0 +1,16 @@ +/* +** EPITECH PROJECT, 2023 +** R-Bus +** File description: +** ButtonCallbacks +*/ + +#pragma once + +namespace Menu { + namespace Callback { + void initConnection(); + + void defaultCallBack(); + } // namespace Callback +} // namespace Menu diff --git a/src/Client/Systems/Menu/CMakeLists.txt b/src/Client/Systems/Menu/CMakeLists.txt new file mode 100644 index 00000000..343ceec4 --- /dev/null +++ b/src/Client/Systems/Menu/CMakeLists.txt @@ -0,0 +1,15 @@ +cmake_minimum_required(VERSION 3.15) + +target_include_directories( + ${PROJECT_NAME_CLIENT} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR} +) + +target_sources( + ${PROJECT_NAME_CLIENT} + PRIVATE + ${CMAKE_CURRENT_SOURCE_DIR}/Menu.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/MenuSystems.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/ButtonCallbacks.cpp +) diff --git a/src/Client/Systems/Menu/Menu.cpp b/src/Client/Systems/Menu/Menu.cpp new file mode 100644 index 00000000..089226dd --- /dev/null +++ b/src/Client/Systems/Menu/Menu.cpp @@ -0,0 +1,188 @@ +/* +** EPITECH PROJECT, 2023 +** R-Bus +** File description: +** Menu +*/ + +#include "Menu.hpp" +#include "ButtonCallbacks.hpp" +#include "CustomTypes.hpp" +#include "Maths.hpp" +#include "NitworkClient.hpp" +#include "Raylib.hpp" +#include "SceneManager.hpp" + +namespace Menu { + // NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables) + MenuBuilder MenuBuilder::_instance = MenuBuilder(); + // NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables) + + constexpr float maxPercent = 100.0F; + + static void initFromSprite(nlohmann::json &elem) + { + Types::SpriteDatas spriteDatas( + Json::getInstance().getDataFromJson(elem, "spritePath"), + Json::getInstance().getDataFromJson(elem, "width"), + Json::getInstance().getDataFromJson(elem, "height"), + FRONTLAYER, + static_cast(FRONT)); + Types::Rect rect = {Types::Rect(Json::getInstance().getDataFromJson(elem, "rect"))}; + nlohmann::basic_json<> animRectData = + Json::getInstance().getDataFromJson>(elem, "animRect"); + Types::AnimRect animRect(rect, animRectData); + Registry::getInstance().getComponents().insertBack(animRect); + Registry::getInstance().getComponents().insertBack(spriteDatas); + Registry::getInstance().getComponents().insertBack(rect); + } + + static void initInputBox(nlohmann::json &elem) + { + std::size_t id = Registry::getInstance().addEntity(); + + Types::Position position(Json::getInstance().getDataFromJson(elem, "position")); + Types::CollisionRect collisionRect( + Json::getInstance().getDataFromJson(elem, "collisionRect")); + Types::FontSize fsz({Json::getInstance().getDataFromJson(elem, "textSize")}); + std::string text = Json::isDataExist(elem, "text") + ? Json::getInstance().getDataFromJson(elem, "text") + : ""; + std::string name = Json::isDataExist(elem, "name") + ? Json::getInstance().getDataFromJson(elem, "name") + : ""; + Raylib::Text textComp(text); + std::size_t maxChar(Json::getInstance().getDataFromJson(elem, "maxChar")); + Types::InputBox inputBox(text, name, maxChar); + auto search = + Types::colorMatchStrings.find(Json::getInstance().getDataFromJson(elem, "color")); + + Raylib::Color color = search != Types::colorMatchStrings.end() + ? Types::colorMatchStrings.at(Json::getInstance().getDataFromJson(elem, "color")) + : Raylib::White; + Registry::getInstance().getComponents().insertBack(color); + + if (!Json::getInstance().isDataExist(elem, "spritePath")) { + Types::RectangleShape rectangle( + {Json::getInstance().getDataFromJson(elem, "width"), + Json::getInstance().getDataFromJson(elem, "height")}); + Registry::getInstance().getComponents().insertBack(rectangle); + Registry::getInstance().setToFrontLayers(id); + } else { + initFromSprite(elem); + } + Registry::getInstance().getComponents().insertBack(fsz); + Registry::getInstance().getComponents().insertBack(textComp); + Registry::getInstance().getComponents().insertBack(inputBox); + Registry::getInstance().getComponents().insertBack(position); + Registry::getInstance().getComponents().insertBack(collisionRect); + } + + static void initButtonFromSprite(nlohmann::json &elem, std::function &callback) + { + nlohmann::basic_json<> animRectData = + Json::getInstance().getDataFromJson>(elem, "animRect"); + Types::Button button(callback); + + Registry::getInstance().addEntity(); + Types::SpriteDatas spriteDatas( + Json::getInstance().getDataFromJson(elem, "spritePath"), + Json::getInstance().getDataFromJson(elem, "width"), + Json::getInstance().getDataFromJson(elem, "height"), + FRONTLAYER, + static_cast(FRONT)); + Types::Rect rect = {Types::Rect(Json::getInstance().getDataFromJson(elem, "rect"))}; + Types::Position position = { + Types::Position(Json::getInstance().getDataFromJson(elem, "position"))}; + Types::CollisionRect collisionRect = {Types::CollisionRect( + Json::getInstance().getDataFromJson(elem, "collisionRect"))}; + Types::AnimRect animRect(rect, animRectData, Types::RectListType::MOVE); + + Registry::getInstance().getComponents().insertBack(position); + Registry::getInstance().getComponents().insertBack(rect); + Registry::getInstance().getComponents().insertBack(animRect); + Registry::getInstance().getComponents().insertBack(collisionRect); + Registry::getInstance().getComponents().insertBack(spriteDatas); + Registry::getInstance().getComponents().insertBack(button); + } + + static void initButtonFromRectangle(nlohmann::json &elem, std::function &callback) + { + std::size_t id = Registry::getInstance().addEntity(); + + Types::Position position = { + Types::Position(Json::getInstance().getDataFromJson(elem, "position"))}; + Types::CollisionRect collisionRect = {Types::CollisionRect( + Json::getInstance().getDataFromJson(elem, "collisionRect"))}; + Types::Button button(callback); + + Types::RectangleShape rectangle( + {static_cast(collisionRect.width), static_cast(collisionRect.height)}); + Registry::getInstance().getComponents().insertBack(rectangle); + Registry::getInstance().getComponents().insertBack(position); + Registry::getInstance().getComponents().insertBack(collisionRect); + Registry::getInstance().getComponents().insertBack(button); + Registry::getInstance().setToFrontLayers(id); + } + + static void initButton(nlohmann::json &elem, std::function &callback) + { + if (Json::isDataExist(elem, "spritePath")) { + initButtonFromSprite(elem, callback); + } else { + initButtonFromRectangle(elem, callback); + } + } + + void MenuBuilder::initMenuEntity(nlohmann::json &elem, std::function callback) + { + switch (Json::getInstance().getDataFromJson(elem, "type")) { + case ObjectType::BUTTON: initButton(elem, callback); break; + case ObjectType::TEXT: break; // no clickable text for now + case ObjectType::INPUT_BOX: initInputBox(elem); break; + default: Logger::error("Object type is undefined, check your json data"); break; + } + } + + bool checkClick(std::size_t &idEntity) + { + std::vector ids = Registry::getInstance().getEntitiesByComponents( + {typeid(Types::CollisionRect), typeid(Types::Position)}); + + for (auto id : ids) { + if (checkIsInsideRect(id)) { + idEntity = id; + return (true); + } + } + return (false); + } + + bool checkIsInsideRect(const std::size_t &id) + { + Registry::components arrCollisionRect = + Registry::getInstance().getComponents(); + Registry::components arrPosition = + Registry::getInstance().getComponents(); + + if (!arrCollisionRect.exist(id) || !arrPosition.exist(id)) { + return (false); + } + Raylib::Rectangle rect( + Maths::intToFloatConservingDecimals(arrPosition[id].x), + Maths::intToFloatConservingDecimals(arrPosition[id].y), + Maths::intToFloatConservingDecimals(arrCollisionRect[id].width), + Maths::intToFloatConservingDecimals(arrCollisionRect[id].height)); + Raylib::Vector2 mousePos(Raylib::getMousePosition().x, Raylib::getMousePosition().y); + + mousePos.x = (mousePos.x * maxPercent) / Raylib::getScreenWidth(); + mousePos.y = (mousePos.y * maxPercent) / Raylib::getScreenHeight(); + + return Raylib::checkCollisionPointRec(mousePos, rect); + } + + MenuBuilder &MenuBuilder::getInstance() + { + return _instance; + } +} // namespace Menu diff --git a/src/Client/Systems/Menu/Menu.hpp b/src/Client/Systems/Menu/Menu.hpp new file mode 100644 index 00000000..aab2fac8 --- /dev/null +++ b/src/Client/Systems/Menu/Menu.hpp @@ -0,0 +1,80 @@ +/* +** EPITECH PROJECT, 2023 +** R-Bus +** File description: +** Menu +*/ + +#pragma once + +#include "ButtonCallbacks.hpp" +#include "Json.hpp" +#include "Registry.hpp" +#include "SystemManagersDirector.hpp" + +namespace Menu { + + // Enum that defines the type of the object you're creating + enum ObjectType { UNDEFINED, BUTTON, TEXT, INPUT_BOX }; + + // Enum serialization to precise in a json what enum you defined with a string + NLOHMANN_JSON_SERIALIZE_ENUM( + ObjectType, + { + {UNDEFINED, nullptr }, + {BUTTON, "button"}, + {TEXT, "text" }, + {INPUT_BOX, "input" }, + }); + + bool checkClick(std::size_t &idEntity); + + bool checkIsInsideRect(const std::size_t &idEntity); + + /** + * @class MenuBuilder + * @brief Singleton class for building and initializing menu entities. + * + * This class provides functions for initializing menu entities from a JSON element. It's designed as a + * Singleton, meaning there should only be one instance of this class in the application. + */ + class MenuBuilder { + public: + /** + * @brief Returns the single instance of the MenuBuilder class. + * + * This function ensures that only one instance of the MenuBuilder class exists. + * If the instance doesn't already exist, it's created. + * + * @return Reference to the singleton instance of the MenuBuilder. + */ + static MenuBuilder &getInstance(); + + /** + * @brief Initializes a menu entity from a JSON element. + * + * This function sets up a menu entity using the provided JSON element and + * an optional callback function. If no callback is provided, a default callback is used. + * + * @param elem The JSON element from which the menu entity will be initialized. + * @param callback Optional callback function for the menu entity. Defaults to + * Menu::Callback::defaultCallBack. + */ + void initMenuEntity( + nlohmann::json &elem, + std::function callback = Menu::Callback::defaultCallBack); + + private: + MenuBuilder() = default; + ~MenuBuilder() = default; + + /** + * @brief Singleton instance of the MenuBuilder class. + * + * This static member holds the only instance of the MenuBuilder class. + */ + // NOLINTBEGIN(cppcoreguidelines-avoid-non-const-global-variables) + static MenuBuilder _instance; + // NOLINTEND(cppcoreguidelines-avoid-non-const-global-variables) + }; +} // namespace Menu diff --git a/src/Client/Systems/Menu/MenuSystems.cpp b/src/Client/Systems/Menu/MenuSystems.cpp new file mode 100644 index 00000000..b2afe1a8 --- /dev/null +++ b/src/Client/Systems/Menu/MenuSystems.cpp @@ -0,0 +1,192 @@ +/* +** EPITECH PROJECT, 2023 +** R-Bus +** File description: +** Menu +*/ + +#include "MenuSystems.hpp" +#include "CustomTypes.hpp" +#include "Maths.hpp" +#include "Menu.hpp" +#include "SceneManager.hpp" + +namespace Systems { + namespace Menu { + + constexpr float maxPercent = 100.0F; + + static void setAllInputBoxFalse() + { + Registry::components arrInputBox = + Registry::getInstance().getComponents(); + std::vector ids = + Registry::getInstance().getEntitiesByComponents({typeid(Types::InputBox)}); + + for (auto id : ids) { + if (arrInputBox[id].selected) { + arrInputBox[id].selected = false; + } + } + } + + static void setInputBoxSelected(const std::size_t &id) + { + Registry::components arrInputBox = + Registry::getInstance().getComponents(); + + setAllInputBoxFalse(); + if (arrInputBox.exist(id)) { + arrInputBox[id].selected = true; + } + } + + static void insertText(std::size_t id, Registry::components &arrInputBox) + { + Registry::components arrText = + Registry::getInstance().getComponents(); + int key = Raylib::getCharPressed(); + + if ((key >= ' ') && (key <= '}') && (arrInputBox[id].text.size() < arrInputBox[id].maxChar)) { + arrInputBox[id].text += static_cast(key); + arrText[id].setCurrentText(arrInputBox[id].text); + } + } + + void checkTextInput(std::size_t /*unused*/, std::size_t /*unused*/) + { + Registry::components arrInputBox = + Registry::getInstance().getComponents(); + std::vector ids = Registry::getInstance().getEntitiesByComponents( + {typeid(Types::InputBox), typeid(Raylib::Text)}); + + for (auto id : ids) { + if (arrInputBox[id].selected == true) { + insertText(id, arrInputBox); + } + } + } + + void manageInputBox(std::size_t, std::size_t) + { + std::size_t idEntity = 0; + + if (Raylib::isMouseButtonPressed(Raylib::MouseButton::MOUSE_BTN_LEFT)) { + if (!::Menu::checkClick(idEntity)) { + setAllInputBoxFalse(); + return; + } + setInputBoxSelected(idEntity); + } + } + + static void deleteInputBoxChar(std::size_t id, Registry::components &arrInputBox) + { + Registry::components arrText = + Registry::getInstance().getComponents(); + + if (arrInputBox[id].text.size() > 0) { + arrInputBox[id].text.pop_back(); + arrText[id].setCurrentText(arrInputBox[id].text); + } + } + + void checkInputDeletion(std::size_t, std::size_t) + { + Registry::components arrInputBox = + Registry::getInstance().getComponents(); + std::vector ids = Registry::getInstance().getEntitiesByComponents( + {typeid(Types::InputBox), typeid(Raylib::Text)}); + + for (auto id : ids) { + if (arrInputBox[id].selected && Raylib::isKeyPressed(Raylib::KeyboardKey::KB_BACKSPACE)) { + deleteInputBoxChar(id, arrInputBox); + } + } + } + + void hoverInputBox(std::size_t /*unused*/, std::size_t /*unused*/) + { + Registry::components arrAnimRect = + Registry::getInstance().getComponents(); + std::vector ids = Registry::getInstance().getEntitiesByComponents( + {typeid(Types::CollisionRect), typeid(Types::Position), typeid(Types::InputBox)}); + + for (auto id : ids) { + if (::Menu::checkIsInsideRect(id)) { + if (arrAnimRect.exist(id)) { + arrAnimRect[id].changeRectList(Types::RectListType::HOVER); + } + Raylib::setMouseCursor(MOUSE_CURSOR_IBEAM); + return; + } + Raylib::setMouseCursor(MOUSE_CURSOR_DEFAULT); + if (arrAnimRect.exist(id)) { + arrAnimRect[id].changeRectList(Types::RectListType::UNDEFINED); + } + } + } + + void pressButton(std::size_t /*unused*/, std::size_t /*unused*/) + { + Registry::components arrAnimRect = + Registry::getInstance().getComponents(); + Registry::components arrButton = + Registry::getInstance().getComponents(); + std::vector ids = Registry::getInstance().getEntitiesByComponents( + {typeid(Types::CollisionRect), + typeid(Types::AnimRect), + typeid(Types::Position), + typeid(Types::Button)}); + + for (auto id : ids) { + if (::Menu::checkIsInsideRect(id)) { + arrAnimRect[id].changeRectList(Types::RectListType::HOVER); + Raylib::setMouseCursor(MOUSE_CURSOR_ARROW); + if (Raylib::isMouseButtonPressed(Raylib::MouseButton::MOUSE_BTN_LEFT)) { + arrButton[id].callback(); + } + return; + } + arrAnimRect[id].changeRectList(Types::RectListType::UNDEFINED); + } + Raylib::setMouseCursor(MOUSE_CURSOR_DEFAULT); + } + + void initMenu(std::size_t managerId, std::size_t systemId) + { + if (Scene::SceneManager::getInstance().getCurrentScene() != Scene::Scene::MENU) { + SystemManagersDirector::getInstance().getSystemManager(managerId).removeSystem(systemId); + return; + } + nlohmann::json connectButton = + Json::getInstance().getDataByVector({"menu", "connect"}, JsonType::MENU); + nlohmann::json inputBoxIp = Json::getInstance().getDataByVector({"menu", "ip"}, JsonType::MENU); + nlohmann::json inputBoxHost = + Json::getInstance().getDataByVector({"menu", "host"}, JsonType::MENU); + + try { + ::Menu::MenuBuilder::getInstance().initMenuEntity( + connectButton, + ::Menu::Callback::initConnection); + ::Menu::MenuBuilder::getInstance().initMenuEntity(inputBoxHost); + ::Menu::MenuBuilder::getInstance().initMenuEntity(inputBoxIp); + } catch (std::runtime_error &err) { + Logger::error( + "Counldn't load menu correctly, verify your json data : " + std::string(err.what())); + } + SystemManagersDirector::getInstance().getSystemManager(managerId).removeSystem(systemId); + } + + std::vector> getMenuSystems() + { + return { + initMenu, + pressButton, + manageInputBox, + hoverInputBox, + checkTextInput, + checkInputDeletion}; + } + } // namespace Menu +} // namespace Systems diff --git a/src/Client/Systems/Menu/MenuSystems.hpp b/src/Client/Systems/Menu/MenuSystems.hpp new file mode 100644 index 00000000..975f12c7 --- /dev/null +++ b/src/Client/Systems/Menu/MenuSystems.hpp @@ -0,0 +1,31 @@ +/* +** EPITECH PROJECT, 2023 +** R-Bus +** File description: +** MenuSystems +*/ + +#pragma once + +#include +#include + +namespace Systems { + namespace Menu { + + std::vector> getMenuSystems(); + + void manageInputBox(std::size_t /*unused*/, std::size_t /*unused*/); + + void checkTextInput(std::size_t /*unused*/, std::size_t /*unused*/); + + void checkInputDeletion(std::size_t /*unused*/, std::size_t /*unused*/); + + void initMenu(std::size_t managerId, std::size_t systemId); + + void pressButton(std::size_t /*unused*/, std::size_t /*unused*/); + + void hoverInputBox(std::size_t /*unused*/, std::size_t /*unused*/); + + } // namespace Menu +} // namespace Systems diff --git a/src/ECS/Json.cpp b/src/ECS/Json.cpp index 6d16c436..f47ce98f 100644 --- a/src/ECS/Json.cpp +++ b/src/ECS/Json.cpp @@ -103,14 +103,6 @@ std::vector Json::getDatasFromList(const nlohmann::json &list, c return (datas); } -nlohmann::json &Json::getDataFromJson(nlohmann::json jsonData, const std::string &index) -{ - if (jsonData[index] == nullptr) { - throw std::runtime_error("Json error"); - } - return (jsonData[index]); -} - std::vector Json::getDatasFromList(const nlohmann::json &list) { std::vector datas; diff --git a/src/ECS/Json.hpp b/src/ECS/Json.hpp index d9b8ca01..da97d07e 100644 --- a/src/ECS/Json.hpp +++ b/src/ECS/Json.hpp @@ -16,7 +16,7 @@ extern "C" #include "MessageTypes.h" } -enum class JsonType { DEFAULT_ENEMY, DEFAULT_PLAYER, DEFAULT_PARALLAX, TERMINATOR, WAVE, BULLETS }; +enum class JsonType { DEFAULT_ENEMY, DEFAULT_PLAYER, DEFAULT_PARALLAX, TERMINATOR, WAVE, BULLETS, MENU }; const std::unordered_map messageTypes = { {CLASSIC_ENEMY, JsonType::DEFAULT_ENEMY}, @@ -29,7 +29,8 @@ const std::unordered_map pathToJson = { {JsonType::DEFAULT_PARALLAX, "assets/Json/parallaxData.json"}, {JsonType::TERMINATOR, "assets/Json/terminator.json" }, {JsonType::WAVE, "assets/Json/wave.json" }, - {JsonType::BULLETS, "assets/Json/bullets.json" } + {JsonType::BULLETS, "assets/Json/bullets.json" }, + {JsonType::MENU, "assets/Json/menu.json" } }; class Json { @@ -45,8 +46,6 @@ class Json { std::vector getDatasByJsonType(const std::vector &indexes, JsonType dataType); - nlohmann::json &getDataFromJson(nlohmann::json jsonData, const std::string &index); - static bool isDataExist(nlohmann::json jsonData, const std::string &index); std::vector diff --git a/src/main_client.cpp b/src/main_client.cpp index 3bd93d09..a893d1c4 100644 --- a/src/main_client.cpp +++ b/src/main_client.cpp @@ -13,46 +13,16 @@ constexpr int EXIT_EPITECH = 84; -static bool isNumber(const std::string &str) -{ - return std::all_of(str.begin(), str.end(), ::isdigit); -} - -static bool checkArgs(int ac, const char **av) -{ - if (ac != 3) { - Logger::error("Usage: ./r-type_client "); - return false; - } - const std::vector args(av + 1, av + ac); - if (args[0].empty()) { - Logger::error("Invalid ip"); - return false; - } - if (!isNumber(args[1]) || std::stoi(args[1]) < 0 || std::stoi(args[1]) > 65535) { - Logger::error("Invalid port"); - return false; - } - return true; -} - -int main(int ac, const char **av) +int main(int /*unused*/, const char **av) { #ifndef NDEBUG Registry::getInstance().getLogger().setLogLevel(Logger::LogLevel::Debug); #endif ECS::ResourcesManager::init(av[0]); - if (!checkArgs(ac, av)) { - return EXIT_EPITECH; - } auto &sceneManager = Scene::SceneManager::getInstance(); - if (!Nitwork::NitworkClient::getInstance() - .startClient(std::stoi(av[2]), av[1], DEFAULT_THREAD_NB, TICKS)) { - return EXIT_EPITECH; + int res = sceneManager.run(); + if (Nitwork::NitworkClient::getInstance().isRunning()) { + Nitwork::NitworkClient::getInstance().stop(); } - Nitwork::NitworkClient::getInstance().addInitMsg(); - Nitwork::NitworkClient::getInstance().addReadyMsg(); - int res = sceneManager.run(); - Nitwork::NitworkClient::getInstance().stop(); return res; }