From 15c4cf103c4da7808b7173581ead22ab7190632d Mon Sep 17 00:00:00 2001 From: JAROWMR Date: Thu, 14 Nov 2024 18:49:17 +0100 Subject: updated test --- src/test/CMakeLists.txt | 1 + 1 file changed, 1 insertion(+) (limited to 'src/test/CMakeLists.txt') diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index 0e4eaed..8618ae6 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -2,5 +2,6 @@ target_sources(test_main PUBLIC dummy.cpp # audio.cpp PhysicsTest.cpp + CollisionTest.cpp ) -- cgit v1.2.3 From 690471c7c4536c074a4dca5aab7cc618d47bfb5f Mon Sep 17 00:00:00 2001 From: JAROWMR Date: Wed, 20 Nov 2024 10:43:32 +0100 Subject: merge with maser --- src/crepe/api/LoopManager.cpp | 6 +- src/crepe/api/LoopManager.h | 5 +- src/crepe/api/Script.h | 9 ++- src/crepe/system/CollisionSystem.cpp | 6 +- src/crepe/system/CollisionSystem.h | 2 - src/example/CMakeLists.txt | 2 +- src/example/collision.cpp | 123 ----------------------------------- src/example/game.cpp | 89 +++++++++++++++++++++++++ src/example/particles.cpp | 43 ------------ src/example/physics.cpp | 24 ------- src/example/rendering.cpp | 4 +- src/test/CMakeLists.txt | 2 - src/test/CollisionTest.cpp | 121 ++++++++++++++++------------------ 13 files changed, 165 insertions(+), 271 deletions(-) delete mode 100644 src/example/collision.cpp create mode 100644 src/example/game.cpp delete mode 100644 src/example/particles.cpp delete mode 100644 src/example/physics.cpp (limited to 'src/test/CMakeLists.txt') diff --git a/src/crepe/api/LoopManager.cpp b/src/crepe/api/LoopManager.cpp index a4bc101..586919d 100644 --- a/src/crepe/api/LoopManager.cpp +++ b/src/crepe/api/LoopManager.cpp @@ -35,10 +35,8 @@ void LoopManager::start() { void LoopManager::set_running(bool running) { this->game_running = running; } void LoopManager::fixed_update() { - PhysicsSystem phys; - phys.update(); - CollisionSystem col; - col.update(); + this->get_system().update(); + this->get_system().update(); } void LoopManager::loop() { diff --git a/src/crepe/api/LoopManager.h b/src/crepe/api/LoopManager.h index f6904be..37f13ac 100644 --- a/src/crepe/api/LoopManager.h +++ b/src/crepe/api/LoopManager.h @@ -4,6 +4,7 @@ #include "../ComponentManager.h" #include "../system/System.h" +#include "api/SceneManager.h" namespace crepe { @@ -71,7 +72,9 @@ private: private: //! Component manager instance ComponentManager component_manager{}; - +public: + //! Scene manager instance + SceneManager scene_manager{component_manager}; private: /** * \brief Collection of System instances diff --git a/src/crepe/api/Script.h b/src/crepe/api/Script.h index 2b70379..939d142 100644 --- a/src/crepe/api/Script.h +++ b/src/crepe/api/Script.h @@ -63,7 +63,14 @@ protected: */ template std::vector> get_components() const; - + + /** + * \brief Gets game object id this script is attached to + * + * \returns game object id + */ + game_object_id_t get_game_object_id() const {return this->game_object_id;}; + protected: // NOTE: Script must have a constructor without arguments so the game programmer doesn't need // to manually add `using Script::Script` to their concrete script class. diff --git a/src/crepe/system/CollisionSystem.cpp b/src/crepe/system/CollisionSystem.cpp index df0ee41..3e73b44 100644 --- a/src/crepe/system/CollisionSystem.cpp +++ b/src/crepe/system/CollisionSystem.cpp @@ -18,11 +18,9 @@ using namespace crepe; -CollisionSystem::CollisionSystem() {} - void CollisionSystem::update() { // Get collider components and keep them seperate - ComponentManager & mgr = ComponentManager::get_instance(); + ComponentManager & mgr = this->component_manager; std::vector> boxcolliders = mgr.get_components_by_type(); std::vector> circlecolliders = mgr.get_components_by_type(); @@ -185,7 +183,7 @@ void CollisionSystem::static_collision_handler(CollisionInfo& info){ } std::vector> CollisionSystem::check_collisions(const std::vector>& boxcolliders, const std::vector>& circlecolliders) { - ComponentManager & mgr = ComponentManager::get_instance(); + ComponentManager & mgr = this->component_manager; std::vector> collisions_ret; // TODO: diff --git a/src/crepe/system/CollisionSystem.h b/src/crepe/system/CollisionSystem.h index 0518b34..d94f6bc 100644 --- a/src/crepe/system/CollisionSystem.h +++ b/src/crepe/system/CollisionSystem.h @@ -70,8 +70,6 @@ public: public: - CollisionSystem(); - //! Updates the collision system by checking for collisions between colliders and handling them. void update() override; diff --git a/src/example/CMakeLists.txt b/src/example/CMakeLists.txt index d2ea926..2facc4d 100644 --- a/src/example/CMakeLists.txt +++ b/src/example/CMakeLists.txt @@ -28,7 +28,7 @@ add_example(proxy) add_example(db) add_example(ecs) add_example(scene_manager) -add_example(collision) +add_example(game) add_example(events) add_example(particles) add_example(gameloop) diff --git a/src/example/collision.cpp b/src/example/collision.cpp deleted file mode 100644 index f51380e..0000000 --- a/src/example/collision.cpp +++ /dev/null @@ -1,123 +0,0 @@ -#include "api/BoxCollider.h" -#include "system/CollisionSystem.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -using namespace crepe; -using namespace std; - -class MyScript : public Script { - static bool oncollision(const CollisionEvent& test) { - std::cout << "test collision: " << test.info.first.collider.game_object_id << std::endl; - return true; - } - void init() { - EventManager::get_instance().subscribe(oncollision, this->parent->game_object_id); - } - void update() { - // Retrieve component from the same GameObject this script is on - - } - - -}; - -int main(int argc, char * argv[]) { - //setup - LoopManager gameloop; - Color color(0, 0, 0, 0); - - double screen_size_width = 640; - double screen_size_height = 480; - double world_collider = 1000; - //define playable world - GameObject World(0, "Name", "Tag", Vector2{screen_size_width/2, screen_size_height/2}, 0, 1); - World.add_component(Rigidbody::Data{ - .mass = 0, - .gravity_scale = 0, - .body_type = Rigidbody::BodyType::STATIC, - .constraints = {0, 0, 0}, - .use_gravity = false, - .bounce = false, - .offset = {0,0} - }); - World.add_component(Vector2{0, 0-(screen_size_height/2+world_collider/2)}, world_collider, world_collider);; // Top - World.add_component(Vector2{0, screen_size_height/2+world_collider/2}, world_collider, world_collider); // Bottom - World.add_component(Vector2{0-(screen_size_width/2+world_collider/2), 0}, world_collider, world_collider); // Left - World.add_component(Vector2{screen_size_width/2+world_collider/2, 0}, world_collider, world_collider); // right - - - GameObject game_object1(1, "Name", "Tag", Vector2{screen_size_width/2, screen_size_height/2}, 0, 1); - game_object1.add_component(Rigidbody::Data{ - .mass = 1, - .gravity_scale = 0.01, - .body_type = Rigidbody::BodyType::DYNAMIC, - .linear_velocity = {1,0}, - .constraints = {0, 0, 0}, - .use_gravity = true, - .bounce = true, - .elastisity = 1, - .offset = {0,0}, - }); - game_object1.add_component(Vector2{0, 0}, 20, 20); - game_object1.add_component().set_script(); - game_object1.add_component( - make_shared("/home/jaro/crepe/asset/texture/green_square.png"), color, - FlipSettings{true, true}); - game_object1.add_component(Color::get_white()); - - - // GameObject game_object2(2, "Name", "Tag", Vector2{20, 470}, 0, 1); - // game_object2.add_component(Rigidbody::Data{ - // .mass = 1, - // .gravity_scale = 1, - // .body_type = Rigidbody::BodyType::DYNAMIC, - // .linear_velocity = {0,0}, - // .constraints = {0, 0, 0}, - // .use_gravity = false, - // .bounce = false, - // .offset = {0,0}, - // }); - // game_object2.add_component(Vector2{0, 0}, 0, 0); - // game_object2.add_component().set_script(); - // game_object2.add_component( - // make_shared("/home/jaro/crepe/asset/texture/red_square.png"), color, - // FlipSettings{true, true}); - - - crepe::ScriptSystem sys; - // Update all scripts. This should result in MyScript::update being called - sys.update(); - - gameloop.start(); - // auto & render = crepe::RenderSystem::get_instance(); - // auto start = std::chrono::steady_clock::now(); - // while (std::chrono::steady_clock::now() - start < std::chrono::seconds(5)) { - // render.update(); - // } - - - return 0; -} diff --git a/src/example/game.cpp b/src/example/game.cpp new file mode 100644 index 0000000..a9f6103 --- /dev/null +++ b/src/example/game.cpp @@ -0,0 +1,89 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace crepe; + +using namespace std; + +class MyScript : public Script { + static bool oncollision(const CollisionEvent& test) { + std::cout << "test collision: " << test.info.first.collider.game_object_id << std::endl; + return true; + } + void init() { + EventManager::get_instance().subscribe(oncollision, this->get_game_object_id()); + } + void update() { + // Retrieve component from the same GameObject this script is on + + } +}; + +class ConcreteScene1 : public Scene { +public: + using Scene::Scene; + + void load_scene() { + ComponentManager & mgr = this->component_manager; + Color color(0, 0, 0, 0); + + double screen_size_width = 640; + double screen_size_height = 480; + double world_collider = 1000; + //define playable world + GameObject world = mgr.new_object("Name", "Tag", Vector2{screen_size_width/2, screen_size_height/2}, 0, 1); + world.add_component(Rigidbody::Data{ + .mass = 0, + .gravity_scale = 0, + .body_type = Rigidbody::BodyType::STATIC, + .constraints = {0, 0, 0}, + .use_gravity = false, + .bounce = false, + .offset = {0,0} + }); + world.add_component(Vector2{0, 0-(screen_size_height/2+world_collider/2)}, world_collider, world_collider);; // Top + world.add_component(Vector2{0, screen_size_height/2+world_collider/2}, world_collider, world_collider); // Bottom + world.add_component(Vector2{0-(screen_size_width/2+world_collider/2), 0}, world_collider, world_collider); // Left + world.add_component(Vector2{screen_size_width/2+world_collider/2, 0}, world_collider, world_collider); // right + + + GameObject game_object1 = mgr.new_object("Name", "Tag", Vector2{screen_size_width/2, screen_size_height/2}, 0, 1); + game_object1.add_component(Rigidbody::Data{ + .mass = 1, + .gravity_scale = 0.01, + .body_type = Rigidbody::BodyType::DYNAMIC, + .linear_velocity = {1,0}, + .constraints = {0, 0, 0}, + .use_gravity = true, + .bounce = true, + .elastisity = 1, + .offset = {0,0}, + }); + game_object1.add_component(Vector2{0, 0}, 20, 20); + game_object1.add_component().set_script(); + game_object1.add_component( + make_shared("/home/jaro/crepe/asset/texture/green_square.png"), color, + FlipSettings{true, true}); + game_object1.add_component(Color::get_white()); + } +}; + +int main(int argc, char * argv[]) { + + LoopManager gameloop; + gameloop.scene_manager.add_scene("scene1"); + gameloop.scene_manager.load_next_scene(); + gameloop.start(); + return 0; +} diff --git a/src/example/particles.cpp b/src/example/particles.cpp deleted file mode 100644 index 3d5f676..0000000 --- a/src/example/particles.cpp +++ /dev/null @@ -1,43 +0,0 @@ -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace crepe; -using namespace std; - -int main(int argc, char * argv[]) { - ComponentManager mgr{}; - GameObject game_object = mgr.new_object("", "", Vector2{0, 0}, 0, 0); - Color color(0, 0, 0, 0); - Sprite test_sprite = game_object.add_component( - make_shared("../asset/texture/img.png"), color, FlipSettings{true, true}); - game_object.add_component(ParticleEmitter::Data{ - .position = {0, 0}, - .max_particles = 100, - .emission_rate = 0, - .min_speed = 0, - .max_speed = 0, - .min_angle = 0, - .max_angle = 0, - .begin_lifespan = 0, - .end_lifespan = 0, - .force_over_time = Vector2{0, 0}, - .boundary{ - .width = 0, - .height = 0, - .offset = Vector2{0, 0}, - .reset_on_exit = false, - }, - .sprite = test_sprite, - }); - - return 0; -} diff --git a/src/example/physics.cpp b/src/example/physics.cpp deleted file mode 100644 index ad663a0..0000000 --- a/src/example/physics.cpp +++ /dev/null @@ -1,24 +0,0 @@ -#include -#include -#include -#include -#include -#include - -using namespace crepe; -using namespace std; - -int main(int argc, char * argv[]) { - ComponentManager mgr{}; - - GameObject game_object = mgr.new_object("Name", "Tag", Vector2{0, 0}, 0, 0); - game_object.add_component(Rigidbody::Data{ - .mass = 1, - .gravity_scale = 1, - .body_type = Rigidbody::BodyType::DYNAMIC, - .constraints = {0, 0, 0}, - .use_gravity = true, - .bounce = false, - }); - return 0; -} diff --git a/src/example/rendering.cpp b/src/example/rendering.cpp index c9e62f1..14ecaa9 100644 --- a/src/example/rendering.cpp +++ b/src/example/rendering.cpp @@ -30,13 +30,13 @@ int main() { // Normal adding components { Color color(0, 0, 0, 0); - obj.add_component(make_shared("../asset/texture/img.png"), color, + obj.add_component(make_shared("/home/jaro/crepe/asset/texture/green_square.png"), color, FlipSettings{false, false}); obj.add_component(Color::get_red()); } { Color color(0, 0, 0, 0); - obj1.add_component(make_shared("../asset/texture/second.png"), color, + obj1.add_component(make_shared("/home/jaro/crepe/asset/texture/green_square.png"), color, FlipSettings{true, true}); } diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index a41d097..f830165 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -1,6 +1,4 @@ target_sources(test_main PUBLIC - dummy.cpp - # audio.cpp CollisionTest.cpp main.cpp PhysicsTest.cpp diff --git a/src/test/CollisionTest.cpp b/src/test/CollisionTest.cpp index 3e43479..83564e1 100644 --- a/src/test/CollisionTest.cpp +++ b/src/test/CollisionTest.cpp @@ -1,83 +1,76 @@ -#include "api/BoxCollider.h" -#include "api/CircleCollider.h" -#include "api/Vector2.h" #include #include #include #include #include -#include +#include #include using namespace std; using namespace std::chrono_literals; using namespace crepe; -class CollisionTest : public ::testing::Test { -protected: - GameObject * game_object1; - GameObject * game_object2; - CollisionSystem collision_system; - void SetUp() override { - ComponentManager & mgr = ComponentManager::get_instance(); - mgr.delete_all_components(); - std::vector> transforms - = mgr.get_components_by_id(0); - - // ob 1 - game_object1 = new GameObject(0, "", "", Vector2{0, 0}, 0, 0); - game_object1->add_component(Rigidbody::Data{ - .mass = 1, - .gravity_scale = 1, - .body_type = Rigidbody::BodyType::DYNAMIC, - .max_linear_velocity = Vector2{10, 10}, - .max_angular_velocity = 10, - .constraints = {0, 0, 0}, - .use_gravity = false, - .bounce = false, - }); - - game_object1->add_component(Vector2{0,0},10,10); +class MyScript : public Script { + static bool oncollision(const CollisionEvent& test) { + std::cout << "test collision: " << test.info.first.collider.game_object_id << std::endl; + return true; + } + void init() { + EventManager::get_instance().subscribe(oncollision, this->get_game_object_id()); + } + void update() { + // Retrieve component from the same GameObject this script is on + } +}; + +class PhysicsTest : public ::testing::Test { +public: + ComponentManager component_manager; + PhysicsSystem system{component_manager}; - //ob 2 - game_object2 = new GameObject(1, "", "", Vector2{50, 50}, 0, 0); - game_object2->add_component(Rigidbody::Data{ - .mass = 1, - .gravity_scale = 1, - .body_type = Rigidbody::BodyType::DYNAMIC, - .max_linear_velocity = Vector2{10, 10}, - .max_angular_velocity = 10, - .constraints = {0, 0, 0}, - .use_gravity = false, - .bounce = false, - }); - game_object2->add_component(Vector2{0,0},5); + void SetUp() override { + ComponentManager & mgr = this->component_manager; + vector> transforms + = mgr.get_components_by_id(0); + if (transforms.empty()) { + auto entity = mgr.new_object("", "", Vector2{0, 0}, 0, 0); + entity.add_component(Rigidbody::Data{ + .mass = 1, + .gravity_scale = 1, + .body_type = Rigidbody::BodyType::DYNAMIC, + .max_linear_velocity = Vector2{10, 10}, + .max_angular_velocity = 10, + .constraints = {0, 0}, + .use_gravity = true, + .bounce = false, + }); + } + transforms = mgr.get_components_by_id(0); + Transform & transform = transforms.front().get(); + transform.position.x = 0.0; + transform.position.y = 0.0; + transform.rotation = 0.0; + vector> rigidbodies + = mgr.get_components_by_id(0); + Rigidbody & rigidbody = rigidbodies.front().get(); + rigidbody.data.angular_velocity = 0; + rigidbody.data.linear_velocity.x = 0; + rigidbody.data.linear_velocity.y = 0; } }; -TEST_F(CollisionTest, box_box_collision) { +TEST_F(PhysicsTest, gravity) { Config::get_instance().physics.gravity = 1; - ComponentManager & mgr = ComponentManager::get_instance(); - std::vector> transforms - = mgr.get_components_by_id(0); - Transform & transform = transforms.front().get(); + ComponentManager & mgr = this->component_manager; + vector> transforms = mgr.get_components_by_id(0); + const Transform & transform = transforms.front().get(); ASSERT_FALSE(transforms.empty()); - transform.position = {39,50}; - collision_system.update(); - transform.position = {40,50}; - collision_system.update(); - transform.position = {50,39}; - collision_system.update(); - transform.position = {50,40}; - collision_system.update(); - transform.position = {50,60}; - collision_system.update(); - transform.position = {50,61}; - collision_system.update(); - transform.position = {60,50}; - collision_system.update(); - transform.position = {61,50}; - collision_system.update(); -} + EXPECT_EQ(transform.position.y, 0); + + system.update(); + EXPECT_EQ(transform.position.y, 1); + system.update(); + EXPECT_EQ(transform.position.y, 3); +} -- cgit v1.2.3 From a67c52325bc8cbd264293b9dcc217fc07bfbaf57 Mon Sep 17 00:00:00 2001 From: Loek Le Blansch Date: Wed, 20 Nov 2024 18:07:48 +0100 Subject: merge `master` into `loek/collision-system` --- Doxyfile | 1 + contributing.md | 23 +++- makefile | 3 +- src/crepe/api/Color.cpp | 37 ++---- src/crepe/api/Color.h | 49 +++----- src/crepe/api/Sprite.h | 3 +- src/crepe/facade/SDLContext.h | 6 - src/crepe/system/RenderSystem.cpp | 43 +++++-- src/crepe/system/RenderSystem.h | 32 +++-- src/example/CMakeLists.txt | 3 - src/example/components_internal.cpp | 51 -------- src/example/ecs.cpp | 53 -------- src/example/events.cpp | 30 ++--- src/example/game.cpp | 2 +- src/example/rendering.cpp | 10 +- src/example/scene_manager.cpp | 79 ------------ src/makefile | 7 +- src/test/CMakeLists.txt | 2 + src/test/ECSTest.cpp | 236 ++++++++++++++++++++++++++++++++++++ src/test/RenderSystemTest.cpp | 174 ++++++++++++++++++++++++++ src/test/SceneManagerTest.cpp | 122 +++++++++++++++++++ 21 files changed, 667 insertions(+), 299 deletions(-) delete mode 100644 src/example/components_internal.cpp delete mode 100644 src/example/ecs.cpp delete mode 100644 src/example/scene_manager.cpp create mode 100644 src/test/ECSTest.cpp create mode 100644 src/test/RenderSystemTest.cpp create mode 100644 src/test/SceneManagerTest.cpp (limited to 'src/test/CMakeLists.txt') diff --git a/Doxyfile b/Doxyfile index 9328b24..e0a31df 100644 --- a/Doxyfile +++ b/Doxyfile @@ -24,6 +24,7 @@ USE_MDFILE_AS_MAINPAGE = ./readme.md REPEAT_BRIEF = NO INTERNAL_DOCS = YES +EXTRACT_PRIVATE = YES EXTRACT_STATIC = YES HIDE_UNDOC_NAMESPACES = YES HIDE_UNDOC_CLASSES = YES diff --git a/contributing.md b/contributing.md index 5b0c79d..9c95851 100644 --- a/contributing.md +++ b/contributing.md @@ -20,7 +20,7 @@ that you can click on to open them. # Code style - Formatting nitty-gritty is handled by clang-format/clang-tidy (run `make - format` in the root folder of this repository to format all sources files) + format` or `make lint`) -
ASCII only
GoodBad
@@ -798,6 +798,27 @@ that you can click on to open them. resolving merge conflicts when multiple sources were added by different people to the same CMakeLists.txt easier. +## GoogleTest-specific + +- Unit tests are not *required* to follow all code standards +-
+ Private/protected members may be accessed using preprocessor tricks + + + ```cpp + // include unrelated headers before + + #define private public + #define protected public + + // headers included after *will* be affected + ``` +
+- Each test source file defines tests within a single test suite (first + parameter of `TEST()` / `TEST_F()` macro) +- Test source files match their suite name (or test fixture name in the case of + tests that use a fixture) + # Structure - Files are placed in the appropriate directory: diff --git a/makefile b/makefile index dd7c587..c46e8a5 100644 --- a/makefile +++ b/makefile @@ -6,5 +6,6 @@ doxygen: Doxyfile FORCE FMT += $(shell git ls-files '*.c' '*.cpp' '*.h' '*.hpp') format: FORCE clang-format -i $(FMT) - $(MAKE) -C src $@ +lint: FORCE + $(MAKE) -C src $@ diff --git a/src/crepe/api/Color.cpp b/src/crepe/api/Color.cpp index 9e5f187..29bd77a 100644 --- a/src/crepe/api/Color.cpp +++ b/src/crepe/api/Color.cpp @@ -2,32 +2,11 @@ using namespace crepe; -Color Color::white = Color(255, 255, 255, 0); -Color Color::red = Color(255, 0, 0, 0); -Color Color::green = Color(0, 255, 0, 0); -Color Color::blue = Color(0, 0, 255, 0); -Color Color::black = Color(0, 0, 0, 0); -Color Color::cyan = Color(0, 255, 255, 0); -Color Color::yellow = Color(255, 255, 0, 0); -Color Color::magenta = Color(255, 0, 255, 0); - -Color::Color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha) { - this->a = alpha; - this->r = red; - this->g = green; - this->b = blue; -}; - -const Color & Color::get_white() { return Color::white; }; - -const Color & Color::get_red() { return Color::red; }; -const Color & Color::get_green() { return Color::green; }; -const Color & Color::get_blue() { return Color::blue; }; - -const Color & Color::get_black() { return Color::black; }; - -const Color & Color::get_cyan() { return Color::cyan; }; - -const Color & Color::get_yellow() { return Color::yellow; }; - -const Color & Color::get_magenta() { return Color::magenta; }; +const Color Color::WHITE{0xff, 0xff, 0xff}; +const Color Color::RED{0xff, 0x00, 0x00}; +const Color Color::GREEN{0x00, 0xff, 0x00}; +const Color Color::BLUE{0x00, 0x00, 0xff}; +const Color Color::BLACK{0x00, 0x00, 0x00}; +const Color Color::CYAN{0x00, 0xff, 0xff}; +const Color Color::YELLOW{0xff, 0xff, 0x00}; +const Color Color::MAGENTA{0xff, 0x00, 0xff}; diff --git a/src/crepe/api/Color.h b/src/crepe/api/Color.h index aa47bf4..84edb5c 100644 --- a/src/crepe/api/Color.h +++ b/src/crepe/api/Color.h @@ -4,41 +4,20 @@ namespace crepe { -// TODO: make Color a struct w/o constructors/destructors -class Color { - - // FIXME: can't these colors be defined as a `static constexpr const Color` - // instead? - -public: - Color(uint8_t red, uint8_t green, uint8_t blue, uint8_t alpha); - static const Color & get_white(); - static const Color & get_red(); - static const Color & get_green(); - static const Color & get_blue(); - static const Color & get_cyan(); - static const Color & get_magenta(); - static const Color & get_yellow(); - static const Color & get_black(); - -private: - // TODO: why are these private!? - uint8_t r; - uint8_t g; - uint8_t b; - uint8_t a; - - static Color white; - static Color red; - static Color green; - static Color blue; - static Color cyan; - static Color magenta; - static Color yellow; - static Color black; - -private: - friend class SDLContext; +struct Color { + uint8_t r = 0x00; + uint8_t g = 0x00; + uint8_t b = 0x00; + uint8_t a = 0xff; + + static const Color WHITE; + static const Color RED; + static const Color GREEN; + static const Color BLUE; + static const Color CYAN; + static const Color MAGENTA; + static const Color YELLOW; + static const Color BLACK; }; } // namespace crepe diff --git a/src/crepe/api/Sprite.h b/src/crepe/api/Sprite.h index 0192793..74a55d4 100644 --- a/src/crepe/api/Sprite.h +++ b/src/crepe/api/Sprite.h @@ -2,8 +2,9 @@ #include +#include "../Component.h" + #include "Color.h" -#include "Component.h" #include "Texture.h" namespace crepe { diff --git a/src/crepe/facade/SDLContext.h b/src/crepe/facade/SDLContext.h index 007092b..652a83e 100644 --- a/src/crepe/facade/SDLContext.h +++ b/src/crepe/facade/SDLContext.h @@ -21,9 +21,6 @@ namespace crepe { // typedef is unusable when crepe is packaged. Wouter will fix this later. typedef SDL_Keycode CREPE_KEYCODES; -class Texture; -class LoopManager; - /** * \class SDLContext * \brief Facade for the SDL library @@ -91,9 +88,6 @@ private: //! Will use the funtions: texture_from_path, get_width,get_height. friend class Texture; - //! Will use the funtions: texture_from_path, get_width,get_height. - friend class Animator; - /** * \brief Loads a texture from a file path. * \param path Path to the image file. diff --git a/src/crepe/system/RenderSystem.cpp b/src/crepe/system/RenderSystem.cpp index fa3d0de..96c5f27 100644 --- a/src/crepe/system/RenderSystem.cpp +++ b/src/crepe/system/RenderSystem.cpp @@ -1,38 +1,59 @@ +#include +#include #include +#include #include #include "../ComponentManager.h" #include "../api/Sprite.h" #include "../api/Transform.h" #include "../facade/SDLContext.h" -#include "../util/Log.h" #include "RenderSystem.h" using namespace crepe; +using namespace std; -void RenderSystem::clear_screen() const { SDLContext::get_instance().clear_screen(); } +void RenderSystem::clear_screen() { this->context.clear_screen(); } -void RenderSystem::present_screen() const { SDLContext::get_instance().present_screen(); } +void RenderSystem::present_screen() { this->context.present_screen(); } void RenderSystem::update_camera() { ComponentManager & mgr = this->component_manager; std::vector> cameras = mgr.get_components_by_type(); + if (cameras.size() == 0) throw std::runtime_error("No cameras in current scene"); + for (Camera & cam : cameras) { - SDLContext::get_instance().camera(cam); - this->curr_cam = &cam; + this->context.camera(cam); + this->curr_cam_ref = &cam; } } -void RenderSystem::render_sprites() const { - ComponentManager & mgr = this->component_manager; - std::vector> sprites = mgr.get_components_by_type(); +bool sorting_comparison(const Sprite & a, const Sprite & b) { + if (a.sorting_in_layer < b.sorting_in_layer) return true; + if (a.sorting_in_layer == b.sorting_in_layer) return a.order_in_layer < b.order_in_layer; + + return false; +} + +std::vector> +RenderSystem::sort(std::vector> & objs) { + + std::vector> sorted_objs(objs); + std::sort(sorted_objs.begin(), sorted_objs.end(), sorting_comparison); + + return sorted_objs; +} + +void RenderSystem::render_sprites() { + ComponentManager & mgr = this->component_manager; + vector> sprites = mgr.get_components_by_type(); + vector> sorted_sprites = this->sort(sprites); - SDLContext & render = SDLContext::get_instance(); - for (const Sprite & sprite : sprites) { + for (const Sprite & sprite : sorted_sprites) { auto transforms = mgr.get_components_by_id(sprite.game_object_id); - render.draw(sprite, transforms[0], *curr_cam); + this->context.draw(sprite, transforms[0], *this->curr_cam_ref); } } diff --git a/src/crepe/system/RenderSystem.h b/src/crepe/system/RenderSystem.h index 87ec494..57b9c73 100644 --- a/src/crepe/system/RenderSystem.h +++ b/src/crepe/system/RenderSystem.h @@ -1,18 +1,23 @@ #pragma once -#include "api/Camera.h" +#include +#include + +#include "facade/SDLContext.h" #include "System.h" namespace crepe { +class Camera; +class Sprite; + /** * \class RenderSystem * \brief Manages rendering operations for all game objects. * - * RenderSystem is responsible for rendering sprites, clearing and presenting the screen, and - * managing the active camera. It functions as a singleton, providing centralized rendering - * services for the application. + * RenderSystem is responsible for rendering, clearing and presenting the screen, and + * managing the active camera. */ class RenderSystem : public System { public: @@ -25,16 +30,25 @@ public: private: //! Clears the screen in preparation for rendering. - void clear_screen() const; + void clear_screen(); //! Presents the rendered frame to the display. - void present_screen() const; + void present_screen(); //! Updates the active camera used for rendering. void update_camera(); //! Renders all active sprites to the screen. - void render_sprites() const; + void render_sprites(); + + /** + * \brief sort a vector sprite objects with + * + * \param objs the vector that will do a sorting algorithm on + * \return returns a sorted reference vector + */ + std::vector> + sort(std::vector> & objs); /** * \todo Include color handling for sprites. @@ -48,8 +62,10 @@ private: private: //! Pointer to the current active camera for rendering - Camera * curr_cam = nullptr; + Camera * curr_cam_ref = nullptr; // TODO: needs a better solution + + SDLContext & context = SDLContext::get_instance(); }; } // namespace crepe diff --git a/src/example/CMakeLists.txt b/src/example/CMakeLists.txt index c5cb63f..045f4d4 100644 --- a/src/example/CMakeLists.txt +++ b/src/example/CMakeLists.txt @@ -17,7 +17,6 @@ function(add_example target_name) endfunction() add_example(audio_internal) -# add_example(components_internal) add_example(script) add_example(log) add_example(rendering) @@ -25,8 +24,6 @@ add_example(asset_manager) add_example(savemgr) add_example(proxy) add_example(db) -add_example(ecs) -add_example(scene_manager) add_example(game) add_example(events) add_example(gameloop) diff --git a/src/example/components_internal.cpp b/src/example/components_internal.cpp deleted file mode 100644 index 2a232a9..0000000 --- a/src/example/components_internal.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/** \file - * - * Standalone example for usage of the internal ECS - */ - -#include -#include - -#include -#include - -#include -#include -#include - -#include - -using namespace crepe; -using namespace std; - -#define OBJ_COUNT 100000 - -int main() { - dbg_trace(); - - ComponentManager mgr{}; - - auto start_adding = chrono::high_resolution_clock::now(); - - for (int i = 0; i < OBJ_COUNT; ++i) { - GameObject obj = mgr.new_object("Name", "Tag"); - obj.add_component("test"); - obj.add_component(0, 0, i); - } - - auto stop_adding = chrono::high_resolution_clock::now(); - - auto sprites = mgr.get_components_by_type(); - for (auto sprite : sprites) { - assert(true); - } - - auto stop_looping = chrono::high_resolution_clock::now(); - - auto add_time = chrono::duration_cast(stop_adding - start_adding); - auto loop_time = chrono::duration_cast(stop_looping - stop_adding); - printf("add time: %ldus\n", add_time.count()); - printf("loop time: %ldus\n", loop_time.count()); - - return 0; -} diff --git a/src/example/ecs.cpp b/src/example/ecs.cpp deleted file mode 100644 index d5ba51b..0000000 --- a/src/example/ecs.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include - -#include -#include -#include -#include - -using namespace crepe; -using namespace std; - -int main() { - ComponentManager mgr{}; - - // Create a few GameObjects - try { - GameObject body = mgr.new_object("body", "person", Vector2{0, 0}, 0, 1); - GameObject right_leg = mgr.new_object("rightLeg", "person", Vector2{1, 1}, 0, 1); - GameObject left_leg = mgr.new_object("leftLeg", "person", Vector2{1, 1}, 0, 1); - GameObject right_foot = mgr.new_object("rightFoot", "person", Vector2{2, 2}, 0, 1); - GameObject left_foot = mgr.new_object("leftFoot", "person", Vector2{2, 2}, 0, 1); - - // Set the parent of each GameObject - right_foot.set_parent(right_leg); - left_foot.set_parent(left_leg); - right_leg.set_parent(body); - left_leg.set_parent(body); - - // Adding a second Transform component is not allowed and will invoke an exception - body.add_component(Vector2{10, 10}, 0, 1); - } catch (const exception & e) { - cerr << e.what() << endl; - } - - // Get the Metadata and Transform components of each GameObject - vector> metadata = mgr.get_components_by_type(); - vector> transform = mgr.get_components_by_type(); - - // Print the Metadata and Transform components - for (auto & m : metadata) { - cout << "Id: " << m.get().game_object_id << " Name: " << m.get().name - << " Tag: " << m.get().tag << " Parent: " << m.get().parent << " Children: "; - for (auto & c : m.get().children) { - cout << c << " "; - } - cout << endl; - } - for (auto & t : transform) { - cout << "Id: " << t.get().game_object_id << " Position: [" << t.get().position.x - << ", " << t.get().position.y << "]" << endl; - } - - return 0; -} diff --git a/src/example/events.cpp b/src/example/events.cpp index ed519ff..e6d91aa 100644 --- a/src/example/events.cpp +++ b/src/example/events.cpp @@ -2,7 +2,7 @@ #include #include -#include +#include #include #include @@ -65,6 +65,10 @@ public: } }; int main() { + EventManager & evmgr = EventManager::get_instance(); + ComponentManager mgr{}; + ScriptSystem sys{mgr}; + // two events to trigger KeyPressEvent key_press; key_press.key = Keycode::A; @@ -74,22 +78,19 @@ int main() { click_event.mouse_x = 100; click_event.mouse_y = 200; // queue events to test queue - EventManager::get_instance().queue_event( - std::move(key_press), 0); - EventManager::get_instance().queue_event( - std::move(click_event), 0); + evmgr.queue_event(std::move(key_press), 0); + evmgr.queue_event(std::move(click_event), 0); { TestKeyListener test_listener; test_listener.set_channel(1); - auto obj = GameObject(0, "name", "tag", Vector2{1.2, 3.4}, 0, 1); + auto obj = mgr.new_object("name", "tag", Vector2{1.2, 3.4}, 0, 1); obj.add_component().set_script(); - ScriptSystem sys; sys.update(); // Trigger the events while `testListener` is in scope - EventManager::get_instance().trigger_event(key_press, 1); - EventManager::get_instance().trigger_event(MouseClickEvent{ + evmgr.trigger_event(key_press, 1); + evmgr.trigger_event(MouseClickEvent{ .mouse_x = 100, .mouse_y = 100, .button = MouseButton::LEFT_MOUSE, @@ -100,14 +101,13 @@ int main() { std::cout << "lambda test" << std::endl; return false; }; - EventManager::get_instance().subscribe( - std::move(event_handler), 0); + evmgr.subscribe(std::move(event_handler), 0); // testing trigger with testListener not in scope (unsubscribed) - EventManager::get_instance().trigger_event(key_press, 0); - EventManager::get_instance().trigger_event(click_event, 0); + evmgr.trigger_event(key_press, 0); + evmgr.trigger_event(click_event, 0); // dispatching queued events - EventManager::get_instance().dispatch_events(); + evmgr.dispatch_events(); - EventManager::get_instance().unsubscribe(event_handler, 0); + evmgr.unsubscribe(event_handler, 0); return EXIT_SUCCESS; } diff --git a/src/example/game.cpp b/src/example/game.cpp index b6a0c31..a557be7 100644 --- a/src/example/game.cpp +++ b/src/example/game.cpp @@ -74,7 +74,7 @@ public: game_object1.add_component( make_shared("/home/jaro/crepe/asset/texture/green_square.png"), color, FlipSettings{true, true}); - game_object1.add_component(Color::get_white()); + game_object1.add_component(Color::WHITE); } }; diff --git a/src/example/rendering.cpp b/src/example/rendering.cpp index 14ecaa9..9e3c8cc 100644 --- a/src/example/rendering.cpp +++ b/src/example/rendering.cpp @@ -30,13 +30,13 @@ int main() { // Normal adding components { Color color(0, 0, 0, 0); - obj.add_component(make_shared("/home/jaro/crepe/asset/texture/green_square.png"), color, + obj.add_component(make_shared("../asset/texture/green_square.png"), color, FlipSettings{false, false}); - obj.add_component(Color::get_red()); + obj.add_component(Color::RED); } { Color color(0, 0, 0, 0); - obj1.add_component(make_shared("/home/jaro/crepe/asset/texture/green_square.png"), color, + obj1.add_component(make_shared("../asset/texture/green_square.png"), color, FlipSettings{true, true}); } @@ -48,8 +48,12 @@ int main() { } */ + sys.update(); + /* + auto start = std::chrono::steady_clock::now(); while (std::chrono::steady_clock::now() - start < std::chrono::seconds(5)) { sys.update(); } + */ } diff --git a/src/example/scene_manager.cpp b/src/example/scene_manager.cpp deleted file mode 100644 index accec7d..0000000 --- a/src/example/scene_manager.cpp +++ /dev/null @@ -1,79 +0,0 @@ -#include - -#include -#include -#include -#include -#include -#include - -using namespace crepe; -using namespace std; - -class ConcreteScene1 : public Scene { -public: - using Scene::Scene; - - void load_scene() { - auto & mgr = this->component_manager; - GameObject object1 = mgr.new_object("scene_1", "tag_scene_1", Vector2{0, 0}, 0, 1); - GameObject object2 = mgr.new_object("scene_1", "tag_scene_1", Vector2{1, 0}, 0, 1); - GameObject object3 = mgr.new_object("scene_1", "tag_scene_1", Vector2{2, 0}, 0, 1); - } -}; - -class ConcreteScene2 : public Scene { -public: - using Scene::Scene; - - void load_scene() { - auto & mgr = this->component_manager; - GameObject object1 = mgr.new_object("scene_2", "tag_scene_2", Vector2{0, 0}, 0, 1); - GameObject object2 = mgr.new_object("scene_2", "tag_scene_2", Vector2{0, 1}, 0, 1); - GameObject object3 = mgr.new_object("scene_2", "tag_scene_2", Vector2{0, 2}, 0, 1); - GameObject object4 = mgr.new_object("scene_2", "tag_scene_2", Vector2{0, 3}, 0, 1); - } -}; - -int main() { - ComponentManager component_mgr{}; - SceneManager scene_mgr{component_mgr}; - - // Add the scenes to the scene manager - scene_mgr.add_scene("scene1"); - scene_mgr.add_scene("scene2"); - - // There is no need to call set_next_scene() at the beginnen, because the first scene will be - // automatically set as the next scene - - // Load scene1 (the first scene added) - scene_mgr.load_next_scene(); - - // Get the Metadata components of each GameObject of Scene1 - vector> metadata - = component_mgr.get_components_by_type(); - - cout << "Metadata components of Scene1:" << endl; - // Print the Metadata - for (auto & m : metadata) { - cout << "Id: " << m.get().game_object_id << " Name: " << m.get().name - << " Tag: " << m.get().tag << endl; - } - - // Set scene2 as the next scene - scene_mgr.set_next_scene("scene2"); - // Load scene2 - scene_mgr.load_next_scene(); - - // Get the Metadata components of each GameObject of Scene2 - metadata = component_mgr.get_components_by_type(); - - cout << "Metadata components of Scene2:" << endl; - // Print the Metadata - for (auto & m : metadata) { - cout << "Id: " << m.get().game_object_id << " Name: " << m.get().name - << " Tag: " << m.get().tag << endl; - } - - return 0; -} diff --git a/src/makefile b/src/makefile index 5f80204..a0e8f02 100644 --- a/src/makefile +++ b/src/makefile @@ -1,6 +1,9 @@ .PHONY: FORCE -FMT := $(shell git ls-files '*.c' '*.cpp' '*.h' '*.hpp') format: FORCE - clang-tidy -p build/compile_commands.json --fix-errors $(FMT) + $(MAKE) -C .. $@ + +LINT := $(shell git ls-files '*.c' '*.cpp' '*.h' '*.hpp') +lint: FORCE + clang-tidy -p build/compile_commands.json --fix-errors $(LINT) diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index f830165..14c5123 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -4,5 +4,7 @@ target_sources(test_main PUBLIC PhysicsTest.cpp ScriptTest.cpp ParticleTest.cpp + ECSTest.cpp + SceneManagerTest.cpp ) diff --git a/src/test/ECSTest.cpp b/src/test/ECSTest.cpp new file mode 100644 index 0000000..d5a5826 --- /dev/null +++ b/src/test/ECSTest.cpp @@ -0,0 +1,236 @@ +#include + +#define protected public + +#include +#include +#include +#include +#include + +using namespace std; +using namespace crepe; + +class ECSTest : public ::testing::Test { +public: + ComponentManager mgr{}; +}; + +TEST_F(ECSTest, createGameObject) { + GameObject obj = mgr.new_object("body", "person", Vector2{0, 0}, 0, 1); + + vector> metadata = mgr.get_components_by_type(); + vector> transform = mgr.get_components_by_type(); + + EXPECT_EQ(metadata.size(), 1); + EXPECT_EQ(transform.size(), 1); + + EXPECT_EQ(metadata[0].get().name, "body"); + EXPECT_EQ(metadata[0].get().tag, "person"); + EXPECT_EQ(metadata[0].get().parent, -1); + EXPECT_EQ(metadata[0].get().children.size(), 0); + + EXPECT_EQ(transform[0].get().position.x, 0); + EXPECT_EQ(transform[0].get().position.y, 0); + EXPECT_EQ(transform[0].get().rotation, 0); + EXPECT_EQ(transform[0].get().scale, 1); +} + +TEST_F(ECSTest, deleteAllGameObjects) { + GameObject obj0 = mgr.new_object("body", "person", Vector2{0, 0}, 0, 1); + GameObject obj1 = mgr.new_object("body", "person", Vector2{0, 0}, 0, 1); + + mgr.delete_all_components(); + + vector> metadata = mgr.get_components_by_type(); + vector> transform = mgr.get_components_by_type(); + + EXPECT_EQ(metadata.size(), 0); + EXPECT_EQ(transform.size(), 0); + + GameObject obj2 = mgr.new_object("body2", "person2", Vector2{1, 0}, 5, 1); + + metadata = mgr.get_components_by_type(); + transform = mgr.get_components_by_type(); + + EXPECT_EQ(metadata.size(), 1); + EXPECT_EQ(transform.size(), 1); + + EXPECT_EQ(metadata[0].get().game_object_id, 0); + EXPECT_EQ(metadata[0].get().name, "body2"); + EXPECT_EQ(metadata[0].get().tag, "person2"); + EXPECT_EQ(metadata[0].get().parent, -1); + EXPECT_EQ(metadata[0].get().children.size(), 0); + + EXPECT_EQ(transform[0].get().game_object_id, 0); + EXPECT_EQ(transform[0].get().position.x, 1); + EXPECT_EQ(transform[0].get().position.y, 0); + EXPECT_EQ(transform[0].get().rotation, 5); + EXPECT_EQ(transform[0].get().scale, 1); +} + +TEST_F(ECSTest, deleteGameObject) { + GameObject obj0 = mgr.new_object("body", "person", Vector2{0, 0}, 0, 1); + GameObject obj1 = mgr.new_object("body", "person", Vector2{0, 0}, 0, 1); + + mgr.delete_all_components_of_id(0); + + vector> metadata = mgr.get_components_by_type(); + vector> transform = mgr.get_components_by_type(); + + EXPECT_EQ(metadata.size(), 1); + EXPECT_EQ(transform.size(), 1); + + EXPECT_EQ(metadata[0].get().game_object_id, 1); + EXPECT_EQ(metadata[0].get().name, "body"); + EXPECT_EQ(metadata[0].get().tag, "person"); + EXPECT_EQ(metadata[0].get().parent, -1); + EXPECT_EQ(metadata[0].get().children.size(), 0); + + EXPECT_EQ(transform[0].get().game_object_id, 1); + EXPECT_EQ(transform[0].get().position.x, 0); + EXPECT_EQ(transform[0].get().position.y, 0); + EXPECT_EQ(transform[0].get().rotation, 0); + EXPECT_EQ(transform[0].get().scale, 1); +} + +TEST_F(ECSTest, manyGameObjects) { + for (int i = 0; i < 5000; i++) { + GameObject obj = mgr.new_object("body", "person", Vector2{0, 0}, 0, i); + } + + vector> metadata = mgr.get_components_by_type(); + vector> transform = mgr.get_components_by_type(); + + EXPECT_EQ(metadata.size(), 5000); + EXPECT_EQ(transform.size(), 5000); + for (int i = 0; i < 5000; i++) { + EXPECT_EQ(metadata[i].get().game_object_id, i); + EXPECT_EQ(metadata[i].get().name, "body"); + EXPECT_EQ(metadata[i].get().tag, "person"); + EXPECT_EQ(metadata[i].get().parent, -1); + EXPECT_EQ(metadata[i].get().children.size(), 0); + + EXPECT_EQ(transform[i].get().game_object_id, i); + EXPECT_EQ(transform[i].get().position.x, 0); + EXPECT_EQ(transform[i].get().position.y, 0); + EXPECT_EQ(transform[i].get().rotation, 0); + EXPECT_EQ(transform[i].get().scale, i); + } + + mgr.delete_components(); + + metadata = mgr.get_components_by_type(); + transform = mgr.get_components_by_type(); + + EXPECT_EQ(metadata.size(), 0); + EXPECT_EQ(transform.size(), 5000); + + for (int i = 0; i < 10000 - 5000; i++) { + string tag = "person" + to_string(i); + GameObject obj = mgr.new_object("body", tag, Vector2{0, 0}, i, 0); + } + + metadata = mgr.get_components_by_type(); + transform = mgr.get_components_by_type(); + + EXPECT_EQ(metadata.size(), 10000 - 5000); + EXPECT_EQ(transform.size(), 10000); +} + +TEST_F(ECSTest, getComponentsByID) { + GameObject obj0 = mgr.new_object("body", "person", Vector2{0, 0}, 0, 1); + GameObject obj1 = mgr.new_object("body", "person", Vector2{0, 0}, 0, 1); + + vector> metadata = mgr.get_components_by_id(0); + vector> transform = mgr.get_components_by_id(1); + + EXPECT_EQ(metadata.size(), 1); + EXPECT_EQ(transform.size(), 1); + + EXPECT_EQ(metadata[0].get().game_object_id, 0); + EXPECT_EQ(metadata[0].get().name, "body"); + EXPECT_EQ(metadata[0].get().tag, "person"); + EXPECT_EQ(metadata[0].get().parent, -1); + EXPECT_EQ(metadata[0].get().children.size(), 0); + + EXPECT_EQ(transform[0].get().game_object_id, 1); + EXPECT_EQ(transform[0].get().position.x, 0); + EXPECT_EQ(transform[0].get().position.y, 0); + EXPECT_EQ(transform[0].get().rotation, 0); + EXPECT_EQ(transform[0].get().scale, 1); +} + +TEST_F(ECSTest, tooMuchComponents) { + try { + GameObject obj0 = mgr.new_object("body", "person", Vector2{0, 0}, 0, 1); + obj0.add_component(Vector2{10, 10}, 0, 1); + } catch (const exception & e) { + EXPECT_EQ(e.what(), + string("Exceeded maximum number of instances for this component type")); + } + + try { + GameObject obj1 = mgr.new_object("body", "person", Vector2{0, 0}, 0, 1); + obj1.add_component("body", "person"); + } catch (const exception & e) { + EXPECT_EQ(e.what(), + string("Exceeded maximum number of instances for this component type")); + } + + vector> metadata = mgr.get_components_by_type(); + + EXPECT_EQ(metadata.size(), 2); + EXPECT_EQ(metadata[0].get().name, "body"); + EXPECT_EQ(metadata[1].get().name, "body"); +} + +TEST_F(ECSTest, partentChild) { + { + GameObject body = mgr.new_object("body", "person", Vector2{0, 0}, 0, 1); + GameObject right_leg = mgr.new_object("rightLeg", "person", Vector2{1, 1}, 0, 1); + GameObject left_leg = mgr.new_object("leftLeg", "person", Vector2{1, 1}, 0, 1); + GameObject right_foot = mgr.new_object("rightFoot", "person", Vector2{2, 2}, 0, 1); + GameObject left_foot = mgr.new_object("leftFoot", "person", Vector2{2, 2}, 0, 1); + + // Set the parent of each GameObject + right_foot.set_parent(right_leg); + left_foot.set_parent(left_leg); + right_leg.set_parent(body); + left_leg.set_parent(body); + } + + // Get the Metadata and Transform components of each GameObject + vector> metadata = mgr.get_components_by_type(); + + // Check IDs + EXPECT_EQ(metadata[0].get().game_object_id, 0); + EXPECT_EQ(metadata[1].get().game_object_id, 1); + EXPECT_EQ(metadata[2].get().game_object_id, 2); + EXPECT_EQ(metadata[3].get().game_object_id, 3); + EXPECT_EQ(metadata[4].get().game_object_id, 4); + + // Check the parent-child relationships + EXPECT_EQ(metadata[0].get().name, "body"); + EXPECT_EQ(metadata[1].get().name, "rightLeg"); + EXPECT_EQ(metadata[2].get().name, "leftLeg"); + EXPECT_EQ(metadata[3].get().name, "rightFoot"); + EXPECT_EQ(metadata[4].get().name, "leftFoot"); + + EXPECT_EQ(metadata[0].get().parent, -1); + EXPECT_EQ(metadata[1].get().parent, 0); + EXPECT_EQ(metadata[2].get().parent, 0); + EXPECT_EQ(metadata[3].get().parent, 1); + EXPECT_EQ(metadata[4].get().parent, 2); + + EXPECT_EQ(metadata[0].get().children.size(), 2); + EXPECT_EQ(metadata[1].get().children.size(), 1); + EXPECT_EQ(metadata[2].get().children.size(), 1); + EXPECT_EQ(metadata[3].get().children.size(), 0); + EXPECT_EQ(metadata[4].get().children.size(), 0); + + EXPECT_EQ(metadata[0].get().children[0], 1); + EXPECT_EQ(metadata[0].get().children[1], 2); + EXPECT_EQ(metadata[1].get().children[0], 3); + EXPECT_EQ(metadata[2].get().children[0], 4); +} diff --git a/src/test/RenderSystemTest.cpp b/src/test/RenderSystemTest.cpp new file mode 100644 index 0000000..ac479d3 --- /dev/null +++ b/src/test/RenderSystemTest.cpp @@ -0,0 +1,174 @@ +#include "api/Camera.h" +#include +#include +#include +#include + +#define private public +#define protected public + +#include +#include +#include +#include +#include + +#include + +using namespace std; +using namespace crepe; +using namespace testing; + +class RenderSystemTest : public Test { +public: + ComponentManager mgr{}; + RenderSystem sys{mgr}; + GameObject entity1 = this->mgr.new_object("name"); + GameObject entity2 = this->mgr.new_object("name"); + GameObject entity3 = this->mgr.new_object("name"); + GameObject entity4 = this->mgr.new_object("name"); + + void SetUp() override { + auto & sprite1 + = entity1.add_component(make_shared("../asset/texture/img.png"), + Color(0, 0, 0, 0), FlipSettings{false, false}); + ASSERT_NE(sprite1.sprite_image.get(), nullptr); + sprite1.order_in_layer = 5; + sprite1.sorting_in_layer = 5; + EXPECT_EQ(sprite1.order_in_layer, 5); + EXPECT_EQ(sprite1.sorting_in_layer, 5); + auto & sprite2 + = entity2.add_component(make_shared("../asset/texture/img.png"), + Color(0, 0, 0, 0), FlipSettings{false, false}); + ASSERT_NE(sprite2.sprite_image.get(), nullptr); + sprite2.sorting_in_layer = 2; + sprite2.order_in_layer = 1; + + EXPECT_EQ(sprite2.sorting_in_layer, 2); + EXPECT_EQ(sprite2.order_in_layer, 1); + + auto & sprite3 + = entity3.add_component(make_shared("../asset/texture/img.png"), + Color(0, 0, 0, 0), FlipSettings{false, false}); + ASSERT_NE(sprite3.sprite_image.get(), nullptr); + sprite3.sorting_in_layer = 1; + sprite3.order_in_layer = 2; + + EXPECT_EQ(sprite3.sorting_in_layer, 1); + EXPECT_EQ(sprite3.order_in_layer, 2); + + auto & sprite4 + = entity4.add_component(make_shared("../asset/texture/img.png"), + Color(0, 0, 0, 0), FlipSettings{false, false}); + ASSERT_NE(sprite4.sprite_image.get(), nullptr); + sprite4.sorting_in_layer = 1; + sprite4.order_in_layer = 1; + EXPECT_EQ(sprite4.sorting_in_layer, 1); + EXPECT_EQ(sprite4.order_in_layer, 1); + } +}; + +TEST_F(RenderSystemTest, expected_throws) { + GameObject entity1 = this->mgr.new_object("NAME"); + + // no texture img + EXPECT_ANY_THROW({ + entity1.add_component(make_shared("NO_IMAGE"), Color(0, 0, 0, 0), + FlipSettings{false, false}); + }); + + // No camera + EXPECT_ANY_THROW({ this->sys.update(); }); +} + +TEST_F(RenderSystemTest, make_sprites) {} + +TEST_F(RenderSystemTest, sorting_sprites) { + vector> sprites = this->mgr.get_components_by_type(); + ASSERT_EQ(sprites.size(), 4); + + vector> sorted_sprites = this->sys.sort(sprites); + ASSERT_EQ(sorted_sprites.size(), 4); + + // Expected order after sorting: + // 1. sorting_in_layer: 1, order_in_layer: 1 (entity4) + // 2. sorting_in_layer: 1, order_in_layer: 2 (entity3) + // 3. sorting_in_layer: 2, order_in_layer: 1 (entity2) + // 4. sorting_in_layer: 5, order_in_layer: 5 (entity1) + + EXPECT_EQ(sorted_sprites[0].get().sorting_in_layer, 1); + EXPECT_EQ(sorted_sprites[0].get().order_in_layer, 1); + + EXPECT_EQ(sorted_sprites[1].get().sorting_in_layer, 1); + EXPECT_EQ(sorted_sprites[1].get().order_in_layer, 2); + + EXPECT_EQ(sorted_sprites[2].get().sorting_in_layer, 2); + EXPECT_EQ(sorted_sprites[2].get().order_in_layer, 1); + + EXPECT_EQ(sorted_sprites[3].get().sorting_in_layer, 5); + EXPECT_EQ(sorted_sprites[3].get().order_in_layer, 5); + + for (size_t i = 1; i < sorted_sprites.size(); ++i) { + const Sprite & prev = sorted_sprites[i - 1].get(); + const Sprite & curr = sorted_sprites[i].get(); + + if (prev.sorting_in_layer == curr.sorting_in_layer) { + EXPECT_LE(prev.order_in_layer, curr.order_in_layer); + } else { + EXPECT_LE(prev.sorting_in_layer, curr.sorting_in_layer); + } + } +} + +TEST_F(RenderSystemTest, Update) { + entity1.add_component(Color::WHITE); + { + vector> sprites = this->mgr.get_components_by_type(); + ASSERT_EQ(sprites.size(), 4); + + EXPECT_EQ(sprites[0].get().game_object_id, 0); + EXPECT_EQ(sprites[1].get().game_object_id, 1); + EXPECT_EQ(sprites[2].get().game_object_id, 2); + EXPECT_EQ(sprites[3].get().game_object_id, 3); + } + this->sys.update(); + { + vector> sprites = this->mgr.get_components_by_type(); + ASSERT_EQ(sprites.size(), 4); + + EXPECT_EQ(sprites[0].get().game_object_id, 0); + EXPECT_EQ(sprites[1].get().game_object_id, 1); + EXPECT_EQ(sprites[2].get().game_object_id, 2); + EXPECT_EQ(sprites[3].get().game_object_id, 3); + } +} + +TEST_F(RenderSystemTest, Camera) { + { + auto cameras = this->mgr.get_components_by_type(); + EXPECT_NE(cameras.size(), 1); + } + { + entity1.add_component(Color::WHITE); + auto cameras = this->mgr.get_components_by_type(); + EXPECT_EQ(cameras.size(), 1); + } + + //TODO improve with newer version +} +TEST_F(RenderSystemTest, Color) { + entity1.add_component(Color::WHITE); + auto & sprite = this->mgr.get_components_by_id(entity1.id).front().get(); + ASSERT_NE(sprite.sprite_image.get(), nullptr); + + sprite.color = Color::GREEN; + EXPECT_EQ(sprite.color.r, Color::GREEN.r); + EXPECT_EQ(sprite.color.g, Color::GREEN.g); + EXPECT_EQ(sprite.color.b, Color::GREEN.b); + EXPECT_EQ(sprite.color.a, Color::GREEN.a); + this->sys.update(); + EXPECT_EQ(sprite.color.r, Color::GREEN.r); + EXPECT_EQ(sprite.color.g, Color::GREEN.g); + EXPECT_EQ(sprite.color.b, Color::GREEN.b); + EXPECT_EQ(sprite.color.a, Color::GREEN.a); +} diff --git a/src/test/SceneManagerTest.cpp b/src/test/SceneManagerTest.cpp new file mode 100644 index 0000000..69e1171 --- /dev/null +++ b/src/test/SceneManagerTest.cpp @@ -0,0 +1,122 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace crepe; + +class ConcreteScene1 : public Scene { +public: + using Scene::Scene; + + void load_scene() { + auto & mgr = this->component_manager; + GameObject object1 = mgr.new_object("scene_1", "tag_scene_1", Vector2{0, 0}, 0, 1); + GameObject object2 = mgr.new_object("scene_1", "tag_scene_1", Vector2{1, 0}, 0, 1); + GameObject object3 = mgr.new_object("scene_1", "tag_scene_1", Vector2{2, 0}, 0, 1); + } +}; + +class ConcreteScene2 : public Scene { +public: + using Scene::Scene; + + void load_scene() { + auto & mgr = this->component_manager; + GameObject object1 = mgr.new_object("scene_2", "tag_scene_2", Vector2{0, 0}, 0, 1); + GameObject object2 = mgr.new_object("scene_2", "tag_scene_2", Vector2{0, 1}, 0, 1); + GameObject object3 = mgr.new_object("scene_2", "tag_scene_2", Vector2{0, 2}, 0, 1); + GameObject object4 = mgr.new_object("scene_2", "tag_scene_2", Vector2{0, 3}, 0, 1); + } +}; + +class SceneManagerTest : public ::testing::Test { +public: + ComponentManager component_mgr{}; + SceneManager scene_mgr{component_mgr}; +}; + +TEST_F(SceneManagerTest, loadScene) { + scene_mgr.add_scene("scene1"); + scene_mgr.add_scene("scene2"); + + scene_mgr.load_next_scene(); + + vector> metadata + = component_mgr.get_components_by_type(); + vector> transform + = component_mgr.get_components_by_type(); + + EXPECT_EQ(metadata.size(), 3); + EXPECT_EQ(transform.size(), 3); + + EXPECT_EQ(metadata[0].get().game_object_id, 0); + EXPECT_EQ(metadata[0].get().name, "scene_1"); + EXPECT_EQ(metadata[0].get().tag, "tag_scene_1"); + EXPECT_EQ(metadata[0].get().parent, -1); + EXPECT_EQ(metadata[0].get().children.size(), 0); + EXPECT_EQ(transform[0].get().position.x, 0); + EXPECT_EQ(transform[0].get().position.y, 0); + + EXPECT_EQ(metadata[1].get().game_object_id, 1); + EXPECT_EQ(metadata[1].get().name, "scene_1"); + EXPECT_EQ(metadata[1].get().tag, "tag_scene_1"); + EXPECT_EQ(metadata[1].get().parent, -1); + EXPECT_EQ(metadata[1].get().children.size(), 0); + EXPECT_EQ(transform[1].get().position.x, 1); + EXPECT_EQ(transform[1].get().position.y, 0); + + EXPECT_EQ(metadata[2].get().game_object_id, 2); + EXPECT_EQ(metadata[2].get().name, "scene_1"); + EXPECT_EQ(metadata[2].get().tag, "tag_scene_1"); + EXPECT_EQ(metadata[2].get().parent, -1); + EXPECT_EQ(metadata[2].get().children.size(), 0); + EXPECT_EQ(transform[2].get().position.x, 2); + EXPECT_EQ(transform[2].get().position.y, 0); + + scene_mgr.set_next_scene("scene2"); + scene_mgr.load_next_scene(); + + metadata = component_mgr.get_components_by_type(); + transform = component_mgr.get_components_by_type(); + + EXPECT_EQ(metadata.size(), 4); + EXPECT_EQ(transform.size(), 4); + + EXPECT_EQ(metadata[0].get().game_object_id, 0); + EXPECT_EQ(metadata[0].get().name, "scene_2"); + EXPECT_EQ(metadata[0].get().tag, "tag_scene_2"); + EXPECT_EQ(metadata[0].get().parent, -1); + EXPECT_EQ(metadata[0].get().children.size(), 0); + EXPECT_EQ(transform[0].get().position.x, 0); + EXPECT_EQ(transform[0].get().position.y, 0); + + EXPECT_EQ(metadata[1].get().game_object_id, 1); + EXPECT_EQ(metadata[1].get().name, "scene_2"); + EXPECT_EQ(metadata[1].get().tag, "tag_scene_2"); + EXPECT_EQ(metadata[1].get().parent, -1); + EXPECT_EQ(metadata[1].get().children.size(), 0); + EXPECT_EQ(transform[1].get().position.x, 0); + EXPECT_EQ(transform[1].get().position.y, 1); + + EXPECT_EQ(metadata[2].get().game_object_id, 2); + EXPECT_EQ(metadata[2].get().name, "scene_2"); + EXPECT_EQ(metadata[2].get().tag, "tag_scene_2"); + EXPECT_EQ(metadata[2].get().parent, -1); + EXPECT_EQ(metadata[2].get().children.size(), 0); + EXPECT_EQ(transform[2].get().position.x, 0); + EXPECT_EQ(transform[2].get().position.y, 2); + + EXPECT_EQ(metadata[3].get().game_object_id, 3); + EXPECT_EQ(metadata[3].get().name, "scene_2"); + EXPECT_EQ(metadata[3].get().tag, "tag_scene_2"); + EXPECT_EQ(metadata[3].get().parent, -1); + EXPECT_EQ(metadata[3].get().children.size(), 0); + EXPECT_EQ(transform[3].get().position.x, 0); + EXPECT_EQ(transform[3].get().position.y, 3); +} -- cgit v1.2.3 From c341f6a44699d71b8b20e6b814274b30e43514c8 Mon Sep 17 00:00:00 2001 From: JAROWMR Date: Sat, 23 Nov 2024 22:07:15 +0100 Subject: added profiling test --- src/test/CMakeLists.txt | 27 +++++----- src/test/CollisionTest.cpp | 16 ------ src/test/Profiling.cpp | 128 +++++++++++++++++++++++++++++++++++++++++++++ src/test/main.cpp | 2 +- 4 files changed, 143 insertions(+), 30 deletions(-) create mode 100644 src/test/Profiling.cpp (limited to 'src/test/CMakeLists.txt') diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index c65940b..68fa01c 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -1,16 +1,17 @@ target_sources(test_main PUBLIC - CollisionTest.cpp + # CollisionTest.cpp main.cpp - PhysicsTest.cpp - ScriptTest.cpp - ParticleTest.cpp - AssetTest.cpp - OptionalRefTest.cpp - RenderSystemTest.cpp - EventTest.cpp - ECSTest.cpp - SceneManagerTest.cpp - ValueBrokerTest.cpp - DBTest.cpp - Vector2Test.cpp + # PhysicsTest.cpp + # ScriptTest.cpp + # ParticleTest.cpp + # AssetTest.cpp + # OptionalRefTest.cpp + # RenderSystemTest.cpp + # EventTest.cpp + # ECSTest.cpp + # SceneManagerTest.cpp + # ValueBrokerTest.cpp + # DBTest.cpp + # Vector2Test.cpp + Profiling.cpp ) diff --git a/src/test/CollisionTest.cpp b/src/test/CollisionTest.cpp index e36260c..245cced 100644 --- a/src/test/CollisionTest.cpp +++ b/src/test/CollisionTest.cpp @@ -22,22 +22,6 @@ using namespace std::chrono_literals; using namespace crepe; using namespace testing; -// class MyScript : public Script { -// bool oncollision(const CollisionEvent& test) { -// Log::logf("Box {} script on_collision()", test.info.first.collider.game_object_id); -// return true; -// } -// void init() { -// subscribe([this](const CollisionEvent& ev) -> bool { -// return this->oncollision(ev); -// }); -// } -// void update() { -// // Retrieve component from the same GameObject this script is on -// } -// }; - - class CollisionHandler : public Script { public: int box_id; diff --git a/src/test/Profiling.cpp b/src/test/Profiling.cpp new file mode 100644 index 0000000..9929288 --- /dev/null +++ b/src/test/Profiling.cpp @@ -0,0 +1,128 @@ +#include "system/ParticleSystem.h" +#include "system/PhysicsSystem.h" +#include "system/RenderSystem.h" +#include +#include +#include + +#define private public +#define protected public + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +using namespace std; +using namespace std::chrono_literals; +using namespace crepe; +using namespace testing; + +class CollisionHandler : public Script { +public: + int box_id; + + CollisionHandler(int box_id) { + this->box_id = box_id; + } + + bool on_collision(const CollisionEvent& ev) { + // test load? + return true; + } + + void init() { + subscribe([this](const CollisionEvent& ev) -> bool { + return this->on_collision(ev); + }); + } + void update() { + // Retrieve component from the same GameObject this script is on + } +}; + +class Profiling : public Test { +public: + ComponentManager mgr; + // Add system used for profling tests + CollisionSystem collision_sys{mgr}; + PhysicsSystem physics_sys{mgr}; + ParticleSystem particle_sys{mgr}; + RenderSystem render_sys{mgr}; + ScriptSystem script_sys{mgr}; + + // Store individual function timings + std::map timings; + + // Min and max gameobject that should and can be created + int min_gameobject_count = 100; + int max_gameobject_count = 100; + + void SetUp() override { + + GameObject do_not_use = mgr.new_object("DO_NOT_USE","",{0,0}); + do_not_use.add_component(Color::WHITE); + // initialize systems here: + //calls init + script_sys.update(); + //creates window + render_sys.update(); + } + + // Helper function to time an update call and store its duration + template + long long time_function(const std::string& name, Func&& func) { + auto start = std::chrono::steady_clock::now(); + func(); + auto end = std::chrono::steady_clock::now(); + auto duration = std::chrono::duration_cast(end - start).count(); + timings[name] = duration; // Store the duration in microseconds + return duration; // Return the duration in microseconds + } + + // Run and profile all systems, return the total time in milliseconds + long long run_all_systems() { + long long total_microseconds = 0; + total_microseconds += time_function("PhysicsSystem", [&]() { physics_sys.update(); }); + total_microseconds += time_function("CollisionSystem", [&]() { collision_sys.update(); }); + total_microseconds += time_function("ParticleSystem", [&]() { particle_sys.update(); }); + total_microseconds += time_function("RenderSystem", [&]() { render_sys.update(); }); + return total_microseconds; + } + + // Print timings of all functions + void log_timings(long long total_time,int game_object_count) const { + std::stringstream ss; + ss << std::endl <<"Function timings:\n"; // Starting with a header + for (const auto& [name, duration] : timings) { + ss << name << " took " << duration / 1000.0 << " ms (" << duration << " µs). " << std::endl; + } + ss << "Total time: " << total_time / 1000.0 << "ms (" << total_time << " µs)" << std::endl; + ss << "Amount of gameobjects: " << game_object_count << std::endl; + // Use GTest INFO macro to print the accumulated log without extra newlines + GTEST_LOG_(INFO) << ss.str(); + } +}; + +TEST_F(Profiling, Profiling_example) { + int game_object_count = 0; + long long total_time = 0; + while (total_time < 16000) { + game_object_count++; + { + //define gameobject used for testing + GameObject gameobject = mgr.new_object("gameobject","",{0,0}); + } + total_time = run_all_systems(); + if(game_object_count >= max_gameobject_count) break; + } + log_timings(total_time,game_object_count); + EXPECT_GE(game_object_count, min_gameobject_count); +} diff --git a/src/test/main.cpp b/src/test/main.cpp index 241015d..ec293a6 100644 --- a/src/test/main.cpp +++ b/src/test/main.cpp @@ -9,7 +9,7 @@ int main(int argc, char ** argv) { InitGoogleTest(&argc, argv); auto & cfg = Config::get_instance(); - cfg.log.level = Log::Level::ERROR; + cfg.log.level = Log::Level::DEBUG; return RUN_ALL_TESTS(); } -- cgit v1.2.3 From 327154fd428e0798eea544d9f073f8e1293aa158 Mon Sep 17 00:00:00 2001 From: WBoerenkamps Date: Mon, 25 Nov 2024 10:38:18 +0100 Subject: most test working --- src/crepe/api/Button.h | 3 +- src/crepe/api/EventManager.hpp | 2 +- src/crepe/api/UiObject.h | 4 +- src/crepe/facade/SDLContext.cpp | 86 +-------------- src/crepe/facade/SDLContext.h | 4 +- src/crepe/system/CMakeLists.txt | 2 + src/crepe/system/InputSystem.cpp | 125 +++++++++++++-------- src/crepe/system/InputSystem.h | 17 ++- src/test/CMakeLists.txt | 1 + src/test/EventTest.cpp | 66 ++++++----- src/test/inputTest.cpp | 231 ++++++++++++++++++++------------------- 11 files changed, 266 insertions(+), 275 deletions(-) (limited to 'src/test/CMakeLists.txt') diff --git a/src/crepe/api/Button.h b/src/crepe/api/Button.h index 9b1341f..709854a 100644 --- a/src/crepe/api/Button.h +++ b/src/crepe/api/Button.h @@ -1,3 +1,4 @@ +#pragma once #include #include "Component.h" @@ -6,7 +7,7 @@ namespace crepe { class Button : public UiObject{ public: - Button(); + Button(game_object_id_t id) : UiObject(id){}; bool interactable = true; bool is_toggle = false; bool is_pressed = false; diff --git a/src/crepe/api/EventManager.hpp b/src/crepe/api/EventManager.hpp index a5f4556..3eae90a 100644 --- a/src/crepe/api/EventManager.hpp +++ b/src/crepe/api/EventManager.hpp @@ -1,5 +1,5 @@ #pragma once - +#include #include "EventManager.h" namespace crepe { diff --git a/src/crepe/api/UiObject.h b/src/crepe/api/UiObject.h index 1d7be69..82140a0 100644 --- a/src/crepe/api/UiObject.h +++ b/src/crepe/api/UiObject.h @@ -4,12 +4,14 @@ #include "api/EventHandler.h" namespace crepe { + class UiObject : public Component{ public: - UiObject(); + UiObject(game_object_id_t id) : Component(id){}; int width = 0; int height = 0; public: virtual int get_instances_max() const { return 1; } }; + } diff --git a/src/crepe/facade/SDLContext.cpp b/src/crepe/facade/SDLContext.cpp index 1ef222c..f87cc61 100644 --- a/src/crepe/facade/SDLContext.cpp +++ b/src/crepe/facade/SDLContext.cpp @@ -76,75 +76,6 @@ SDLContext::~SDLContext() { SDL_Quit(); } -void SDLContext::handle_events(bool &running) { - EventManager& event_manager = EventManager::get_instance(); - SDL_Event event; - - while (SDL_PollEvent(&event)) { - switch (event.type) { - case SDL_QUIT: - running = false; - event_manager.trigger_event(ShutDownEvent{}); - break; - case SDL_KEYDOWN: - event_manager.trigger_event(KeyPressEvent{ - .repeat = (!event.key.repeat == 0), - .key = this->sdl_to_keycode(event.key.keysym.scancode) - }); - break; - - case SDL_KEYUP: - event_manager.trigger_event(KeyReleaseEvent{ - .key = this->sdl_to_keycode(event.key.keysym.scancode), - }); - break; - - case SDL_MOUSEBUTTONDOWN: - { - int x, y; - SDL_GetMouseState(&x, &y); - event_manager.trigger_event(MousePressEvent{ - .mouse_x = x, - .mouse_y = y, - .button = this->sdl_to_mousebutton(event.button.button) - }); - } - break; - - case SDL_MOUSEBUTTONUP: - { - int x, y; - SDL_GetMouseState(&x, &y); - event_manager.trigger_event(MouseReleaseEvent{ - .mouse_x = x, - .mouse_y = y, - .button = this->sdl_to_mousebutton(event.button.button) - }); - } - break; - - case SDL_MOUSEMOTION: - event_manager.trigger_event(MouseMoveEvent{ - .mouse_x = event.motion.x, - .mouse_y = event.motion.y, - .rel_x = event.motion.xrel, - .rel_y = event.motion.yrel - }); - break; - - case SDL_MOUSEWHEEL: - event_manager.trigger_event(MouseScrollEvent{ - .scroll_x = event.wheel.x, - .scroll_y = event.wheel.y, - .direction = (event.wheel.direction == SDL_MOUSEWHEEL_FLIPPED ? -1 : 1) - }); - break; - } - } -} - - - Keycode SDLContext::sdl_to_keycode(SDL_Keycode sdl_key) { static const std::array LOOKUP_TABLE = [] { std::array table{}; @@ -259,8 +190,8 @@ Keycode SDLContext::sdl_to_keycode(SDL_Keycode sdl_key) { return LOOKUP_TABLE[sdl_key]; } MouseButton SDLContext::sdl_to_mousebutton(Uint8 sdl_button) { - static const std::array MOUSE_BUTTON_LOOKUP_TABLE = [] { - std::array table{}; + static const std::array MOUSE_BUTTON_LOOKUP_TABLE = [] { + std::array table{}; table.fill(MouseButton::NONE); table[SDL_BUTTON_LEFT] = MouseButton::LEFT_MOUSE; @@ -409,7 +340,7 @@ std::vector SDLContext::get_events(){ event_list.push_back(EventData{ .event_type = SDLContext::Event::MOUSEDOWN, .mouse_button = sdl_to_mousebutton(event.button.button), - .mouse_position = {x,y}, + .mouse_position = {event.button.x,event.button.y}, }); } break; @@ -420,32 +351,27 @@ std::vector SDLContext::get_events(){ event_list.push_back(EventData{ .event_type = SDLContext::Event::MOUSEUP, .mouse_button = sdl_to_mousebutton(event.button.button), - .mouse_position = {x,y}, + .mouse_position = {event.button.x,event.button.y}, }); } break; case SDL_MOUSEMOTION: { - int x,y; - SDL_GetMouseState(&x, &y); event_list.push_back(EventData{ .event_type = SDLContext::Event::MOUSEMOVE, - .mouse_position = {x,y}, + .mouse_position = {event.button.x,event.button.y}, }); } break; case SDL_MOUSEWHEEL: { - int x, y; - SDL_GetMouseState(&x, &y); - event_list.push_back(EventData{ .event_type = SDLContext::Event::MOUSEWHEEL, .mouse_position = {event.motion.x,event.motion.y}, .wheel_delta = event.wheel.y, - .rel_mouse_move {event.motion.yrel,event.motion.xrel}, + .rel_mouse_move = {event.motion.yrel,event.motion.xrel}, }); } break; diff --git a/src/crepe/facade/SDLContext.h b/src/crepe/facade/SDLContext.h index 5b6b093..1b881d1 100644 --- a/src/crepe/facade/SDLContext.h +++ b/src/crepe/facade/SDLContext.h @@ -6,6 +6,7 @@ #include #include #include +#include #include #include @@ -43,7 +44,7 @@ public: MOUSEWHEEL, KEYUP, KEYDOWN, - SHUTDOWN + SHUTDOWN, }; struct EventData { @@ -73,7 +74,6 @@ private: * \brief Handles SDL events such as window close and input. * \param running Reference to a boolean flag that controls the main loop. */ - void handle_events(bool & running); std::vector get_events(); Keycode get_key(); diff --git a/src/crepe/system/CMakeLists.txt b/src/crepe/system/CMakeLists.txt index d658b25..95f6e33 100644 --- a/src/crepe/system/CMakeLists.txt +++ b/src/crepe/system/CMakeLists.txt @@ -6,6 +6,7 @@ target_sources(crepe PUBLIC CollisionSystem.cpp RenderSystem.cpp AnimatorSystem.cpp + InputSystem.cpp ) target_sources(crepe PUBLIC FILE_SET HEADERS FILES @@ -15,4 +16,5 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES CollisionSystem.h RenderSystem.h AnimatorSystem.h + InputSystem.h ) diff --git a/src/crepe/system/InputSystem.cpp b/src/crepe/system/InputSystem.cpp index c61a80f..4560411 100644 --- a/src/crepe/system/InputSystem.cpp +++ b/src/crepe/system/InputSystem.cpp @@ -1,7 +1,7 @@ #include "ComponentManager.h" -#include "../api/Button.h" + #include "../api/EventManager.h" -#include "../api/Transform.h" + #include "../facade/SDLContext.h" #include "../api/Event.h" @@ -14,32 +14,67 @@ using namespace crepe; void InputSystem::update() { EventManager& event_mgr = EventManager::get_instance(); std::vector event_list = SDLContext::get_instance().get_events(); - + for (SDLContext::EventData event : event_list) { switch (event.event_type) { case SDLContext::Event::KEYDOWN: { - event_mgr.queue_event(KeyPressEvent{ + event_mgr.queue_event(KeyPressEvent{ + .repeat = event.key_repeat, .key = event.key, - .repeat = event.key_repeat, }); break; } case SDLContext::Event::KEYUP: { - event_mgr.queue_event(KeyReleaseEvent{ + event_mgr.queue_event(KeyReleaseEvent{ .key = event.key, }); break; } case SDLContext::Event::MOUSEDOWN: { - event_mgr.queue_event(MousePressEvent{ + event_mgr.queue_event(MousePressEvent{ .mouse_x = event.mouse_position.first, .mouse_y = event.mouse_position.second, .button = event.mouse_button, }); + last_mouse_down_position = {event.mouse_position.first,event.mouse_position.second}; + last_mouse_button = event.mouse_button; break; } + case SDLContext::Event::MOUSEUP: { + MouseReleaseEvent mouse_release_event = MouseReleaseEvent{ + .mouse_x = event.mouse_position.first, + .mouse_y = event.mouse_position.second, + .button = event.mouse_button, + }; + event_mgr.queue_event(mouse_release_event); + + // Calculate deltas for click detection + int delta_x = event.mouse_position.first - last_mouse_down_position.first; + int delta_y = event.mouse_position.second - last_mouse_down_position.second; + + // Ensure last_mouse_button is properly set and matches the current mouse button + if (last_mouse_button == event.mouse_button && + std::abs(delta_x) <= click_tolerance && + std::abs(delta_y) <= click_tolerance) { + std::cout << "Click registered at (" << event.mouse_position.first + << ", " << event.mouse_position.second << ") with button " + << static_cast(event.mouse_button) << std::endl; + + event_mgr.queue_event(MouseClickEvent{ + .mouse_x = event.mouse_position.first, + .mouse_y = event.mouse_position.second, + .button = event.mouse_button, + }); + + this->handle_click(mouse_release_event); + } else { + std::cout << "Mouse release did not register as a click." << std::endl; + } + + break; + } case SDLContext::Event::MOUSEMOVE: { - event_mgr.queue_event(MouseMoveEvent{ + event_mgr.queue_event(MouseMoveEvent{ .mouse_x = event.mouse_position.first, .mouse_y = event.mouse_position.second, .rel_x = event.rel_mouse_move.first, @@ -47,27 +82,9 @@ void InputSystem::update() { }); break; } - case SDLContext::Event::MOUSEUP: { - event_mgr.queue_event(MouseReleaseEvent{ - .mouse_x = event.mouse_position.first, - .mouse_y = event.mouse_position.second, - .button = event.mouse_button, - }); - int delta_x = event.mouse_position.first - last_mouse_down_position.first; - int delta_y = event.mouse_position.second - last_mouse_down_position.second; - if (last_mouse_button == event.mouse_button && - std::abs(delta_x) <= click_tolerance && - std::abs(delta_y) <= click_tolerance) { - event_mgr.queue_event(MouseClickEvent{ - .mouse_x = event.mouse_position.first, - .mouse_y = event.mouse_position.second, - .button = event.mouse_button, - }); - } - break; - } + case SDLContext::Event::MOUSEWHEEL: { - event_mgr.queue_event(MouseScrollEvent{ + event_mgr.queue_event(MouseScrollEvent{ .scroll_x = event.mouse_position.first, .scroll_y = event.mouse_position.second, .direction = event.wheel_delta, @@ -75,7 +92,7 @@ void InputSystem::update() { break; } case SDLContext::Event::SHUTDOWN: { - event_mgr.queue_event(ShutDownEvent{}); + event_mgr.queue_event(ShutDownEvent{}); break; } default: @@ -84,24 +101,44 @@ void InputSystem::update() { } } -bool InputSystem::handle_click(const MouseClickEvent &event) { +void InputSystem::handle_click(const MouseReleaseEvent event) { ComponentManager &mgr = this->component_manager; - std::vector> buttons = - mgr.get_components_by_type