diff --git a/core/CMakeLists.txt b/core/CMakeLists.txt index 2b63a86..95198b9 100644 --- a/core/CMakeLists.txt +++ b/core/CMakeLists.txt @@ -1,8 +1,8 @@ -add_executable(${PROJECT_NAME} +add_executable(arcade main.cpp ) -target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_LIST_DIR}/..) -target_include_directories(${PROJECT_NAME} PUBLIC ${CMAKE_CURRENT_LIST_DIR}/src) +target_include_directories(arcade PUBLIC ${CMAKE_CURRENT_LIST_DIR}/..) +target_include_directories(arcade PUBLIC ${CMAKE_CURRENT_LIST_DIR}/src) add_subdirectory(src) diff --git a/core/main.cpp b/core/main.cpp index 4c9f92b..db25d09 100644 --- a/core/main.cpp +++ b/core/main.cpp @@ -5,6 +5,7 @@ ** main */ +#include "Core.hpp" #include "loader/Loader.hpp" int main(void) @@ -15,6 +16,8 @@ int main(void) loader.loadLibraries("./lib"); std::cout << "Games libraries:" << loader.getGamesLibraries().size() << std::endl; std::cout << "Graphics libraries:" << loader.getGraphicsLibraries().size() << std::endl; + Core core(loader.getGamesLibraries(), loader.getGraphicsLibraries()); + core.run(); } catch (const std::exception &e) { std::cerr << e.what() << std::endl; } diff --git a/core/src/CMakeLists.txt b/core/src/CMakeLists.txt index ea744bc..e2576e8 100644 --- a/core/src/CMakeLists.txt +++ b/core/src/CMakeLists.txt @@ -1,3 +1,8 @@ +target_sources(arcade PRIVATE + Core.cpp + Core.hpp +) + add_subdirectory(exception) add_subdirectory(loader) add_subdirectory(utils) diff --git a/core/src/Core.cpp b/core/src/Core.cpp new file mode 100644 index 0000000..48f4526 --- /dev/null +++ b/core/src/Core.cpp @@ -0,0 +1,402 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Core +*/ + +#include + +#include +#include +#include "Core.hpp" +#include "shared/games/components/IComponent.hpp" + +Core::Core(GameProviders &gameProviders, GraphicsProviders &graphicsProviders) : + _gameProviders(gameProviders), _graphicsProviders(graphicsProviders), + _gameProvider(gameProviders.at(0)), _graphicsProvider(graphicsProviders.at(0)) {} + +Core::~Core() {} + +void Core::_initGame() +{ + this->_game = this->_gameProvider->createInstance(); +} + +void Core::_initWindow() +{ + auto gameManifest = this->_game->getManifest(); + IWindow::WindowInitProps windowInitProps { + this->_game->getSize(), + IWindow::WINDOWED, + this->_game->getFps(), + gameManifest.name, + gameManifest.iconPath + }; + + this->_window = this->_graphicsProvider->createWindow(windowInitProps); +} + +std::shared_ptr Core::_getTexture(std::string bin, std::string ascii) +{ + if (this->_textures.find(bin + ascii) == this->_textures.end()) + this->_textures[bin + ascii] = this->_graphicsProvider->createTexture(bin, ascii); + return this->_textures[bin + ascii]; +} + +std::shared_ptr Core::_getFont(std::string path) +{ + if (this->_fonts.find(path) == this->_fonts.end()) + this->_fonts[path] = this->_graphicsProvider->createFont(path); + return this->_fonts[path]; +} + +Core::SoundProps Core::_getSound(std::string path) +{ + if (this->_sounds.find(path) == this->_sounds.end()) { + SoundProps soundProps { + this->_graphicsProvider->createSound(path), + ISound::SoundState::STOP, + components::STOP + }; + soundProps.sound->setState(ISound::SoundState::STOP); + this->_sounds[path] = soundProps; + } + return this->_sounds[path]; +} + +TextureProps Core::_getTextureEntity(std::shared_ptr texture) +{ + auto textureProps = texture->getTextureProps(); + TextureProps entityTextureProps { + this->_getTexture(textureProps.sources.bin, textureProps.sources.ascii), + textureProps.sources.binTileSize, + textureProps.origin, + texture->getSize(), + texture->getPosition() + }; + + return entityTextureProps; +} + +TextProps Core::_getTextEntity(std::shared_ptr text) +{ + auto textProps = text->getTextProps(); + TextProps entityTextProps { + this->_getFont(textProps.font.path), + textProps.font.size, + textProps.content, + static_cast(textProps.align), + static_cast(textProps.verticalAlign), + textProps.color, + text->getSize(), + text->getPosition() + }; + + return entityTextProps; +} + +void Core::_renderTextureProps(std::map> &textures, std::map>::iterator &texturePropsIt) +{ + if (texturePropsIt == textures.end()) + return; + for (auto &textureProps : texturePropsIt->second) + this->_window->render(textureProps); + texturePropsIt++; +} + +void Core::_renderTextProps(std::map> &texts, std::map>::iterator &textPropsIt) +{ + if (textPropsIt == texts.end()) + return; + for (auto &textureProps : textPropsIt->second) + this->_window->render(textureProps); + textPropsIt++; +} + +void Core::_renderProps(std::map> &textures, std::map> &texts) +{ + auto textPropsIt = texts.begin(); + auto texturePropsIt = textures.begin(); + + while (texturePropsIt != textures.end() || textPropsIt != texts.end()) { + if (textPropsIt != texts.end()) { + if (texturePropsIt->first <= textPropsIt->first) + this->_renderTextureProps(textures, texturePropsIt); + } else { + this->_renderTextureProps(textures, texturePropsIt); + } + if (texturePropsIt != textures.end()) { + if (textPropsIt->first <= texturePropsIt->first) + this->_renderTextProps(texts, textPropsIt); + } else { + this->_renderTextProps(texts, textPropsIt); + } + } +} + +void Core::_renderEntities() +{ + std::map> entitiesTextureProps; + std::map> entitiesTextProps; + + for (auto &entity : this->_gameEntities) { + auto components = entity->getComponents(); + for (auto &component : components) { + if (component->getType() == components::TEXTURE) { + auto texture = std::dynamic_pointer_cast(component); + unsigned int index = texture->getZIndex(); + entitiesTextureProps[index].push_back(this->_getTextureEntity(texture)); + } + if (component->getType() == components::TEXT) { + auto texture = std::dynamic_pointer_cast(component); + unsigned int index = texture->getZIndex(); + entitiesTextProps[index].push_back(this->_getTextEntity(texture)); + } + } + } + this->_window->clear(); + this->_renderProps(entitiesTextureProps, entitiesTextProps); + this->_window->display(); +} + +components::IKeyboardComponent::KeyData Core::_convertKeyPressData(events::IKeyEvent::KeyType type, events::IKeyEvent::KeyCode code) +{ + components::IKeyboardComponent::KeyData keyCodeData; + + if (type == events::IKeyEvent::CHAR) { + keyCodeData.code.character = code.character; + keyCodeData.type = components::IKeyboardComponent::CHAR; + } else if (type == events::IKeyEvent::CONTROL) { + keyCodeData.code.control = static_cast(code.control); + keyCodeData.type = components::IKeyboardComponent::CONTROL; + } else if (type == events::IKeyEvent::ARROW) { + keyCodeData.code.arrow = static_cast(code.arrow); + keyCodeData.type = components::IKeyboardComponent::ARROW; + } else if (type == events::IKeyEvent::FUNC) { + keyCodeData.code.func = code.func; + keyCodeData.type = components::IKeyboardComponent::FUNC; + } + return keyCodeData; +} + +void Core::_preventWindowClose(std::vector events) +{ + for (auto &event : events) { + auto type = event->getType(); + if (type == events::WINDOW_CLOSE) + this->_handleWindowClose(); + } +} + +void Core::_handleKeyPress(std::shared_ptr &keyEvent, std::shared_ptr &keyboard) +{ + auto keyCode = keyEvent->getKeyCode(); + auto keyType = keyEvent->getKeyType(); + auto keyCodeData = this->_convertKeyPressData(keyType, keyCode); + + keyboard->onKeyPress(this->_game, keyCodeData); +} + +void Core::_handleKeyRelease(std::shared_ptr &keyEvent, std::shared_ptr &keyboard) +{ + auto keyCode = keyEvent->getKeyCode(); + auto keyType = keyEvent->getKeyType(); + auto keyCodeData = this->_convertKeyPressData(keyType, keyCode); + + keyboard->onKeyRelease(this->_game, keyCodeData); +} + +void Core::_handleMouseButtonPress(std::shared_ptr &event, std::shared_ptr &component) +{ + auto button = event->getButton(); + auto mousePosition = event->getPosition(); + auto entityPosition = component->getPosition(); + auto entitySize = component->getSize(); + + if (mousePosition.x >= entityPosition.x && mousePosition.x <= entityPosition.x + entitySize.x && + mousePosition.y >= entityPosition.y && mousePosition.y <= entityPosition.y + entitySize.y) + component->onMousePress(this->_game); +} + +void Core::_handleMouseButtonRelease(std::shared_ptr &event, std::shared_ptr &component) +{ + auto button = event->getButton(); + auto mousePosition = event->getPosition(); + auto entityPosition = component->getPosition(); + auto entitySize = component->getSize(); + + if (mousePosition.x >= entityPosition.x && mousePosition.x <= entityPosition.x + entitySize.x && + mousePosition.y >= entityPosition.y && mousePosition.y <= entityPosition.y + entitySize.y) + component->onMouseRelease(this->_game); +} + +void Core::_handleMouseMove(std::shared_ptr &event, std::shared_ptr &component) +{ + auto mousePosition = event->getPosition(); + auto entityPosition = component->getPosition(); + auto entitySize = component->getSize(); + + if (mousePosition.x >= entityPosition.x && mousePosition.x <= entityPosition.x + entitySize.x && + mousePosition.y >= entityPosition.y && mousePosition.y <= entityPosition.y + entitySize.y) + component->onMouseHover(this->_game); +} + +void Core::_handleWindowClose() +{ + this->_window->close(); +} + +void Core::_handleWindowResize() +{ + std::cout << "Window resized" << std::endl; +} + +void Core::_handleKeyboardEvents(std::vector &events, std::shared_ptr &component) +{ + for (auto &event : events) { + auto type = event->getType(); + if (type == events::KEY_PRESS) { + auto keyEvent = std::dynamic_pointer_cast(event); + this->_handleKeyPress(keyEvent, component); + } + if (type == events::KEY_RELEASE) { + auto keyEvent = std::dynamic_pointer_cast(event); + this->_handleKeyRelease(keyEvent, component); + } + } +} + +void Core::_handleDisplayableEvents(std::vector &events, std::shared_ptr &component) +{ + for (auto &event : events) { + auto type = event->getType(); + if (type == events::MOUSE_BTN_PRESS) { + auto mouseButtonEvent = std::dynamic_pointer_cast(event); + this->_handleMouseButtonPress(mouseButtonEvent, component); + } + if (type == events::MOUSE_BTN_RELEASE) { + auto mouseButtonEvent = std::dynamic_pointer_cast(event); + this->_handleMouseButtonRelease(mouseButtonEvent, component); + } + if (type == events::MOUSE_MOVE) { + auto mouseEvent = std::dynamic_pointer_cast(event); + this->_handleMouseMove(mouseEvent, component); + } + } +} + +void Core::_handleCollisions(std::shared_ptr &component, std::shared_ptr &target) +{ + auto componentPosition = component->getPosition(); + auto componentSize = component->getSize(); + auto targetPosition = target->getPosition(); + auto targetSize = target->getSize(); + + if (componentPosition.x < targetPosition.x + targetSize.x && + componentPosition.x + componentSize.x > targetPosition.x && + componentPosition.y < targetPosition.y + targetSize.y && + componentPosition.y + componentSize.y > targetPosition.y) + component->onCollide(this->_game, target); +} + +void Core::_handleCollidableComponents(std::shared_ptr &component) +{ + for (auto &entity : this->_gameEntities) { + auto components = entity->getComponents(); + for (auto &entityComponent : components) { + if (entityComponent->getType() == components::COLLIDABLE) { + auto collidable = std::dynamic_pointer_cast(entityComponent); + this->_handleCollisions(component, collidable); + } + } + } +} + +void Core::_handleSoundComponent(std::shared_ptr &gameSound) +{ + auto gameSoundPath = gameSound->getPath(); + auto sound = this->_getSound(gameSoundPath); + + auto gameSoundState = gameSound->getState(); + auto gameSoundVolume = gameSound->getVolume(); + auto gameSoundLoop = gameSound->getLoop(); + auto graphicSoundState = sound.sound->getState(); + auto graphicSoundVolume = sound.sound->getVolume(); + auto graphicSoundLoop = sound.sound->getLoopState(); + + if (gameSoundState != sound.previousGameState) { + if (gameSoundState == components::PLAY) + sound.sound->setState(ISound::SoundState::PLAY); + if (gameSoundState == components::PAUSE) + sound.sound->setState(ISound::SoundState::PAUSE); + if (gameSoundState == components::STOP) + sound.sound->setState(ISound::SoundState::STOP); + sound.previousGameState = gameSoundState; + } + if (graphicSoundState != sound.previousGraphicState) { + if (graphicSoundState == ISound::SoundState::PLAY) + gameSound->onStateChange(this->_game, components::PLAY); + if (graphicSoundState == ISound::SoundState::PAUSE) + gameSound->onStateChange(this->_game, components::PAUSE); + if (graphicSoundState == ISound::SoundState::STOP) + gameSound->onStateChange(this->_game, components::STOP); + } + if (gameSoundVolume != graphicSoundVolume) + sound.sound->setVolume(gameSoundVolume); + if (gameSoundLoop != graphicSoundLoop) + sound.sound->setLoopState(gameSoundLoop); +} + +void Core::_handleComponentEvents(std::vector &events, std::shared_ptr &component) +{ + auto type = component->getType(); + + if (type == components::KEYBOARD) { + auto keyboard = std::dynamic_pointer_cast(component); + this->_handleKeyboardEvents(events, keyboard); + } + if (type == components::TEXT || type == components::TEXTURE) { + auto displayable = std::dynamic_pointer_cast(component); + this->_handleDisplayableEvents(events, displayable); + } + if (type == components::COLLIDABLE) { + auto collidable = std::dynamic_pointer_cast(component); + this->_handleCollidableComponents(collidable); + } + if (type == components::SOUND) { + auto sound = std::dynamic_pointer_cast(component); + this->_handleSoundComponent(sound); + } +} + +void Core::_handleEvents() +{ + auto gameEvents = this->_window->getEvents(); + + this->_preventWindowClose(gameEvents); + for (auto &entity : this->_gameEntities) { + auto components = entity->getComponents(); + for (auto &component : components) { + this->_handleComponentEvents(gameEvents, component); + } + } +} + +void Core::run() +{ + auto previousTime = std::chrono::high_resolution_clock::now(); + + this->_initGame(); + this->_initWindow(); + while (this->_window->isOpen()) { + auto currentTime = std::chrono::high_resolution_clock::now(); + auto deltaTime = std::chrono::duration_cast(previousTime - currentTime); + previousTime = currentTime; + + this->_game->compute(deltaTime); + this->_gameEntities = this->_game->getEntities(); + this->_handleEvents(); + this->_renderEntities(); + } +} diff --git a/core/src/Core.hpp b/core/src/Core.hpp new file mode 100644 index 0000000..bcab8cc --- /dev/null +++ b/core/src/Core.hpp @@ -0,0 +1,273 @@ +/* +** EPITECH PROJECT, 2024 +** arcade +** File description: +** Core +*/ + +#pragma once + +#include +#include "types/Providers.hpp" +#include "shared/graphics/ISound.hpp" +#include "shared/graphics/events/IKeyEvent.hpp" +#include "shared/graphics/events/IMouseEvent.hpp" +#include "shared/graphics/events/IMouseButtonEvent.hpp" +#include "shared/games/components/ITextComponent.hpp" +#include "shared/games/components/ITextureComponent.hpp" +#include "shared/games/components/IKeyboardComponent.hpp" +#include "shared/games/components/IDisplayableComponent.hpp" +#include "shared/games/components/ICollidableComponent.hpp" +#include "shared/games/components/ISoundComponent.hpp" + +using namespace shared::graphics; +using namespace shared::games; + +class Core { + public: + Core(GameProviders &gameProviders, GraphicsProviders &graphicsProviders); + ~Core(); + + /** + * @brief Run the core + * + */ + void run(); + + private: + + typedef struct { + std::shared_ptr sound; + ISound::SoundState previousGraphicState; + components::SoundState previousGameState; + } SoundProps; + + std::shared_ptr _game; + std::shared_ptr _window; + std::shared_ptr &_gameProvider; + std::shared_ptr &_graphicsProvider; + std::map> _fonts; + std::map> _textures; + std::map _sounds; + GameProviders &_gameProviders; + GraphicsProviders &_graphicsProviders; + entity::EntitiesMap _gameEntities; + + /** + * @brief Initialize the window + * + */ + void _initWindow(); + + /** + * @brief Initialize the game + * + */ + void _initGame(); + + /** + * @brief Render all entities + * + */ + void _renderEntities(); + + /** + * @brief Get a texture + * + * @param bin Path to the binary file + * @param ascii Path to the ascii file + * @return The correct texture + */ + std::shared_ptr _getTexture(std::string bin, std::string ascii); + + /** + * @brief Get a font + * + * @param path Path to the font file + * @return The correct font + */ + std::shared_ptr _getFont(std::string path); + + /** + * @brief Get a sound + * + * @param path Path to the sound file + * @return The correct sound + */ + SoundProps _getSound(std::string path); + + /** + * @brief Get the texture entity + * + * @param texture The texture component + * @return The texture entity + */ + TextureProps _getTextureEntity(std::shared_ptr texture); + + /** + * @brief Get the text entity + * + * @param text The text component + * @return The text entity + */ + TextProps _getTextEntity(std::shared_ptr text); + + /** + * @brief Render the props + * + * @param textures The textures + * @param texts The texts + */ + void _renderProps(std::map> &textures, std::map> &texts); + + /** + * @brief Render the texture props + * + * @param textures The textures + * @param texturePropsIt The iterator + */ + void _renderTextureProps(std::map> &textures, std::map>::iterator &texturePropsIt); + + /** + * @brief Render the text props + * + * @param texts The texts + * @param textPropsIt The iterator + */ + void _renderTextProps(std::map> &texts, std::map>::iterator &textPropsIt); + + /** + * @brief Handle the events + * + */ + void _handleEvents(); + + /** + * @brief Handle the component events + * + * @param events Events to handle + * @param component The component + */ + void _handleComponentEvents(std::vector &events, std::shared_ptr &component); + + /** + * @brief Handle the keyboard events + * + * @param events Events to handle + * @param component The keyboard component + */ + void _handleKeyboardEvents(std::vector &events, std::shared_ptr &component); + + /** + * @brief Handle the displayable events + * + * @param events Events to handle + * @param component The displayable component + */ + void _handleDisplayableEvents(std::vector &events, std::shared_ptr &component); + + /** + * @brief Handle the collidable events + * + * @param events Events to handle + * @param component The collidable component + */ + void _handleCollidableComponents(std::shared_ptr &component); + + /** + * @brief Handle the collisions + * + * @param component The collidable component + * @param target The target collidable component + */ + void _handleCollisions(std::shared_ptr &component, std::shared_ptr &target); + + /** + * @brief Handle the key press event + * + * @param event The key event + * @param component The keyboard component + */ + void _handleKeyPress(std::shared_ptr &event, std::shared_ptr &component); + + /** + * @brief Handle the key release event + * + * @param event The key event + * @param component The keyboard component + */ + void _handleKeyRelease(std::shared_ptr &event, std::shared_ptr &component); + + /** + * @brief Handle the mouse button press event + * + * @param event The mouse button event + * @param component The displayable component + */ + void _handleMouseButtonPress(std::shared_ptr &event, std::shared_ptr &component); + + /** + * @brief Handle the mouse button release event + * + * @param event The mouse button event + * @param component The displayable component + */ + void _handleMouseButtonRelease(std::shared_ptr &event, std::shared_ptr &component); + + /** + * @brief Handle the mouse move event + * + * @param event The mouse event + * @param component The displayable component + */ + void _handleMouseMove(std::shared_ptr &event, std::shared_ptr &component); + + /** + * @brief Handle the window close event + * + */ + void _handleWindowClose(); + + /** + * @brief Handle the window resize event + * + */ + void _handleWindowResize(); + + /** + * @brief Prevent the window from closing + * + * @param events The events + */ + void _preventWindowClose(std::vector events); + + /** + * @brief Handle the key press event + * + * @param event The key event + */ + void _handleKeyPress(std::shared_ptr &event); + + /** + * @brief Handle the key release event + * + * @param event The key event + */ + void _handleKeyRelease(std::shared_ptr &event); + + /** + * @brief Convert the key press data + * + * @param type The type of the key + * @param code The code of the key + * @return The converted key press data + */ + components::IKeyboardComponent::KeyData _convertKeyPressData(events::IKeyEvent::KeyType type, events::IKeyEvent::KeyCode code); + + /** + * @brief Handle the mouse button press event + * + * @param event The mouse button event + */ + void _handleSoundComponent(std::shared_ptr &component); +}; diff --git a/core/src/exception/CMakeLists.txt b/core/src/exception/CMakeLists.txt index 7f3f3dc..36668bd 100644 --- a/core/src/exception/CMakeLists.txt +++ b/core/src/exception/CMakeLists.txt @@ -1,3 +1,4 @@ -target_sources(${CMAKE_PROJECT_NAME} PRIVATE +target_sources(arcade PRIVATE ArcadeError.cpp + ArcadeError.hpp ) diff --git a/core/src/loader/CMakeLists.txt b/core/src/loader/CMakeLists.txt index 99592b3..65d16a2 100644 --- a/core/src/loader/CMakeLists.txt +++ b/core/src/loader/CMakeLists.txt @@ -1,3 +1,4 @@ -target_sources(${CMAKE_PROJECT_NAME} PRIVATE +target_sources(arcade PRIVATE Loader.cpp + Loader.hpp ) diff --git a/core/src/loader/Loader.cpp b/core/src/loader/Loader.cpp index 04c7e33..6ad23e5 100644 --- a/core/src/loader/Loader.cpp +++ b/core/src/loader/Loader.cpp @@ -56,10 +56,10 @@ void Loader::loadLibraries(std::string path) { } } -const GameProviders &Loader::getGamesLibraries() const { +GameProviders &Loader::getGamesLibraries() { return this->_gamesLibraries; } -const GraphicsProviders &Loader::getGraphicsLibraries() const { +GraphicsProviders &Loader::getGraphicsLibraries() { return this->_graphicsLibraries; } diff --git a/core/src/loader/Loader.hpp b/core/src/loader/Loader.hpp index 8dd8adc..9bcc4b9 100644 --- a/core/src/loader/Loader.hpp +++ b/core/src/loader/Loader.hpp @@ -39,13 +39,13 @@ class Loader { * @brief Get all games libraries * @return Loaded games libraries */ - const GameProviders &getGamesLibraries() const; + GameProviders &getGamesLibraries(); /** * @brief Get all graphics libraries * @return Loaded graphics libraries */ - const GraphicsProviders &getGraphicsLibraries() const; + GraphicsProviders &getGraphicsLibraries(); private: const std::string _path; diff --git a/core/src/types/CMakeLists.txt b/core/src/types/CMakeLists.txt new file mode 100644 index 0000000..3904d4b --- /dev/null +++ b/core/src/types/CMakeLists.txt @@ -0,0 +1,3 @@ +target_sources(arcade PRIVATE + Providers.hpp +) diff --git a/core/src/types/Providers.hpp b/core/src/types/Providers.hpp index c40fb9e..518f976 100644 --- a/core/src/types/Providers.hpp +++ b/core/src/types/Providers.hpp @@ -9,5 +9,5 @@ #include "shared/types/Libraries.hpp" -typedef std::vector> GameProviders; -typedef std::vector> GraphicsProviders; +typedef std::vector> GameProviders; +typedef std::vector> GraphicsProviders; diff --git a/core/src/utils/DLLoader/CMakeLists.txt b/core/src/utils/DLLoader/CMakeLists.txt index 00db786..7b85e37 100644 --- a/core/src/utils/DLLoader/CMakeLists.txt +++ b/core/src/utils/DLLoader/CMakeLists.txt @@ -1,3 +1,3 @@ -target_sources(${CMAKE_PROJECT_NAME} PRIVATE +target_sources(arcade PRIVATE DLLoader.cpp )