diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b7bc5e5c..f24a0564 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,7 +19,7 @@ jobs: run: | mkdir build && cd build cmake .. - cmake --build . -t wal_tests + cmake --build . -t unit_tests - name: Run tests run: | - ./build/lib/wal/wal_tests + ./build/unit_tests diff --git a/CMakeLists.txt b/CMakeLists.txt index 8960730e..3c6cf9dd 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -9,8 +9,40 @@ include_directories(bomberman lib/wal/sources) add_subdirectory(${PROJECT_SOURCE_DIR}/lib/wal) add_subdirectory(${PROJECT_SOURCE_DIR}/lib/Ray) -add_executable(bomberman - sources/main.cpp +set(SOURCES + sources/Models/GameState.hpp + sources/Runner/Runner.cpp + sources/Runner/Runner.hpp + sources/Component/Position/PositionComponent.cpp + sources/Component/Position/PositionComponent.hpp + sources/Component/Movable/MovableComponent.cpp + sources/Component/Movable/MovableComponent.hpp + sources/System/Movable/MovableSystem.hpp + sources/System/Movable/MovableSystem.cpp + sources/Models/Vector3.hpp ) -target_link_libraries(bomberman wal ray) \ No newline at end of file +add_executable(bomberman + sources/main.cpp + ${SOURCES} +) +target_include_directories(bomberman PUBLIC sources) +target_link_libraries(bomberman PUBLIC wal ray) + + +add_executable(unit_tests EXCLUDE_FROM_ALL + ${SOURCES} + tests/EntityTests.cpp + tests/MainTest.cpp + tests/EngineTests.cpp + tests/CallbackTest.cpp +) +target_include_directories(unit_tests PUBLIC sources) +target_link_libraries(unit_tests PUBLIC wal ray) + +find_package(Catch2 QUIET) +if (NOT Catch2_FOUND) + set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/lib/catch2) + find_package(Catch2 REQUIRED) +endif() +target_link_libraries(unit_tests PRIVATE Catch2::Catch2) diff --git a/lib/wal/CMakeLists.txt b/lib/wal/CMakeLists.txt index fcebfa75..41a455d0 100644 --- a/lib/wal/CMakeLists.txt +++ b/lib/wal/CMakeLists.txt @@ -15,32 +15,8 @@ add_library(wal sources/Exception/WalError.hpp sources/Entity/Entity.cpp sources/Component/Component.cpp - sources/Component/Position/PositionComponent.cpp - sources/Component/Position/PositionComponent.hpp - sources/Models/Vector3.hpp - sources/Component/Movable/MovableComponent.cpp - sources/Component/Movable/MovableComponent.hpp - sources/System/Movable/MovableSystem.cpp - sources/System/Movable/MovableSystem.hpp sources/System/System.cpp sources/Models/Callback.hpp ) -target_include_directories(wal PUBLIC sources) - -add_executable(wal_tests EXCLUDE_FROM_ALL - tests/EntityTests.cpp - tests/MainTest.cpp - tests/EngineTests.cpp - tests/CallbackTest.cpp -) - -target_link_libraries(wal_tests PRIVATE wal) - -find_package(Catch2 QUIET) -if (NOT Catch2_FOUND) - set(CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/../catch2) - find_package(Catch2 REQUIRED) -endif() - -target_link_libraries(wal_tests PRIVATE Catch2::Catch2) +target_include_directories(wal PUBLIC sources) \ No newline at end of file diff --git a/lib/wal/sources/Models/Callback.hpp b/lib/wal/sources/Models/Callback.hpp index 9cce38cd..334d39a7 100644 --- a/lib/wal/sources/Models/Callback.hpp +++ b/lib/wal/sources/Models/Callback.hpp @@ -50,5 +50,11 @@ namespace WAL ~Callback() = default; //! @brief A default assignment operator Callback &operator=(const Callback &) = default; + + //! @brief Implicitly transform a function into a callback. + Callback(std::function callback) // NOLINT(google-explicit-constructor) + { + this->addCallback(callback); + } }; } \ No newline at end of file diff --git a/lib/wal/sources/Scene/SceneManager.hpp b/lib/wal/sources/Scene/SceneManager.hpp deleted file mode 100644 index a0f017db..00000000 --- a/lib/wal/sources/Scene/SceneManager.hpp +++ /dev/null @@ -1,43 +0,0 @@ -// -// Created by Zoe Roux on 2021-05-14. -// - - -#pragma once - -#include -#include "Scene/Scene.hpp" - -namespace WAL -{ - //! @brief A class to manage scenes - class SceneManager - { - private: - std::deque _scenes = {}; - public: - //! @brief Add a scene to the container and move to it. - //! @return The manager instance used to call this function is returned. This allow method chaining. - SceneManager &addScene(Scene &&scene); - - //! @brief Add a scene before the current scene. This could be useful for lobbies or scene where the next scene can be constructed. - //! @return The manager instance used to call this function is returned. This allow method chaining. - SceneManager &addBackScene(Scene &&scene); - - //! @brief Get the current scene - Scene &getCurrent(); - - //! @brief Remove the current scene and switch to the previous scene on the stack. - //! @return The manager instance used to call this function is returned. This allow method chaining. - SceneManager &closeCurrent(); - - //! @brief A default constructor - SceneManager() = default; - //! @brief A scene manager is copy constructable - SceneManager(const SceneManager &) = default; - //! @brief A default destructor. - ~SceneManager() = default; - //! @brief A scene manager is assignable - SceneManager &operator=(const SceneManager &) = default; - }; -} diff --git a/lib/wal/sources/Wal.cpp b/lib/wal/sources/Wal.cpp index 45d2caff..126f78dd 100644 --- a/lib/wal/sources/Wal.cpp +++ b/lib/wal/sources/Wal.cpp @@ -12,25 +12,6 @@ namespace WAL { std::chrono::nanoseconds Wal::timestep = 8ms; - void Wal::run() - { - auto lastTick = std::chrono::steady_clock::now(); - std::chrono::nanoseconds fBehind(0); - - while (!this->_shouldClose) { - auto now = std::chrono::steady_clock::now(); - std::chrono::nanoseconds dtime = now - lastTick; - fBehind += dtime; - lastTick = now; - - while (fBehind > Wal::timestep) { - fBehind -= Wal::timestep; - this->_fixedUpdate(); - } - this->_update(dtime); - } - } - void Wal::_update(std::chrono::nanoseconds dtime) { auto &entities = this->_scene.getEntities(); diff --git a/lib/wal/sources/Wal.hpp b/lib/wal/sources/Wal.hpp index f1b61f6f..9f560ac2 100644 --- a/lib/wal/sources/Wal.hpp +++ b/lib/wal/sources/Wal.hpp @@ -8,10 +8,11 @@ #include #include #include -#include +#include "Exception/WalError.hpp" #include "Scene/Scene.hpp" #include "Entity/Entity.hpp" #include "System/System.hpp" +#include "Models/Callback.hpp" namespace WAL { @@ -101,7 +102,40 @@ namespace WAL } //! @brief Start the game loop - void run(); + //! @param callback A callback called after each update of the game. It allow you to update the engine based on a specific game state. (you can also update the game state here) + //! @param state An initial game state. If not specified, it will be defaulted. + //! @tparam T A type used to track your game state. It must be default constructable. + template + void run(const std::function &callback, T state = T()) + { + Callback update(callback); + return this->run(update, state); + } + + //! @brief Start the game loop + //! @param callback A callback called after each update of the game. It allow you to update the engine based on a specific game state. (you can also update the game state here) + //! @param state An initial game state. If not specified, it will be defaulted. + //! @tparam T A type used to track your game state. It must be default constructable. + template + void run(const Callback &callback, T state = T()) + { + auto lastTick = std::chrono::steady_clock::now(); + std::chrono::nanoseconds fBehind(0); + + while (!this->_shouldClose) { + auto now = std::chrono::steady_clock::now(); + std::chrono::nanoseconds dtime = now - lastTick; + fBehind += dtime; + lastTick = now; + + while (fBehind > Wal::timestep) { + fBehind -= Wal::timestep; + this->_fixedUpdate(); + } + this->_update(dtime); + callback(*this, state); + } + } //! @brief A default constructor Wal() = default; diff --git a/lib/wal/sources/Component/Movable/MovableComponent.cpp b/sources/Component/Movable/MovableComponent.cpp similarity index 62% rename from lib/wal/sources/Component/Movable/MovableComponent.cpp rename to sources/Component/Movable/MovableComponent.cpp index a86a69ab..c0e9e52d 100644 --- a/lib/wal/sources/Component/Movable/MovableComponent.cpp +++ b/sources/Component/Movable/MovableComponent.cpp @@ -4,13 +4,13 @@ #include "MovableComponent.hpp" -namespace WAL +namespace Bomberman { - MovableComponent::MovableComponent(Entity &entity) + MovableComponent::MovableComponent(WAL::Entity &entity) : Component(entity) {} - Component *MovableComponent::clone(Entity &entity) const + WAL::Component *MovableComponent::clone(WAL::Entity &entity) const { return new MovableComponent(entity); } diff --git a/lib/wal/sources/Component/Movable/MovableComponent.hpp b/sources/Component/Movable/MovableComponent.hpp similarity index 84% rename from lib/wal/sources/Component/Movable/MovableComponent.hpp rename to sources/Component/Movable/MovableComponent.hpp index 0693121a..2f194378 100644 --- a/lib/wal/sources/Component/Movable/MovableComponent.hpp +++ b/sources/Component/Movable/MovableComponent.hpp @@ -7,10 +7,10 @@ #include "Models/Vector3.hpp" #include "Entity/Entity.hpp" -namespace WAL +namespace Bomberman { //! @brief A component to place on entities that can move or be moved. - class MovableComponent : public Component + class MovableComponent : public WAL::Component { private: //! @brief The acceleration of this entity. @@ -23,10 +23,10 @@ namespace WAL void addForce(Vector3f force); //! @inherit - Component *clone(Entity &entity) const override; + WAL::Component *clone(WAL::Entity &entity) const override; //! @brief Create a new movable component. - explicit MovableComponent(Entity &entity); + explicit MovableComponent(WAL::Entity &entity); //! @brief A movable component is copy constructable. MovableComponent(const MovableComponent &) = default; //! @brief A default destructor diff --git a/lib/wal/sources/Component/Position/PositionComponent.cpp b/sources/Component/Position/PositionComponent.cpp similarity index 61% rename from lib/wal/sources/Component/Position/PositionComponent.cpp rename to sources/Component/Position/PositionComponent.cpp index 1e470254..d992a4a5 100644 --- a/lib/wal/sources/Component/Position/PositionComponent.cpp +++ b/sources/Component/Position/PositionComponent.cpp @@ -4,24 +4,24 @@ #include "PositionComponent.hpp" -namespace WAL +namespace Bomberman { - PositionComponent::PositionComponent(Entity &entity) + PositionComponent::PositionComponent(WAL::Entity &entity) : Component(entity), position() {} - PositionComponent::PositionComponent(Entity &entity, Vector3f pos) + PositionComponent::PositionComponent(WAL::Entity &entity, Vector3f pos) : Component(entity), position(pos) {} - PositionComponent::PositionComponent(Entity &entity, float x, float y, float z) + PositionComponent::PositionComponent(WAL::Entity &entity, float x, float y, float z) : Component(entity), position(x, y, z) {} - Component *PositionComponent::clone(WAL::Entity &entity) const + WAL::Component *PositionComponent::clone(WAL::Entity &entity) const { return new PositionComponent(entity, this->position); } diff --git a/lib/wal/sources/Component/Position/PositionComponent.hpp b/sources/Component/Position/PositionComponent.hpp similarity index 76% rename from lib/wal/sources/Component/Position/PositionComponent.hpp rename to sources/Component/Position/PositionComponent.hpp index 8e11a2e3..18c5faee 100644 --- a/lib/wal/sources/Component/Position/PositionComponent.hpp +++ b/sources/Component/Position/PositionComponent.hpp @@ -7,10 +7,10 @@ #include "Models/Vector3.hpp" #include "Component/Component.hpp" -namespace WAL +namespace Bomberman { //! @brief A basic position component - class PositionComponent : public Component + class PositionComponent : public WAL::Component { public: //! @brief Get the editable position of this entity @@ -24,14 +24,14 @@ namespace WAL float getZ() const; //! @inherit - Component *clone(Entity &entity) const override; + WAL::Component *clone(WAL::Entity &entity) const override; //! @brief Create a new PositionComponent linked to a specific entity - explicit PositionComponent(Entity &entity); + explicit PositionComponent(WAL::Entity &entity); //! @brief Create a new PositionComponent at a certain position - PositionComponent(Entity &entity, Vector3f pos); + PositionComponent(WAL::Entity &entity, Vector3f pos); //! @brief Create a new PositionComponent at a certain position - PositionComponent(Entity &entity, float x, float y, float z); + PositionComponent(WAL::Entity &entity, float x, float y, float z); //! @brief A position component is copy constructable PositionComponent(const PositionComponent &) = default; //! @brief A default destructor diff --git a/sources/Models/GameState.hpp b/sources/Models/GameState.hpp new file mode 100644 index 00000000..7be6b723 --- /dev/null +++ b/sources/Models/GameState.hpp @@ -0,0 +1,31 @@ +// +// Created by Zoe Roux on 5/24/21. +// + + +#pragma once + +#include +#include + + +namespace Bomberman +{ + //! @brief A class representing the current game state. This allow one to retain information between update calls. + class GameState + { + //! @brief The list of scenes available. + enum SceneID + { + MainMenu, + GameScene + }; + + + //! @brief The currently loaded scene + SceneID currentScene = MainMenu; + + //! @brief The list of loaded scenes. + std::unordered_map _loadedScenes = {}; + }; +} \ No newline at end of file diff --git a/lib/wal/sources/Models/Vector3.hpp b/sources/Models/Vector3.hpp similarity index 97% rename from lib/wal/sources/Models/Vector3.hpp rename to sources/Models/Vector3.hpp index 9aa58d10..ab642e94 100644 --- a/lib/wal/sources/Models/Vector3.hpp +++ b/sources/Models/Vector3.hpp @@ -8,7 +8,7 @@ #include #include -namespace WAL +namespace Bomberman { //! @brief A Vector3 data type. (templated to allow any kind of vector3) template @@ -160,7 +160,7 @@ namespace WAL } template -std::ostream &operator<<(std::ostream &s, const WAL::Vector3 &v) +std::ostream &operator<<(std::ostream &s, const Bomberman::Vector3 &v) { s << "Vector3<" << typeid(T).name() << ">("<< v.x << ", " << v.y << ", " << v.z << ")"; return s; diff --git a/sources/Runner/Runner.cpp b/sources/Runner/Runner.cpp new file mode 100644 index 00000000..837831cc --- /dev/null +++ b/sources/Runner/Runner.cpp @@ -0,0 +1,32 @@ +// +// Created by Zoe Roux on 5/24/21. +// + +#include +#include +#include "Runner.hpp" +#include "Models/GameState.hpp" + +namespace Bomberman +{ + void updateState(WAL::Wal &engine, GameState &state) + { + // You can change the scene here or update the game state based on entities values. + + // If you want to keep a scene loaded but not running, store it in the state.loadedScenes. + // If you don't need the scene anymore, remember to remove it from the loadedScene array. + } + + int run() + { + WAL::Wal wal; + + try { + wal.run(updateState); + return 0; + } catch (const std::exception &ex) { + std::cerr << ex.what() << std::endl; + return 1; + } + } +} \ No newline at end of file diff --git a/sources/Runner/Runner.hpp b/sources/Runner/Runner.hpp new file mode 100644 index 00000000..4531039a --- /dev/null +++ b/sources/Runner/Runner.hpp @@ -0,0 +1,12 @@ +// +// Created by Zoe Roux on 5/24/21. +// + +#pragma once + +namespace Bomberman +{ + //! @brief Start the game and run a Bomberman. + //! @return 0 on success, another value on error. + int run(); +} \ No newline at end of file diff --git a/lib/wal/sources/System/Movable/MovableSystem.cpp b/sources/System/Movable/MovableSystem.cpp similarity index 64% rename from lib/wal/sources/System/Movable/MovableSystem.cpp rename to sources/System/Movable/MovableSystem.cpp index 7bd56fb0..d8b88a48 100644 --- a/lib/wal/sources/System/Movable/MovableSystem.cpp +++ b/sources/System/Movable/MovableSystem.cpp @@ -3,11 +3,11 @@ // #include "Component/Position/PositionComponent.hpp" -#include "System/Movable/MovableSystem.hpp" +#include "MovableSystem.hpp" #include "Component/Movable/MovableComponent.hpp" #include "Wal.hpp" -namespace WAL +namespace Bomberman { MovableSystem::MovableSystem() : System({ @@ -16,13 +16,13 @@ namespace WAL }) {} - void MovableSystem::onFixedUpdate(Entity &entity) + void MovableSystem::onFixedUpdate(WAL::Entity &entity) { auto &movable = entity.getComponent(); auto &position = entity.getComponent(); - position.position += movable._velocity * Wal::timestep.count(); - movable._velocity = movable._acceleration * Wal::timestep.count(); + position.position += movable._velocity * WAL::Wal::timestep.count(); + movable._velocity = movable._acceleration * WAL::Wal::timestep.count(); movable._acceleration = Vector3f(); } } \ No newline at end of file diff --git a/lib/wal/sources/System/Movable/MovableSystem.hpp b/sources/System/Movable/MovableSystem.hpp similarity index 83% rename from lib/wal/sources/System/Movable/MovableSystem.hpp rename to sources/System/Movable/MovableSystem.hpp index f7ec3c3c..0bb89652 100644 --- a/lib/wal/sources/System/Movable/MovableSystem.hpp +++ b/sources/System/Movable/MovableSystem.hpp @@ -7,14 +7,14 @@ #include "System/System.hpp" -namespace WAL +namespace Bomberman { //! @brief A system to handle movable entities. This system update velocity based on accelerations and positions based on velocity. - class MovableSystem : public System + class MovableSystem : public WAL::System { public: //! @inherit - void onFixedUpdate(Entity &entity) override; + void onFixedUpdate(WAL::Entity &entity) override; //! @brief A default constructor MovableSystem(); diff --git a/sources/main.cpp b/sources/main.cpp index 1e40b264..d29f7374 100644 --- a/sources/main.cpp +++ b/sources/main.cpp @@ -6,7 +6,10 @@ */ -#include "Wal.hpp" +#include +#include "Runner/Runner.hpp" + +// Dependencies of the demo #include "Camera/Camera3D.hpp" #include "Controllers/Keyboard.hpp" #include "Drawables/2D/Text.hpp" @@ -17,19 +20,19 @@ #include "Vector/Vector3.hpp" #include "Window.hpp" -int main() +int demo() { - + // Initialization //-------------------------------------------------------------------------------------- const int screenWidth = 800; const int screenHeight = 450; RAY::Window &window = RAY::Window::getInstance(screenWidth, screenHeight, "Bidibidibop", FLAG_WINDOW_RESIZABLE); RAY::Camera::Camera3D camera(RAY::Vector3(10.0f, 10.0f, 10.0f), - RAY::Vector3(0.0f, 0.0f, 0.0f), - RAY::Vector3(0.0f, 1.0f, 0.0f), - 45.0f, CAMERA_PERSPECTIVE - ); + RAY::Vector3(0.0f, 0.0f, 0.0f), + RAY::Vector3(0.0f, 1.0f, 0.0f), + 45.0f, CAMERA_PERSPECTIVE + ); RAY::Model model("assets/guy.iqm"); RAY::Texture texture("assets/guytex.png"); RAY::ModelAnimations animations("assets/guy.iqm"); @@ -63,17 +66,17 @@ int main() //---------------------------------------------------------------------------------- window.setDrawingState(RAY::Window::DRAWING); - window.clear(); + window.clear(); - window.useCamera(camera); + window.useCamera(camera); - window.draw(model, position, RAY::Vector3(1.0f, 0.0f, 0.0f), -90.0f, RAY::Vector3( 1.0f, 1.0f, 1.0f )); + window.draw(model, position, RAY::Vector3(1.0f, 0.0f, 0.0f), -90.0f, RAY::Vector3( 1.0f, 1.0f, 1.0f )); - window.draw(grid); + window.draw(grid); - window.unuseCamera(); + window.unuseCamera(); - window.draw(instructionText); + window.draw(instructionText); window.setDrawingState(RAY::Window::IDLE); //---------------------------------------------------------------------------------- @@ -87,3 +90,22 @@ int main() return 0; } + + +void usage(const std::string &bin) +{ + std::cout << "Bomberman." << std::endl + << "\tUsage: " << bin << " [options]" << std::endl + << "Options:" << std::endl + << "\t-h:\tPrint this help message" << std::endl; +} + +int main(int argc, char **argv) +{ + if (argc == 2 && std::string(argv[1]) == "-h") { + usage(argv[0]); + return 1; + } + return demo(); + return Bomberman::run(); +} diff --git a/lib/wal/tests/CallbackTest.cpp b/tests/CallbackTest.cpp similarity index 100% rename from lib/wal/tests/CallbackTest.cpp rename to tests/CallbackTest.cpp diff --git a/lib/wal/tests/EngineTests.cpp b/tests/EngineTests.cpp similarity index 96% rename from lib/wal/tests/EngineTests.cpp rename to tests/EngineTests.cpp index c6074138..8c908dac 100644 --- a/lib/wal/tests/EngineTests.cpp +++ b/tests/EngineTests.cpp @@ -8,6 +8,7 @@ #include using namespace WAL; +using namespace Bomberman; TEST_CASE("Create system", "[Engine][System]") { diff --git a/lib/wal/tests/EntityTests.cpp b/tests/EntityTests.cpp similarity index 97% rename from lib/wal/tests/EntityTests.cpp rename to tests/EntityTests.cpp index 6c6c4edf..3b009cad 100644 --- a/lib/wal/tests/EntityTests.cpp +++ b/tests/EntityTests.cpp @@ -7,6 +7,7 @@ #include using namespace WAL; +using namespace Bomberman; TEST_CASE("Component", "[Entity]") { diff --git a/lib/wal/tests/MainTest.cpp b/tests/MainTest.cpp similarity index 100% rename from lib/wal/tests/MainTest.cpp rename to tests/MainTest.cpp