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/example/game.cpp | 89 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 src/example/game.cpp (limited to 'src/example/game.cpp') 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; +} -- cgit v1.2.3 From 02cdbd367d701d8d858806f45bfe2f15b392bb59 Mon Sep 17 00:00:00 2001 From: JAROWMR Date: Wed, 20 Nov 2024 11:37:49 +0100 Subject: made test function and fixed static value --- src/example/game.cpp | 5 ++-- src/test/CollisionTest.cpp | 60 +++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 56 insertions(+), 9 deletions(-) (limited to 'src/example/game.cpp') diff --git a/src/example/game.cpp b/src/example/game.cpp index a9f6103..b6a0c31 100644 --- a/src/example/game.cpp +++ b/src/example/game.cpp @@ -26,7 +26,6 @@ class MyScript : public Script { } void update() { // Retrieve component from the same GameObject this script is on - } }; @@ -35,8 +34,8 @@ public: using Scene::Scene; void load_scene() { - ComponentManager & mgr = this->component_manager; - Color color(0, 0, 0, 0); + ComponentManager & mgr = this->component_manager; + Color color(0, 0, 0, 0); double screen_size_width = 640; double screen_size_height = 480; diff --git a/src/test/CollisionTest.cpp b/src/test/CollisionTest.cpp index 3c2ee6e..5da26cc 100644 --- a/src/test/CollisionTest.cpp +++ b/src/test/CollisionTest.cpp @@ -1,3 +1,4 @@ +#include #include #include @@ -9,7 +10,8 @@ #include #include -#include +#include +#include using namespace std; @@ -19,10 +21,10 @@ using namespace crepe; class MyScript : public Script { public: - static crepe::CollisionSystem::CollisionInfo last_collision_info; + static const crepe::CollisionSystem::CollisionInfo* last_collision_info; private: static bool oncollision(const CollisionEvent& test) { - std::cout << "test collision: " << test.info.first.collider.game_object_id << std::endl; + last_collision_info = &test.info; return true; } void init() { @@ -37,14 +39,60 @@ class MyScript : public Script { class CollisionTest : public ::testing::Test { public: ComponentManager component_manager; - PhysicsSystem system{component_manager}; + CollisionSystem system{component_manager}; void SetUp() override { + MyScript::last_collision_info = nullptr; ComponentManager & mgr = this->component_manager; + if(mgr.get_components_by_id(0).empty()) + { + create_test_world(); + create_test_components(); + } + reset_test_components(); + } + + void create_test_world() { + double screen_size_width = 640; + double screen_size_height = 480; + double world_collider = 1000; + ComponentManager & mgr = this->component_manager; + 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 + } + + void create_test_components() + { + + } + + void reset_test_components() + { + } }; TEST_F(CollisionTest, collision) { -//read static data -const CollisionEvent& test = MyScript::last_collision_info; + // change object data before calling update + + // call collision system update + system.update(); + // should not be nullptr after update + ASSERT_NE(MyScript::last_collision_info, nullptr); + + // check if values are correct + EXPECT_EQ(MyScript::last_collision_info->first.collider.game_object_id, 1); + EXPECT_EQ(MyScript::last_collision_info->second.collider.game_object_id, 2); } -- 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/example/game.cpp') 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 3f63143b4005936da446fb2cdbbd1072b47fc8c1 Mon Sep 17 00:00:00 2001 From: JAROWMR Date: Fri, 22 Nov 2024 15:36:14 +0100 Subject: merge with master --- src/crepe/Collider.cpp | 2 +- src/crepe/Collider.h | 5 ++- src/crepe/api/BoxCollider.cpp | 2 +- src/crepe/api/BoxCollider.h | 2 +- src/crepe/api/CircleCollider.cpp | 2 +- src/crepe/api/CircleCollider.h | 2 +- src/crepe/api/LoopManager.cpp | 1 + src/crepe/api/Rigidbody.h | 2 +- src/crepe/system/CollisionSystem.cpp | 79 ++++++++++++++++++------------------ src/crepe/system/CollisionSystem.h | 8 ++-- src/example/CMakeLists.txt | 1 + src/example/game.cpp | 30 +++++++------- 12 files changed, 71 insertions(+), 65 deletions(-) (limited to 'src/example/game.cpp') diff --git a/src/crepe/Collider.cpp b/src/crepe/Collider.cpp index 0706371..80a944d 100644 --- a/src/crepe/Collider.cpp +++ b/src/crepe/Collider.cpp @@ -2,4 +2,4 @@ using namespace crepe; -Collider::Collider(game_object_id_t id, Vector2 offset) : Component(id), offset(offset) {} +Collider::Collider(game_object_id_t id, vec2 offset) : Component(id), offset(offset) {} diff --git a/src/crepe/Collider.h b/src/crepe/Collider.h index 0157324..5b26af5 100644 --- a/src/crepe/Collider.h +++ b/src/crepe/Collider.h @@ -3,16 +3,17 @@ #include "api/Vector2.h" #include "Component.h" +#include "types.h" namespace crepe { class Collider : public Component { public: - Collider(game_object_id_t id, Vector2 offset); + Collider(game_object_id_t id, vec2 offset); public: //! Offset of the collider relative to rigidbody position - Vector2 offset; + vec2 offset; }; } // namespace crepe diff --git a/src/crepe/api/BoxCollider.cpp b/src/crepe/api/BoxCollider.cpp index eafbdb2..83fb632 100644 --- a/src/crepe/api/BoxCollider.cpp +++ b/src/crepe/api/BoxCollider.cpp @@ -4,4 +4,4 @@ using namespace crepe; -BoxCollider::BoxCollider(game_object_id_t game_object_id,Vector2 offset, double width, double height) : Collider(game_object_id,offset), width(width), height(height) {} +BoxCollider::BoxCollider(game_object_id_t game_object_id,vec2 offset, double width, double height) : Collider(game_object_id,offset), width(width), height(height) {} diff --git a/src/crepe/api/BoxCollider.h b/src/crepe/api/BoxCollider.h index 7f51cba..6135954 100644 --- a/src/crepe/api/BoxCollider.h +++ b/src/crepe/api/BoxCollider.h @@ -12,7 +12,7 @@ namespace crepe { */ class BoxCollider : public Collider { public: - BoxCollider(game_object_id_t game_object_id,Vector2 offset, double width, double height); + BoxCollider(game_object_id_t game_object_id,vec2 offset, double width, double height); //! Width of box collider double width; diff --git a/src/crepe/api/CircleCollider.cpp b/src/crepe/api/CircleCollider.cpp index 04a4995..43de991 100644 --- a/src/crepe/api/CircleCollider.cpp +++ b/src/crepe/api/CircleCollider.cpp @@ -3,4 +3,4 @@ using namespace crepe; -CircleCollider::CircleCollider(game_object_id_t game_object_id,Vector2 offset, int radius) : Collider(game_object_id,offset), radius(radius) {} +CircleCollider::CircleCollider(game_object_id_t game_object_id,vec2 offset, int radius) : Collider(game_object_id,offset), radius(radius) {} diff --git a/src/crepe/api/CircleCollider.h b/src/crepe/api/CircleCollider.h index 4e04fa4..843547f 100644 --- a/src/crepe/api/CircleCollider.h +++ b/src/crepe/api/CircleCollider.h @@ -14,7 +14,7 @@ namespace crepe { class CircleCollider : public Collider { public: - CircleCollider(game_object_id_t game_object_id,Vector2 offset, int radius); + CircleCollider(game_object_id_t game_object_id,vec2 offset, int radius); //! Radius of the circle collider. double radius; diff --git a/src/crepe/api/LoopManager.cpp b/src/crepe/api/LoopManager.cpp index 586919d..10b59c8 100644 --- a/src/crepe/api/LoopManager.cpp +++ b/src/crepe/api/LoopManager.cpp @@ -63,6 +63,7 @@ void LoopManager::setup() { this->game_running = true; LoopTimer::get_instance().start(); LoopTimer::get_instance().set_fps(60); + this->scene_manager.load_next_scene(); } void LoopManager::render() { diff --git a/src/crepe/api/Rigidbody.h b/src/crepe/api/Rigidbody.h index b96b463..7939563 100644 --- a/src/crepe/api/Rigidbody.h +++ b/src/crepe/api/Rigidbody.h @@ -78,7 +78,7 @@ public: //! bounce factor of material double elastisity = 0.0; //! offset of all colliders relative to transform position - Vector2 offset; + vec2 offset; }; public: diff --git a/src/crepe/system/CollisionSystem.cpp b/src/crepe/system/CollisionSystem.cpp index 9ca8b3a..8d9b356 100644 --- a/src/crepe/system/CollisionSystem.cpp +++ b/src/crepe/system/CollisionSystem.cpp @@ -15,6 +15,7 @@ #include "ComponentManager.h" #include "CollisionSystem.h" #include "Collider.h" +#include "types.h" using namespace crepe; @@ -39,7 +40,7 @@ void CollisionSystem::collision_handler(CollidedInfoStor& data1,CollidedInfoStor // Data needed for collision handler info const Collider* collider1 = nullptr; const Collider* collider2 = nullptr; - Vector2 move_back; + vec2 move_back; // Check collision type and get values for handler if (std::holds_alternative>(data1.collider)) { @@ -53,8 +54,8 @@ void CollisionSystem::collision_handler(CollidedInfoStor& data1,CollidedInfoStor // TODO: send with the collider info to this function because this is calculated previously // Get the current position of the collider - Vector2 final_position1 = current_position(box_collider1,data1.transform,data1.rigidbody); - Vector2 final_position2 = current_position(box_collider2,data2.transform,data2.rigidbody); + vec2 final_position1 = current_position(box_collider1,data1.transform,data1.rigidbody); + vec2 final_position2 = current_position(box_collider2,data2.transform,data2.rigidbody); // Determine move_back value for smallest overlap (x or y) move_back = box_box_collision_move_back(box_collider1,box_collider2,final_position1,final_position2); @@ -112,20 +113,20 @@ void CollisionSystem::collision_handler(CollidedInfoStor& data1,CollidedInfoStor } -Vector2 CollisionSystem::box_box_collision_move_back(const BoxCollider& box_collider1,const BoxCollider& box_collider2,Vector2 final_position1,Vector2 final_position2) +vec2 CollisionSystem::box_box_collision_move_back(const BoxCollider& box_collider1,const BoxCollider& box_collider2,vec2 final_position1,vec2 final_position2) { - Vector2 resolution; // Default resolution vector - Vector2 delta = final_position2 - final_position1; + vec2 resolution; // Default resolution vector + vec2 delta = final_position2 - final_position1; // Compute half-dimensions of the boxes - double half_width1 = box_collider1.width / 2.0; - double half_height1 = box_collider1.height / 2.0; - double half_width2 = box_collider2.width / 2.0; - double half_height2 = box_collider2.height / 2.0; + float half_width1 = box_collider1.width / 2.0; + float half_height1 = box_collider1.height / 2.0; + float half_width2 = box_collider2.width / 2.0; + float half_height2 = box_collider2.height / 2.0; // Calculate overlaps along X and Y axes - double overlap_x = (half_width1 + half_width2) - std::abs(delta.x); - double overlap_y = (half_height1 + half_height2) - std::abs(delta.y); + float overlap_x = (half_width1 + half_width2) - std::abs(delta.x); + float overlap_y = (half_height1 + half_height2) - std::abs(delta.y); // Check if there is a collision if (overlap_x > 0 && overlap_y > 0) {//should always be true check if this can be removed @@ -288,14 +289,14 @@ std::vector(oncollision, this->get_game_object_id()); + EventManager::get_instance().subscribe(oncollision, 0); } void update() { // Retrieve component from the same GameObject this script is on } }; + class ConcreteScene1 : public Scene { public: using Scene::Scene; @@ -37,11 +38,11 @@ public: 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; + float screen_size_width = 640; + float screen_size_height = 480; + float world_collider = 1000; //define playable world - GameObject world = mgr.new_object("Name", "Tag", Vector2{screen_size_width/2, screen_size_height/2}, 0, 1); + GameObject world = mgr.new_object("Name", "Tag", vec2{screen_size_width/2, screen_size_height/2}, 0, 1); world.add_component(Rigidbody::Data{ .mass = 0, .gravity_scale = 0, @@ -51,13 +52,13 @@ public: .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 + world.add_component(vec2{0, 0-(screen_size_height/2+world_collider/2)}, world_collider, world_collider);; // Top + world.add_component(vec2{0, screen_size_height/2+world_collider/2}, world_collider, world_collider); // Bottom + world.add_component(vec2{0-(screen_size_width/2+world_collider/2), 0}, world_collider, world_collider); // Left + world.add_component(vec2{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); + GameObject game_object1 = mgr.new_object("Name", "Tag", vec2{screen_size_width/2, screen_size_height/2}, 0, 1); game_object1.add_component(Rigidbody::Data{ .mass = 1, .gravity_scale = 0.01, @@ -69,20 +70,21 @@ public: .elastisity = 1, .offset = {0,0}, }); - game_object1.add_component(Vector2{0, 0}, 20, 20); + game_object1.add_component(vec2{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::WHITE); } + + string get_name() const { return "scene1"; } }; int main(int argc, char * argv[]) { LoopManager gameloop; - gameloop.scene_manager.add_scene("scene1"); - gameloop.scene_manager.load_next_scene(); + gameloop.add_scene(); gameloop.start(); return 0; } -- cgit v1.2.3 From bcf57e81f68913049f84cabb66871931c8f47b2b Mon Sep 17 00:00:00 2001 From: JAROWMR Date: Fri, 22 Nov 2024 16:11:39 +0100 Subject: script fix --- src/crepe/api/Config.h | 2 +- src/crepe/api/LoopManager.cpp | 1 + src/example/game.cpp | 6 ++++-- src/test/CollisionTest.cpp | 7 +++---- 4 files changed, 9 insertions(+), 7 deletions(-) (limited to 'src/example/game.cpp') diff --git a/src/crepe/api/Config.h b/src/crepe/api/Config.h index 13eabd1..b6c2ccf 100644 --- a/src/crepe/api/Config.h +++ b/src/crepe/api/Config.h @@ -33,7 +33,7 @@ public: * * Only messages with equal or higher priority than this value will be logged. */ - Log::Level level = Log::Level::INFO; + Log::Level level = Log::Level::DEBUG; /** * \brief Colored log output * diff --git a/src/crepe/api/LoopManager.cpp b/src/crepe/api/LoopManager.cpp index 10b59c8..ff8b90e 100644 --- a/src/crepe/api/LoopManager.cpp +++ b/src/crepe/api/LoopManager.cpp @@ -35,6 +35,7 @@ void LoopManager::start() { void LoopManager::set_running(bool running) { this->game_running = running; } void LoopManager::fixed_update() { + this->get_system().update(); this->get_system().update(); this->get_system().update(); } diff --git a/src/example/game.cpp b/src/example/game.cpp index f6b580a..991d2ec 100644 --- a/src/example/game.cpp +++ b/src/example/game.cpp @@ -17,12 +17,14 @@ using namespace crepe; using namespace std; class MyScript : public Script { - static bool oncollision(const CollisionEvent& test) { + bool oncollision(const CollisionEvent& test) { Log::logf("Box {} script on_collision()", test.info.first.collider.game_object_id); return true; } void init() { - EventManager::get_instance().subscribe(oncollision, 0); + subscribe([this](const CollisionEvent& ev) -> bool { + return this->oncollision(ev); + }); } void update() { // Retrieve component from the same GameObject this script is on diff --git a/src/test/CollisionTest.cpp b/src/test/CollisionTest.cpp index c175eb4..bbf6348 100644 --- a/src/test/CollisionTest.cpp +++ b/src/test/CollisionTest.cpp @@ -25,7 +25,6 @@ using namespace testing; class CollisionHandler : public Script { public: int box_id; - EventManager & evmgr = EventManager::get_instance(); function test_fn = [](const CollisionEvent & ev) { }; CollisionHandler(int box_id) { @@ -42,9 +41,9 @@ public: //Log::logf("Box {} script init()", box_id); // TODO: this should be built into script - evmgr.subscribe([this](const CollisionEvent & ev) { - return this->on_collision(ev); - }, this->get_game_object_id()); + subscribe([](const CollisionEvent&) -> bool { + return true; + }); } }; -- cgit v1.2.3 From 2a37965c797e1ef03ec10ea8bf503d7605465f11 Mon Sep 17 00:00:00 2001 From: JAROWMR Date: Fri, 22 Nov 2024 21:17:30 +0100 Subject: refactored collision system --- src/crepe/system/CollisionSystem.cpp | 317 ++++++++++++++++++----------------- src/crepe/system/CollisionSystem.h | 133 ++++----------- src/example/game.cpp | 4 +- 3 files changed, 198 insertions(+), 256 deletions(-) (limited to 'src/example/game.cpp') diff --git a/src/crepe/system/CollisionSystem.cpp b/src/crepe/system/CollisionSystem.cpp index 8d9b356..f61a1dd 100644 --- a/src/crepe/system/CollisionSystem.cpp +++ b/src/crepe/system/CollisionSystem.cpp @@ -1,8 +1,11 @@ #include #include #include +#include #include #include +#include +#include #include "api/Event.h" #include "api/EventManager.h" @@ -16,6 +19,7 @@ #include "CollisionSystem.h" #include "Collider.h" #include "types.h" +#include "util/OptionalRef.h" using namespace crepe; @@ -24,69 +28,88 @@ void CollisionSystem::update() { ComponentManager & mgr = this->component_manager; std::vector> boxcolliders = mgr.get_components_by_type(); std::vector> circlecolliders = mgr.get_components_by_type(); + + std::vector all_colliders; + // Add BoxCollider references + for (auto& box : boxcolliders) { + all_colliders.push_back(collider_stor{box}); + } + + // Add CircleCollider references + for (auto& circle : circlecolliders) { + all_colliders.push_back(collider_stor{circle}); + } // Check between all colliders if there is a collision - std::vector> collided = check_collisions(boxcolliders,circlecolliders); + std::vector> collided = check_collisions(all_colliders); // For both objects call the collision handler for (auto& collision_pair : collided) { - collision_handler(collision_pair.first,collision_pair.second); - collision_handler(collision_pair.second,collision_pair.first); + collision_handler_request(collision_pair.first,collision_pair.second); + collision_handler_request(collision_pair.second,collision_pair.first); } } -void CollisionSystem::collision_handler(CollidedInfoStor& data1,CollidedInfoStor& data2){ +void CollisionSystem::collision_handler_request(CollidedInfoStor& data1,CollidedInfoStor& data2){ - // Data needed for collision handler info - const Collider* collider1 = nullptr; - const Collider* collider2 = nullptr; - vec2 move_back; + ColliderStorType type = check_collider_type(data1.collider,data2.collider); + std::pair move_back_data = collision_handler(data1,data2,type); - // Check collision type and get values for handler - if (std::holds_alternative>(data1.collider)) { - if (std::holds_alternative>(data2.collider)) { - - // Get colliders from variant to be used to determine collision handler info - const BoxCollider& box_collider1 = std::get>(data1.collider).get(); - const BoxCollider& box_collider2 = std::get>(data2.collider).get(); - collider1 = &box_collider1; - collider2 = &box_collider2; - - // TODO: send with the collider info to this function because this is calculated previously - // Get the current position of the collider - vec2 final_position1 = current_position(box_collider1,data1.transform,data1.rigidbody); - vec2 final_position2 = current_position(box_collider2,data2.transform,data2.rigidbody); - - // Determine move_back value for smallest overlap (x or y) - move_back = box_box_collision_move_back(box_collider1,box_collider2,final_position1,final_position2); - + OptionalRef collider1; + OptionalRef collider2; + switch (type) { + case ColliderStorType::BOX_BOX:{ + collider1 = std::get>(data1.collider); + collider2 = std::get>(data2.collider); } - else { - // TODO: calcualte Box - Circle collision info - const BoxCollider& box_collider = std::get>(data1.collider).get(); - const CircleCollider& circle_collider = std::get>(data2.collider).get(); - collider1 = &box_collider; - collider2 = &circle_collider; + case ColliderStorType::BOX_CIRCLE:{ + collider1 = std::get>(data1.collider); + collider2 = std::get>(data2.collider); + } + case ColliderStorType::CIRCLE_BOX:{ + collider1 = std::get>(data1.collider); + collider2 = std::get>(data2.collider); + } + case ColliderStorType::CIRCLE_CIRCLE:{ + collider1 = std::get>(data1.collider); + collider2 = std::get>(data2.collider); } } - else { - if (std::holds_alternative>(data2.collider)) { - // TODO: calcualte Circle - Circle collision info - const CircleCollider& circle_collider1 = std::get>(data1.collider).get(); - const CircleCollider& circle_collider2 = std::get>(data2.collider).get(); - collider1 = &circle_collider1; - collider2 = &circle_collider2; + + // collision info + crepe::CollisionSystem::CollisionInfo collision_info{ + .first={ collider1, data1.transform, data1.rigidbody }, + .second={ collider2, data2.transform, data2.rigidbody }, + .move_back_value = move_back_data.first, + .move_back_direction = move_back_data.second, + }; + + // Determine if static needs to be called + determine_collision_handler(collision_info); +} + + +std::pair CollisionSystem::collision_handler(CollidedInfoStor& data1,CollidedInfoStor& data2,ColliderStorType type) { + vec2 move_back; + switch (type) { + case ColliderStorType::BOX_BOX: { + const BoxCollider & collider1 = std::get>(data1.collider); + const BoxCollider & collider2 = std::get>(data2.collider); + vec2 collider_pos1 = current_position(collider1.offset, data1.transform, data1.rigidbody); + vec2 collider_pos2 = current_position(collider2.offset, data2.transform, data2.rigidbody); + move_back = box_box_move_back(collider1,collider2,collider_pos1,collider_pos2); } - else { - // TODO: calcualte Circle - Box collision info - const CircleCollider& circle_collider = std::get>(data1.collider); - const BoxCollider& box_collider = std::get>(data2.collider); - collider1 = &circle_collider; - collider2 = &box_collider; + case ColliderStorType::BOX_CIRCLE: { + + } + case ColliderStorType::CIRCLE_CIRCLE: { + + } + case ColliderStorType::CIRCLE_BOX: { + } } - // One vaue is calculated for moving back. Calculate the other value (x or y) relateive to the move_back value. Direction move_back_direction = Direction::NONE; if(move_back.x != 0 && move_back.y > 0) { move_back_direction = Direction::BOTH; @@ -100,20 +123,10 @@ void CollisionSystem::collision_handler(CollidedInfoStor& data1,CollidedInfoStor move_back.x = data1.rigidbody.data.linear_velocity.x * (move_back.y/data1.rigidbody.data.linear_velocity.y); } - // collision info - crepe::CollisionSystem::CollisionInfo collision_info{ - .first={ *collider1, data1.transform, data1.rigidbody }, - .second={ *collider2, data2.transform, data2.rigidbody }, - .move_back_value = move_back, - .move_back_direction = move_back_direction, - }; - - // Determine if static needs to be called - determine_collision_handler(collision_info); + return {move_back,move_back_direction}; } - -vec2 CollisionSystem::box_box_collision_move_back(const BoxCollider& box_collider1,const BoxCollider& box_collider2,vec2 final_position1,vec2 final_position2) +vec2 CollisionSystem::box_box_move_back(const BoxCollider& box_collider1,const BoxCollider& box_collider2,vec2 final_position1,vec2 final_position2) { vec2 resolution; // Default resolution vector vec2 delta = final_position2 - final_position1; @@ -185,10 +198,9 @@ void CollisionSystem::static_collision_handler(CollisionInfo& info){ } } -std::vector> CollisionSystem::check_collisions(const std::vector>& boxcolliders, const std::vector>& circlecolliders) { - ComponentManager & mgr = this->component_manager; - std::vector> collisions_ret; - +std::vector> CollisionSystem::check_collisions(std::vector & colliders) { + + // TODO: // If no colliders skip // Check if colliders has rigidbody if not skip @@ -198,99 +210,104 @@ std::vector(game_object_id_1).front().get(); - if(!transform1.active) continue; - Rigidbody& rigidbody1 = mgr.get_components_by_id(game_object_id_1).front().get(); - if(!rigidbody1.active) continue; - - // Check BoxCollider vs BoxCollider - for (size_t j = i + 1; j < boxcolliders.size(); ++j) { - if(!boxcolliders[j].get().active) continue; - // Skip self collision - int game_object_id_2 = boxcolliders[j].get().game_object_id; - if (game_object_id_1 == game_object_id_2) continue; - - // Fetch components for the second box collider - Transform & transform2 = mgr.get_components_by_id(boxcolliders[j].get().game_object_id).front().get(); - if(!transform2.active) continue; - Rigidbody & rigidbody2 = mgr.get_components_by_id(boxcolliders[j].get().game_object_id).front().get(); - if(!rigidbody2.active) continue; - // Check collision - if (check_box_box_collision(boxcolliders[i], boxcolliders[j], transform1, transform2, rigidbody1, rigidbody2)) { - collisions_ret.emplace_back(std::make_pair( - CollidedInfoStor{boxcolliders[i].get(), transform1, rigidbody1}, - CollidedInfoStor{boxcolliders[j].get(), transform2, rigidbody2} - )); - } - } + // Function to retrieve active transform and rigidbody components for a given game_object_id + auto get_active_transform_and_rigidbody = [&](game_object_id_t game_object_id) + -> std::optional, std::reference_wrapper>> { + RefVector transforms = this->component_manager.get_components_by_id(game_object_id); + if (transforms.empty()) return std::nullopt; + + RefVector rigidbodies = this->component_manager.get_components_by_id(game_object_id); + if (rigidbodies.empty()) return std::nullopt; + + Transform& transform = transforms.front().get(); + if (!transform.active) return std::nullopt; + + Rigidbody& rigidbody = rigidbodies.front().get(); + if (!rigidbody.active) return std::nullopt; - // Check BoxCollider vs CircleCollider - for (size_t j = 0; j < circlecolliders.size(); ++j) { - if(!circlecolliders[j].get().active) continue; - // Skip self collision - int game_object_id_2 = circlecolliders[j].get().game_object_id; - if (game_object_id_1 == game_object_id_2) continue; - - // Fetch components for the second collider (circle) - Transform & transform2 = mgr.get_components_by_id(circlecolliders[j].get().game_object_id).front().get(); - if(!transform2.active) continue; - Rigidbody & rigidbody2 = mgr.get_components_by_id(circlecolliders[j].get().game_object_id).front().get(); - if(!rigidbody2.active) continue; - - // Check collision - if (check_box_circle_collision(boxcolliders[i], circlecolliders[j], transform1, transform2, rigidbody1, rigidbody2)) { - - collisions_ret.emplace_back(std::make_pair( - CollidedInfoStor{boxcolliders[i].get(), transform1, rigidbody1}, - CollidedInfoStor{circlecolliders[j].get(), transform2, rigidbody2} - )); + // Return the active components + return std::make_pair(std::ref(transform), std::ref(rigidbody)); + }; + + + std::vector> collisions_ret; + for (size_t i = 0; i < colliders.size(); ++i) { + std::visit([&](auto& inner_collider_ref) { + if (inner_collider_ref.get().active) return; + auto inner_components = get_active_transform_and_rigidbody(inner_collider_ref.get().game_object_id); + if (inner_components) return; + for (size_t j = i + 1; j < colliders.size(); ++j) { + std::visit([&](auto& outer_collider_ref) { + if (outer_collider_ref.get().active) return; + if (inner_collider_ref.get().game_object_id == outer_collider_ref.get().game_object_id) return; + auto outer_components = get_active_transform_and_rigidbody(inner_collider_ref.get().game_object_id); + if (outer_components) return; + ColliderStorType type = check_collider_type(colliders[i],colliders[j]); + check_collision(colliders[i],*inner_components,colliders[j],*outer_components,type); + collisions_ret.emplace_back( + CollidedInfoStor{colliders[i], inner_components->first.get(), inner_components->second.get()}, + CollidedInfoStor{colliders[j], outer_components->first.get(), outer_components->second.get()} + ); + }, colliders[j]); } + }, colliders[i]); + } + + return collisions_ret; +} + +CollisionSystem::ColliderStorType CollisionSystem::check_collider_type(const collider_stor& collider1,const collider_stor& collider2){ + if(std::holds_alternative>(collider1)){ + if(std::holds_alternative>(collider2)) + { + return ColliderStorType::CIRCLE_CIRCLE; + } + else { + return ColliderStorType::CIRCLE_BOX; } } - // Check CircleCollider vs CircleCollider - for (size_t i = 0; i < circlecolliders.size(); ++i) { - if(!circlecolliders[i].get().active) continue; - // Fetch components for the first circle collider - int game_object_id_1 = circlecolliders[i].get().game_object_id; - Transform & transform1 = mgr.get_components_by_id(circlecolliders[i].get().game_object_id).front().get(); - if(!transform1.active) continue; - Rigidbody & rigidbody1 = mgr.get_components_by_id(circlecolliders[i].get().game_object_id).front().get(); - if(!rigidbody1.active) continue; - - for (size_t j = i + 1; j < circlecolliders.size(); ++j) { - if(!circlecolliders[j].get().active) continue; - // Skip self collision - int game_object_id_2 = circlecolliders[j].get().game_object_id; - if (game_object_id_1 == game_object_id_2) continue; - - // Fetch components for the second circle collider - Transform & transform2 = mgr.get_components_by_id(circlecolliders[j].get().game_object_id).front().get(); - if(!transform2.active) continue; - Rigidbody & rigidbody2 = mgr.get_components_by_id(circlecolliders[j].get().game_object_id).front().get(); - if(!rigidbody2.active) continue; - - // Check collision - if (check_circle_circle_collision(circlecolliders[i], circlecolliders[j], transform1, transform2, rigidbody1, rigidbody2)) { - collisions_ret.emplace_back(std::make_pair( - CollidedInfoStor{circlecolliders[i].get(), transform1, rigidbody1}, - CollidedInfoStor{circlecolliders[j].get(), transform2, rigidbody2} - )); - } + else { + if(std::holds_alternative>(collider2)) + { + return ColliderStorType::BOX_CIRCLE; + } + else { + return ColliderStorType::BOX_BOX; } } - return collisions_ret; } +bool CollisionSystem::check_collision(const collider_stor& collider1,std::pair, std::reference_wrapper> components1,const collider_stor& collider2,std::pair, std::reference_wrapper> components2, ColliderStorType type){ + switch (type) { + case ColliderStorType::BOX_BOX: { + const BoxCollider & box_collider1 = std::get>(collider1); + const BoxCollider & box_collider2 = std::get>(collider2); + return check_box_box_collision(box_collider1,box_collider2,components1.first.get(),components2.first.get(),components1.second.get(),components2.second.get()); + } + case ColliderStorType::BOX_CIRCLE: { + const BoxCollider & box_collider = std::get>(collider1); + const CircleCollider & circle_collider = std::get>(collider2); + return check_box_circle_collision(box_collider,circle_collider,components1.first.get(),components2.first.get(),components1.second.get(),components2.second.get()); + } + case ColliderStorType::CIRCLE_CIRCLE: { + const CircleCollider & circle_collider1 = std::get>(collider1); + const CircleCollider & circle_collider2 = std::get>(collider2); + return check_circle_circle_collision(circle_collider1,circle_collider2,components1.first.get(),components2.first.get(),components1.second.get(),components2.second.get()); + } + case ColliderStorType::CIRCLE_BOX: { + const BoxCollider & box_collider = std::get>(collider1); + const CircleCollider & circle_collider = std::get>(collider2); + return check_box_circle_collision(box_collider,circle_collider,components1.first.get(),components2.first.get(),components1.second.get(),components2.second.get()); + } + } +} + + bool CollisionSystem::check_box_box_collision(const BoxCollider& box1, const BoxCollider& box2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2) { // Get current positions of colliders - vec2 final_position1 = current_position(box1,transform1,rigidbody1); - vec2 final_position2 = current_position(box2,transform2,rigidbody2); + vec2 final_position1 = current_position(box1.offset,transform1,rigidbody1); + vec2 final_position2 = current_position(box2.offset,transform2,rigidbody2); // Calculate half-extents (half width and half height) float half_width1 = box1.width / 2.0; @@ -307,8 +324,8 @@ bool CollisionSystem::check_box_box_collision(const BoxCollider& box1, const Box bool CollisionSystem::check_box_circle_collision(const BoxCollider& box1, const CircleCollider& circle2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2) { // Get current positions of colliders - vec2 final_position1 = current_position(box1, transform1, rigidbody1); - vec2 final_position2 = current_position(circle2, transform2, rigidbody2); + vec2 final_position1 = current_position(box1.offset, transform1, rigidbody1); + vec2 final_position2 = current_position(circle2.offset, transform2, rigidbody2); // Calculate box half-extents float half_width = box1.width / 2.0; @@ -329,8 +346,8 @@ bool CollisionSystem::check_box_circle_collision(const BoxCollider& box1, const bool CollisionSystem::check_circle_circle_collision(const CircleCollider& circle1, const CircleCollider& circle2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2) { // Get current positions of colliders - vec2 final_position1 = current_position(circle1,transform1,rigidbody1); - vec2 final_position2 = current_position(circle2,transform2,rigidbody2); + vec2 final_position1 = current_position(circle1.offset,transform1,rigidbody1); + vec2 final_position2 = current_position(circle2.offset,transform2,rigidbody2); float distance_x = final_position1.x - final_position2.x; float distance_y = final_position1.y - final_position2.y; @@ -343,12 +360,12 @@ bool CollisionSystem::check_circle_circle_collision(const CircleCollider& circle return distance_squared <= radius_sum * radius_sum; } -vec2 CollisionSystem::current_position(const Collider& collider, const Transform& transform, const Rigidbody& rigidbody) { +vec2 CollisionSystem::current_position(vec2 collider_offset, const Transform& transform, const Rigidbody& rigidbody) { // Get the rotation in radians float radians1 = transform.rotation * (M_PI / 180.0); // Calculate total offset with scale - vec2 total_offset = (rigidbody.data.offset + collider.offset) * transform.scale; + vec2 total_offset = (rigidbody.data.offset + collider_offset) * transform.scale; // Rotate float rotated_total_offset_x1 = total_offset.x * cos(radians1) - total_offset.y * sin(radians1); diff --git a/src/crepe/system/CollisionSystem.h b/src/crepe/system/CollisionSystem.h index 44fff4e..80f8818 100644 --- a/src/crepe/system/CollisionSystem.h +++ b/src/crepe/system/CollisionSystem.h @@ -25,6 +25,15 @@ private: // using collider_stor = std::variant; using collider_stor = std::variant, std::reference_wrapper>; + //! A enum that is used to tell the pair of the collider stor in a std::pair. + enum class ColliderStorType { + BOX_BOX, + CIRCLE_CIRCLE, + BOX_CIRCLE, + CIRCLE_BOX, + }; + + /** * \brief A structure to store the collision data of a single collider. * @@ -32,7 +41,7 @@ private: */ struct CollidedInfoStor { //! Store either BoxCollider or CircleCollider - collider_stor collider; + collider_stor& collider; Transform& transform; Rigidbody& rigidbody; }; @@ -45,6 +54,8 @@ private: BOTH }; + + public: /** * \brief A structure representing the collision information between two colliders. @@ -73,121 +84,35 @@ public: //! Updates the collision system by checking for collisions between colliders and handling them. void update() override; +private: //generic + ColliderStorType check_collider_type(const collider_stor& collider1,const collider_stor& collider2); + + vec2 current_position(vec2 collider_offset, const Transform& transform, const Rigidbody& rigidbody); + +private:// handeling + + void collision_handler_request(CollidedInfoStor& data1,CollidedInfoStor& data2); + + std::pair collision_handler(CollidedInfoStor& data1,CollidedInfoStor& data2 ,ColliderStorType type); + -private: - /** - * \brief Handles a collision between two colliders. - * - * This function calculates the necessary response to resolve the collision, including - * moving the objects back to prevent overlap and applying any velocity changes. - * - * \param data1 The collision data for the first collider. - * \param data2 The collision data for the second collider. - */ - void collision_handler(CollidedInfoStor& data1,CollidedInfoStor& data2); - /** - * \brief Resolves the movement of two box colliders that are colliding. - * - * This function calculates the smallest overlap (along the X or Y axis) and determines - * the move-back vector to prevent overlap. - * - * \param box_collider1 The first box collider. - * \param box_collider2 The second box collider. - * \param final_position1 The final position of the first box collider. - * \param final_position2 The final position of the second box collider. - * \return The move-back vector to resolve the collision. - */ - vec2 box_box_collision_move_back(const BoxCollider& box_collider1,const BoxCollider& box_collider2,vec2 position1,vec2 position2); + vec2 box_box_move_back(const BoxCollider& box_collider1,const BoxCollider& box_collider2,vec2 position1,vec2 position2); - /** - * \brief Determines the appropriate collision handler based on the rigidbody types of the colliding objects. - * - * This function checks if the second object is static, and if so, it calls the static collision handler. - * Otherwise, it triggers a collision event. - * - * \param info The collision information containing the colliders, transforms, rigidbodies, and move-back data. - */ void determine_collision_handler(CollisionInfo& info); - /** - * \brief Handles the collision with a static object. - * - * This function resolves the collision by moving the object back and applying any bounce or stop behavior. - * - * \param info The collision information containing the colliders, transforms, rigidbodies, and move-back data. - */ void static_collision_handler(CollisionInfo& info); -private: //detection +private: // detection - /** - * \brief Checks for collisions between box colliders and circle colliders - * and returns the collision pairs that need to be resolved. - * - * \param boxcolliders A vector of references to all box colliders. - * \param circlecolliders A vector of references to all circle colliders. - * \return A vector of pairs containing collision information for the detected collisions. - */ - std::vector> check_collisions(const std::vector>& boxcolliders, const std::vector>& circlecolliders); + std::vector> check_collisions(std::vector & colliders); + + bool check_collision(const collider_stor& collider1,std::pair, std::reference_wrapper> components1,const collider_stor& collider2,std::pair, std::reference_wrapper> components2,CollisionSystem::ColliderStorType type); - /** - * \brief Checks for a collision between two box colliders. - * - * This function checks if two box colliders overlap based on their positions and dimensions. - * - * \param box1 The first box collider. - * \param box2 The second box collider. - * \param transform1 The transform component of the first box collider. - * \param transform2 The transform component of the second box collider. - * \param rigidbody1 The rigidbody component of the first box collider. - * \param rigidbody2 The rigidbody component of the second box collider. - * \return True if the two box colliders overlap, otherwise false. - */ bool check_box_box_collision(const BoxCollider& box1, const BoxCollider& box2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2); - /** - * \brief Checks for a collision between a box collider and a circle collider. - * - * This function checks if a box collider overlaps with a circle collider based on their positions - * and dimensions. - * - * \param box1 The box collider. - * \param circle2 The circle collider. - * \param transform1 The transform component of the box collider. - * \param transform2 The transform component of the circle collider. - * \param rigidbody1 The rigidbody component of the box collider. - * \param rigidbody2 The rigidbody component of the circle collider. - * \return True if the box collider and circle collider overlap, otherwise false. - */ bool check_box_circle_collision(const BoxCollider& box1, const CircleCollider& circle2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2); - - /** - * \brief Checks for a collision between two circle colliders. - * - * This function checks if two circle colliders overlap based on their positions and radii. - * - * \param circle1 The first circle collider. - * \param circle2 The second circle collider. - * \param transform1 The transform component of the first circle collider. - * \param transform2 The transform component of the second circle collider. - * \param rigidbody1 The rigidbody component of the first circle collider. - * \param rigidbody2 The rigidbody component of the second circle collider. - * \return True if the two circle colliders overlap, otherwise false. - */ + bool check_circle_circle_collision(const CircleCollider& circle1, const CircleCollider& circle2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2); - - /** - * \brief Gets the current position of a collider by combining its transform and rigidbody data. - * - * This function calculates the current position of the collider by considering its transform and - * rigidbody velocity. - * - * \param collider The collider whose position is being determined. - * \param transform The transform component associated with the collider. - * \param rigidbody The rigidbody component associated with the collider. - * \return The current position of the collider as a vec2. - */ - vec2 current_position(const Collider& collider, const Transform& transform, const Rigidbody& rigidbody); }; } // namespace crepe diff --git a/src/example/game.cpp b/src/example/game.cpp index 991d2ec..afa8c10 100644 --- a/src/example/game.cpp +++ b/src/example/game.cpp @@ -65,9 +65,9 @@ public: .mass = 1, .gravity_scale = 0.01, .body_type = Rigidbody::BodyType::DYNAMIC, - .linear_velocity = {1,0}, + .linear_velocity = {1,1}, .constraints = {0, 0, 0}, - .use_gravity = true, + .use_gravity = false, .bounce = true, .elastisity = 1, .offset = {0,0}, -- cgit v1.2.3 From b6d255762de0bfd5dd096f7eae295a6b1b357bbb Mon Sep 17 00:00:00 2001 From: JAROWMR Date: Fri, 22 Nov 2024 22:01:18 +0100 Subject: added gravity to object --- src/example/game.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/example/game.cpp') diff --git a/src/example/game.cpp b/src/example/game.cpp index afa8c10..e851526 100644 --- a/src/example/game.cpp +++ b/src/example/game.cpp @@ -67,7 +67,7 @@ public: .body_type = Rigidbody::BodyType::DYNAMIC, .linear_velocity = {1,1}, .constraints = {0, 0, 0}, - .use_gravity = false, + .use_gravity = true, .bounce = true, .elastisity = 1, .offset = {0,0}, -- cgit v1.2.3 From 4bbc27098d5a8907ab0500ad3ccc82283cf95ddf Mon Sep 17 00:00:00 2001 From: JAROWMR Date: Mon, 2 Dec 2024 20:34:00 +0100 Subject: merge fix and review fix --- src/example/game.cpp | 13 ++++--------- src/test/CMakeLists.txt | 24 ++++++++++++------------ src/test/PhysicsTest.cpp | 10 ++++------ src/test/Profiling.cpp | 10 +--------- 4 files changed, 21 insertions(+), 36 deletions(-) (limited to 'src/example/game.cpp') diff --git a/src/example/game.cpp b/src/example/game.cpp index e851526..c439f5d 100644 --- a/src/example/game.cpp +++ b/src/example/game.cpp @@ -18,7 +18,7 @@ using namespace std; class MyScript : public Script { bool oncollision(const CollisionEvent& test) { - Log::logf("Box {} script on_collision()", test.info.first.collider.game_object_id); + Log::logf("Box {} script on_collision()", test.info.first_collider.game_object_id); return true; } void init() { @@ -50,8 +50,6 @@ public: .gravity_scale = 0, .body_type = Rigidbody::BodyType::STATIC, .constraints = {0, 0, 0}, - .use_gravity = false, - .bounce = false, .offset = {0,0} }); world.add_component(vec2{0, 0-(screen_size_height/2+world_collider/2)}, world_collider, world_collider);; // Top @@ -67,17 +65,14 @@ public: .body_type = Rigidbody::BodyType::DYNAMIC, .linear_velocity = {1,1}, .constraints = {0, 0, 0}, - .use_gravity = true, - .bounce = true, .elastisity = 1, .offset = {0,0}, }); game_object1.add_component(vec2{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::WHITE); + auto img = Texture("asset/texture/green_square.png"); + game_object1.add_component(img, color, Sprite::FlipSettings{false, false}, 1, 1, 500); + game_object1.add_component(Color::WHITE, ivec2{1080, 720},vec2{2000, 2000}, 1.0f); } string get_name() const { return "scene1"; } diff --git a/src/test/CMakeLists.txt b/src/test/CMakeLists.txt index 4555c0b..cd61fb7 100644 --- a/src/test/CMakeLists.txt +++ b/src/test/CMakeLists.txt @@ -1,17 +1,17 @@ target_sources(test_main PUBLIC 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/PhysicsTest.cpp b/src/test/PhysicsTest.cpp index 33b6020..5dd448f 100644 --- a/src/test/PhysicsTest.cpp +++ b/src/test/PhysicsTest.cpp @@ -28,8 +28,6 @@ public: .max_linear_velocity = vec2{10, 10}, .max_angular_velocity = 10, .constraints = {0, 0}, - .use_gravity = true, - .bounce = false, }); } transforms = mgr.get_components_by_id(0); @@ -105,16 +103,16 @@ TEST_F(PhysicsTest, movement) { EXPECT_EQ(transform.position.y, 1); EXPECT_EQ(transform.rotation, 1); - rigidbody.data.linear_damping.x = 0.5; - rigidbody.data.linear_damping.y = 0.5; - rigidbody.data.angular_damping = 0.5; + rigidbody.data.linear_velocity_factor.x = 0.5; + rigidbody.data.linear_velocity_factor.y = 0.5; + rigidbody.data.angular_velocity_factor = 0.5; system.update(); EXPECT_EQ(rigidbody.data.linear_velocity.x, 0.5); EXPECT_EQ(rigidbody.data.linear_velocity.y, 0.5); EXPECT_EQ(rigidbody.data.angular_velocity, 0.5); rigidbody.data.constraints = {1, 1, 0}; - rigidbody.data.angular_damping = 0; + rigidbody.data.angular_velocity_factor = 0; rigidbody.data.max_angular_velocity = 1000; rigidbody.data.angular_velocity = 360; system.update(); diff --git a/src/test/Profiling.cpp b/src/test/Profiling.cpp index a88bf85..e46d5ff 100644 --- a/src/test/Profiling.cpp +++ b/src/test/Profiling.cpp @@ -26,14 +26,6 @@ using namespace std::chrono_literals; using namespace crepe; using namespace testing; - -/* -List of test cases with component settings/details -1. Minimal test creates gameobject without additonal components -2. Minimal 'Complex' gameobject. Has dynamic body without bounce and no collision handler -3. Minimal 'Complex' gameobject. Same as test 2 but with particle emitter -*/ - class TestScript : public Script { bool oncollision(const CollisionEvent& test) { Log::logf("Box {} script on_collision()", test.info.first_collider.game_object_id); @@ -55,7 +47,7 @@ public: // Minimum amount to let test pass const int min_gameobject_count = 100; // Maximum amount to stop test - const int max_gameobject_count = 200; + const int max_gameobject_count = 150; // Amount of times a test runs to calculate average const int average = 5; // Maximum duration to stop test -- cgit v1.2.3 From ff618da3f97237796042fa3664da59ed147bc1da Mon Sep 17 00:00:00 2001 From: JAROWMR Date: Tue, 3 Dec 2024 19:32:15 +0100 Subject: improved comments --- src/crepe/Collider.h | 18 +++- src/crepe/api/BoxCollider.cpp | 2 +- src/crepe/api/BoxCollider.h | 10 +-- src/crepe/api/Rigidbody.h | 128 +++++++++++++++++++++++---- src/crepe/system/CollisionSystem.cpp | 167 ++++++++++++++++------------------- src/crepe/system/CollisionSystem.h | 32 ++----- src/crepe/system/PhysicsSystem.cpp | 8 +- src/example/game.cpp | 4 +- src/test/CollisionTest.cpp | 56 ++++++------ src/test/PhysicsTest.cpp | 8 +- src/test/Profiling.cpp | 2 +- 11 files changed, 257 insertions(+), 178 deletions(-) (limited to 'src/example/game.cpp') diff --git a/src/crepe/Collider.h b/src/crepe/Collider.h index 15d3a24..f5f53d2 100644 --- a/src/crepe/Collider.h +++ b/src/crepe/Collider.h @@ -10,7 +10,23 @@ public: Collider(game_object_id_t id, const vec2& offset); public: - //! Offset of the collider relative to rigidbody position + /** + * \brief Offset of the collider relative to the rigidbody position. + * + * The `offset` defines the positional shift applied to the collider relative to the position of the rigidbody it is attached to. + * This allows the collider to be placed at a different position than the rigidbody, which can be useful for scenarios + * where the collider's position needs to differ from the rigidbody's center, such as in non-centered colliders. + * + * - The `offset` is typically used when the collider is not meant to be centered exactly on the rigidbody's position. + * - For example, the collider might need to be shifted to account for an object with an asymmetrical shape or for objects + * where the pivot point of the rigidbody is different from the collider's center. + * + * When multiple colliders are added to the same object (e.g., a character with separate body parts or a vehicle with multiple zones), + * the offset is important for properly positioning each collider relative to the rigidbody, allowing accurate collision detection. + * + * - Multiple colliders can be used on the same object, and each can have its own unique offset. + * - Overlap between colliders is allowed and does not impact performance. + */ vec2 offset; }; diff --git a/src/crepe/api/BoxCollider.cpp b/src/crepe/api/BoxCollider.cpp index 1069e90..f94ced7 100644 --- a/src/crepe/api/BoxCollider.cpp +++ b/src/crepe/api/BoxCollider.cpp @@ -4,4 +4,4 @@ using namespace crepe; -BoxCollider::BoxCollider(game_object_id_t game_object_id,const vec2& offset, float width, float height) : Collider(game_object_id,offset), width(width), height(height) {} +BoxCollider::BoxCollider(game_object_id_t game_object_id,const vec2& offset, const vec2& dimensions) : Collider(game_object_id,offset), dimensions(dimensions) {} diff --git a/src/crepe/api/BoxCollider.h b/src/crepe/api/BoxCollider.h index c83d54a..1f5f1c1 100644 --- a/src/crepe/api/BoxCollider.h +++ b/src/crepe/api/BoxCollider.h @@ -2,6 +2,7 @@ #include "Vector2.h" #include "../Collider.h" +#include "types.h" namespace crepe { @@ -12,13 +13,10 @@ namespace crepe { */ class BoxCollider : public Collider { public: - BoxCollider(game_object_id_t game_object_id,const vec2& offset, float width, float height); + BoxCollider(game_object_id_t game_object_id,const vec2& offset, const vec2& dimensions); - //! Width of box collider - float width; - - //! Height of box collider - float height; + //! Width and height of the box collider + vec2 dimensions; }; } // namespace crepe diff --git a/src/crepe/api/Rigidbody.h b/src/crepe/api/Rigidbody.h index 63b1b51..9cdf3f5 100644 --- a/src/crepe/api/Rigidbody.h +++ b/src/crepe/api/Rigidbody.h @@ -36,11 +36,11 @@ public: * the systems will not move the object. */ struct PhysicsConstraints { - //! X constraint + //! Prevent movement along X axis bool x = false; - //! Y constraint + //! Prevent movement along Y axis bool y = false; - //! rotation constraint + //! Prevent rotation bool rotation = false; }; @@ -53,27 +53,112 @@ public: struct Data { //! objects mass float mass = 0.0; - //! gravtiy scale + /** + * \brief Gravity scale factor. + * + * The `gravity_scale` controls how much gravity affects the object. It is a multiplier applied to the default + * gravity force, allowing for fine-grained control over how the object responds to gravity. + * + * - A value of `0.0` means that gravity has **no effect** on the object (i.e., the object is completely immune to gravity). + * - A value of `1.0` means that gravity is applied at its **normal intensity** (the default behavior). + * - A value greater than `1.0` means the object is affected by gravity more strongly than normal. + * - A value less than `1.0` (but greater than `0.0`) reduces the effect of gravity on the object. + * + * This is useful in cases where you need objects to behave differently under gravity, such as lighter objects (like feathers), + * objects that float in water, or heavier objects that fall faster. + */ float gravity_scale = 0; - //! Changes if physics apply + /** + * \brief Defines the type of the physics body, which determines how the physics system interacts with the object. + * + * - **Static**: The object does not move and is not affected by forces. It is used for immovable objects like walls or terrain. Does not have collision detection. + * - **Dynamic**: The object is fully affected by physics forces, including gravity, collisions, and other physical interactions. It can move and be moved by forces. + * - **Kinematic**: The object does not move and is not affected by forces. It is typically controlled by external factors (e.g., animations or user input), and collision detection is handled without affecting its velocity. + * + * The `body_type` defines the behavior of the object in the physics system. + * + * \default BodyType::DYNAMIC + */ BodyType body_type = BodyType::DYNAMIC; - //! linear velocity of object + + /** + * \name Linear (positional) motion + * + * These variables define the linear motion (movement along the position) of an object. + * The linear velocity is applied to the object's position in each update of the PhysicsSystem. + * The motion is affected by the object's linear velocity, its maximum velocity, and a coefficient + * that can scale the velocity over time. + * + * \{ + */ + //! Linear velocity of the object (speed and direction). vec2 linear_velocity; - //! maximum linear velocity of object + //! Maximum linear velocity of the object. This limits the object's speed. vec2 max_linear_velocity = {INFINITY ,INFINITY}; - //! linear damping of object - vec2 linear_velocity_factor; - //! angular velocity of object + //! Linear velocity coefficient. This scales the object's velocity for adjustment or damping. + vec2 linear_velocity_coefficient = {1,1}; + //! \} + + /** + * \name Angular (rotational) motion + * + * These variables define the angular motion (rotation) of an object. + * The angular velocity determines how quickly the object rotates, while the maximum angular velocity + * sets a limit on the rotation speed. The angular velocity coefficient applies damping or scaling + * to the angular velocity, which can be used to simulate friction or other effects that slow down rotation. + * + * \{ + */ + //! Angular velocity of the object, representing the rate of rotation (in radians per second). float angular_velocity = 1; - //! max angular velocity of object + //! Maximum angular velocity of the object. This limits the maximum rate of rotation. float max_angular_velocity = INFINITY; - //! angular damping of object - float angular_velocity_factor = 1; - //! movements constraints of object + //! Angular velocity coefficient. This scales the object's angular velocity, typically used for damping. + float angular_velocity_coefficient = 1; + //! \} + + /** + * \brief Movement constraints for an object. + * + * The `PhysicsConstraints` struct defines the constraints that restrict an object's movement + * in certain directions or prevent rotation. These constraints effect only the physics system + * to prevent the object from moving or rotating in specified ways. + * + * - **X Constraint**: If enabled, the object cannot move along the X-axis. + * - **Y Constraint**: If enabled, the object cannot move along the Y-axis. + * - **Rotation Constraint**: If enabled, the object cannot rotate. + * + * These constraints allow you to restrict movement for specific scenarios (e.g., a platform that shouldn't move + * or a character that should only move horizontally). + */ PhysicsConstraints constraints; - //! bounce factor of material. 0.0 <= means all velocity is lost, 1.0 means it gets the same momentum but the mirrored direction. 0.5 is half of the velocity is saved. - float elastisity = 0.0; - //! offset of all colliders relative to transform position + + /** + * \brief Elasticity factor of the material (bounce factor). + * + * The `elasticity_coefficient` controls how much of the object's velocity is retained after a collision. + * It represents the material's ability to bounce or recover velocity upon impact. The coefficient is a value + * between 0.0 and 1.0, where: + * + * - **0.0** means no velocity is retained after the collision (all velocity is lost, and the object does not bounce). + * - **1.0** means the object retains its full velocity but in the opposite direction (perfect elastic bounce). + * - **0.5** means the object retains half of its velocity, resulting in a bounce with reduced speed. + * + * This factor can be used to simulate different materials, such as rubber (high elasticity) or concrete (low elasticity). + */ + float elastisity_coefficient = 0.0; + + /** + * \brief Offset of all colliders relative to the object's transform position. + * + * The `offset` defines a positional shift applied to all colliders associated with the object, relative to the object's + * transform position. This allows for the colliders to be placed at a different position than the object's actual + * position, without modifying the object's transform itself. + * + * - The `offset` is typically used to adjust the collider's position in cases where all colluders should be moved. + * - For example, if a character has a animation where all colliders should be moved this offset can be used to + * achieve this. + */ vec2 offset; }; @@ -99,6 +184,15 @@ public: * \param force Vector2 that is added to the angular force. */ void add_force_angular(float force); + +protected: + /** + * Ensures there is at most one Rigidbody component per entity. + * \return Always returns 1, indicating this constraint. + */ + virtual int get_instances_max() const { return 1; } + //! ComponentManager instantiates all components + friend class ComponentManager; }; } // namespace crepe diff --git a/src/crepe/system/CollisionSystem.cpp b/src/crepe/system/CollisionSystem.cpp index 380cc3d..2d5ce9d 100644 --- a/src/crepe/system/CollisionSystem.cpp +++ b/src/crepe/system/CollisionSystem.cpp @@ -10,6 +10,7 @@ #include "api/EventManager.h" #include "api/BoxCollider.h" #include "api/CircleCollider.h" +#include "api/Metadata.h" #include "api/Vector2.h" #include "api/Rigidbody.h" #include "api/Transform.h" @@ -23,18 +24,16 @@ using namespace crepe; void CollisionSystem::update() { - std::vector all_colliders; - ComponentManager & mgr = this->component_manager; game_object_id_t id = 0; - RefVector rigidbodies = mgr.get_components_by_type(); + RefVector rigidbodies = this->component_manager.get_components_by_type(); // Collisions can only happen on object with a rigidbody for(Rigidbody& rigidbody : rigidbodies) { if (!rigidbody.active) continue; id = rigidbody.game_object_id; Transform& transform = this->component_manager.get_components_by_id(id).front().get(); // Check if the boxcollider is active and has the same id as the rigidbody. - RefVector boxcolliders = mgr.get_components_by_type(); + RefVector boxcolliders = this->component_manager.get_components_by_type(); for (BoxCollider& boxcollider : boxcolliders) { if(boxcollider.game_object_id != id) continue; if(!boxcollider.active) continue; @@ -48,7 +47,7 @@ void CollisionSystem::update() { ); } // Check if the circlecollider is active and has the same id as the rigidbody. - RefVector circlecolliders = mgr.get_components_by_type(); + RefVector circlecolliders = this->component_manager.get_components_by_type(); for (CircleCollider& circlecollider : circlecolliders) { if(circlecollider.game_object_id != id) continue; if(!circlecollider.active) continue; @@ -64,59 +63,63 @@ void CollisionSystem::update() { } // Check between all colliders if there is a collision - std::vector> collided = gather_collisions(all_colliders); + std::vector> collided = this->gather_collisions(all_colliders); // For both objects call the collision handler for (auto& collision_pair : collided) { - collision_handler_request(collision_pair.first,collision_pair.second); - collision_handler_request(collision_pair.second,collision_pair.first); + this->collision_handler_request(collision_pair.first,collision_pair.second); + this->collision_handler_request(collision_pair.second,collision_pair.first); } } -void CollisionSystem::collision_handler_request(CollisionInternal& data1,CollisionInternal& data2){ +void CollisionSystem::collision_handler_request(CollisionInternal& this_data,CollisionInternal& other_data){ - CollisionInternalType type = get_collider_type(data1.collider,data2.collider); - std::pair resolution_data = collision_handler(data1,data2,type); + CollisionInternalType type = this->get_collider_type(this_data.collider,other_data.collider); + std::pair resolution_data = this->collision_handler(this_data,other_data,type); - OptionalRef collider1; - OptionalRef collider2; + OptionalRef this_metadata = this->component_manager.get_components_by_id(this_data.id).front().get(); + OptionalRef other_metadata = this->component_manager.get_components_by_id(other_data.id).front().get(); + OptionalRef this_collider; + OptionalRef other_collider; switch (type) { case CollisionInternalType::BOX_BOX:{ - collider1 = std::get>(data1.collider); - collider2 = std::get>(data2.collider); + this_collider = std::get>(this_data.collider); + other_collider = std::get>(other_data.collider); break; } case CollisionInternalType::BOX_CIRCLE:{ - collider1 = std::get>(data1.collider); - collider2 = std::get>(data2.collider); + this_collider = std::get>(this_data.collider); + other_collider = std::get>(other_data.collider); break; } case CollisionInternalType::CIRCLE_BOX:{ - collider1 = std::get>(data1.collider); - collider2 = std::get>(data2.collider); + this_collider = std::get>(this_data.collider); + other_collider = std::get>(other_data.collider); break; } case CollisionInternalType::CIRCLE_CIRCLE:{ - collider1 = std::get>(data1.collider); - collider2 = std::get>(data2.collider); + this_collider = std::get>(this_data.collider); + other_collider = std::get>(other_data.collider); break; } } - + // collision info crepe::CollisionSystem::CollisionInfo collision_info{ - .first_collider = collider1, - .first_transform = data1.transform, - .first_rigidbody = data1.rigidbody, - .second_collider = collider2, - .second_transform = data2.transform, - .second_rigidbody = data2.rigidbody, + .this_collider = this_collider, + .this_transform = this_data.transform, + .this_rigidbody = this_data.rigidbody, + .this_metadata = this_metadata, + .other_collider = other_collider, + .other_transform = other_data.transform, + .other_rigidbody = other_data.rigidbody, + .other_metadata = other_metadata, .resolution = resolution_data.first, .resolution_direction = resolution_data.second, }; // Determine if static needs to be called - determine_collision_handler(collision_info); + this->determine_collision_handler(collision_info); } @@ -126,33 +129,33 @@ std::pair CollisionSystem::collision_handler(Co case CollisionInternalType::BOX_BOX: { const BoxCollider & collider1 = std::get>(data1.collider); const BoxCollider & collider2 = std::get>(data2.collider); - vec2 collider_pos1 = get_current_position(collider1.offset, data1.transform, data1.rigidbody); - vec2 collider_pos2 = get_current_position(collider2.offset, data2.transform, data2.rigidbody); - resolution = get_box_box_resolution(collider1,collider2,collider_pos1,collider_pos2); + vec2 collider_pos1 = this->get_current_position(collider1.offset, data1.transform, data1.rigidbody); + vec2 collider_pos2 = this->get_current_position(collider2.offset, data2.transform, data2.rigidbody); + resolution = this->get_box_box_resolution(collider1,collider2,collider_pos1,collider_pos2); break; } case CollisionInternalType::BOX_CIRCLE: { const BoxCollider & collider1 = std::get>(data1.collider); const CircleCollider & collider2 = std::get>(data2.collider); - vec2 collider_pos1 = get_current_position(collider1.offset, data1.transform, data1.rigidbody); - vec2 collider_pos2 = get_current_position(collider2.offset, data2.transform, data2.rigidbody); - resolution = get_circle_box_resolution(collider2,collider1,collider_pos2,collider_pos1); + vec2 collider_pos1 = this->get_current_position(collider1.offset, data1.transform, data1.rigidbody); + vec2 collider_pos2 = this->get_current_position(collider2.offset, data2.transform, data2.rigidbody); + resolution = this->get_circle_box_resolution(collider2,collider1,collider_pos2,collider_pos1); break; } case CollisionInternalType::CIRCLE_CIRCLE: { const CircleCollider & collider1 = std::get>(data1.collider); const CircleCollider & collider2 = std::get>(data2.collider); - vec2 collider_pos1 = get_current_position(collider1.offset, data1.transform, data1.rigidbody); - vec2 collider_pos2 = get_current_position(collider2.offset, data2.transform, data2.rigidbody); - resolution = get_circle_circle_resolution(collider1,collider2,collider_pos1,collider_pos2); + vec2 collider_pos1 = this->get_current_position(collider1.offset, data1.transform, data1.rigidbody); + vec2 collider_pos2 = this->get_current_position(collider2.offset, data2.transform, data2.rigidbody); + resolution = this->get_circle_circle_resolution(collider1,collider2,collider_pos1,collider_pos2); break; } case CollisionInternalType::CIRCLE_BOX: { const CircleCollider & collider1 = std::get>(data1.collider); const BoxCollider & collider2 = std::get>(data2.collider); - vec2 collider_pos1 = get_current_position(collider1.offset, data1.transform, data1.rigidbody); - vec2 collider_pos2 = get_current_position(collider2.offset, data2.transform, data2.rigidbody); - resolution = get_circle_box_resolution(collider1,collider2,collider_pos1,collider_pos2); + vec2 collider_pos1 = this->get_current_position(collider1.offset, data1.transform, data1.rigidbody); + vec2 collider_pos2 = this->get_current_position(collider2.offset, data2.transform, data2.rigidbody); + resolution = this->get_circle_box_resolution(collider1,collider2,collider_pos1,collider_pos2); break; } } @@ -179,10 +182,10 @@ vec2 CollisionSystem::get_box_box_resolution(const BoxCollider& box_collider1,co vec2 delta = final_position2 - final_position1; // Compute half-dimensions of the boxes - float half_width1 = box_collider1.width / 2.0; - float half_height1 = box_collider1.height / 2.0; - float half_width2 = box_collider2.width / 2.0; - float half_height2 = box_collider2.height / 2.0; + float half_width1 = box_collider1.dimensions.x / 2.0; + float half_height1 = box_collider1.dimensions.y / 2.0; + float half_width2 = box_collider2.dimensions.x / 2.0; + float half_height2 = box_collider2.dimensions.y / 2.0; // Calculate overlaps along X and Y axes float overlap_x = (half_width1 + half_width2) - std::abs(delta.x); @@ -234,8 +237,8 @@ vec2 CollisionSystem::get_circle_box_resolution(const CircleCollider& circle_col vec2 delta = circle_position - box_position; // Compute half-dimensions of the box - float half_width = box_collider.width / 2.0f; - float half_height = box_collider.height / 2.0f; + float half_width = box_collider.dimensions.x / 2.0f; + float half_height = box_collider.dimensions.y / 2.0f; // Clamp circle center to the nearest point on the box vec2 closest_point; @@ -261,37 +264,37 @@ vec2 CollisionSystem::get_circle_box_resolution(const CircleCollider& circle_col void CollisionSystem::determine_collision_handler(CollisionInfo& info){ // Check rigidbody type for static - if(info.first_rigidbody.data.body_type == Rigidbody::BodyType::STATIC) return; + if(info.this_rigidbody.data.body_type == Rigidbody::BodyType::STATIC) return; // If second body is static perform the static collision handler in this system - if(info.second_rigidbody.data.body_type == Rigidbody::BodyType::STATIC){ + if(info.other_rigidbody.data.body_type == Rigidbody::BodyType::STATIC){ static_collision_handler(info); }; // Call collision event for user CollisionEvent data(info); - EventManager::get_instance().trigger_event(data, info.first_collider.game_object_id); + EventManager::get_instance().trigger_event(data, info.this_collider.game_object_id); } void CollisionSystem::static_collision_handler(CollisionInfo& info){ // Move object back using calculate move back value - info.first_transform.position += info.resolution; + info.this_transform.position += info.resolution; // If bounce is enabled mirror velocity - if(info.first_rigidbody.data.elastisity > 0) { + if(info.this_rigidbody.data.elastisity_coefficient > 0) { if(info.resolution_direction == Direction::BOTH) { - info.first_rigidbody.data.linear_velocity.y = -info.first_rigidbody.data.linear_velocity.y * info.first_rigidbody.data.elastisity; - info.first_rigidbody.data.linear_velocity.x = -info.first_rigidbody.data.linear_velocity.x * info.first_rigidbody.data.elastisity; + info.this_rigidbody.data.linear_velocity.y = -info.this_rigidbody.data.linear_velocity.y * info.this_rigidbody.data.elastisity_coefficient; + info.this_rigidbody.data.linear_velocity.x = -info.this_rigidbody.data.linear_velocity.x * info.this_rigidbody.data.elastisity_coefficient; } else if(info.resolution_direction == Direction::Y_DIRECTION) { - info.first_rigidbody.data.linear_velocity.y = -info.first_rigidbody.data.linear_velocity.y * info.first_rigidbody.data.elastisity; + info.this_rigidbody.data.linear_velocity.y = -info.this_rigidbody.data.linear_velocity.y * info.this_rigidbody.data.elastisity_coefficient; } else if(info.resolution_direction == Direction::X_DIRECTION){ - info.first_rigidbody.data.linear_velocity.x = -info.first_rigidbody.data.linear_velocity.x * info.first_rigidbody.data.elastisity; + info.this_rigidbody.data.linear_velocity.x = -info.this_rigidbody.data.linear_velocity.x * info.this_rigidbody.data.elastisity_coefficient; } } // Stop movement if bounce is disabled else { - info.first_rigidbody.data.linear_velocity = {0,0}; + info.this_rigidbody.data.linear_velocity = {0,0}; } } @@ -332,24 +335,6 @@ std::vector, std::reference_wrapper>> -CollisionSystem::get_active_transform_and_rigidbody(game_object_id_t game_object_id) const{ - RefVector transforms = this->component_manager.get_components_by_id(game_object_id); - if (transforms.empty()) return std::nullopt; - - Transform& transform = transforms.front().get(); - if (!transform.active) return std::nullopt; - - RefVector rigidbodies = this->component_manager.get_components_by_id(game_object_id); - if (rigidbodies.empty()) return std::nullopt; - - Rigidbody& rigidbody = rigidbodies.front().get(); - if (!rigidbody.active) return std::nullopt; - - // Return the active components - return std::make_pair(std::ref(transform), std::ref(rigidbody)); -} - CollisionSystem::CollisionInternalType CollisionSystem::get_collider_type(const collider_variant& collider1,const collider_variant& collider2) const{ if(std::holds_alternative>(collider1)){ if(std::holds_alternative>(collider2)) @@ -376,22 +361,22 @@ bool CollisionSystem::get_collision(const CollisionInternal& first_info,const Co case CollisionInternalType::BOX_BOX: { const BoxCollider & box_collider1 = std::get>(first_info.collider); const BoxCollider & box_collider2 = std::get>(second_info.collider); - return get_box_box_collision(box_collider1,box_collider2,first_info.transform,second_info.transform,second_info.rigidbody,second_info.rigidbody); + return this->get_box_box_collision(box_collider1,box_collider2,first_info.transform,second_info.transform,second_info.rigidbody,second_info.rigidbody); } case CollisionInternalType::BOX_CIRCLE: { const BoxCollider & box_collider = std::get>(first_info.collider); const CircleCollider & circle_collider = std::get>(second_info.collider); - return get_box_circle_collision(box_collider,circle_collider,first_info.transform,second_info.transform,second_info.rigidbody,second_info.rigidbody); + return this->get_box_circle_collision(box_collider,circle_collider,first_info.transform,second_info.transform,second_info.rigidbody,second_info.rigidbody); } case CollisionInternalType::CIRCLE_CIRCLE: { const CircleCollider & circle_collider1 = std::get>(first_info.collider); const CircleCollider & circle_collider2 = std::get>(second_info.collider); - return get_circle_circle_collision(circle_collider1,circle_collider2,first_info.transform,second_info.transform,second_info.rigidbody,second_info.rigidbody); + return this->get_circle_circle_collision(circle_collider1,circle_collider2,first_info.transform,second_info.transform,second_info.rigidbody,second_info.rigidbody); } case CollisionInternalType::CIRCLE_BOX: { const CircleCollider & circle_collider = std::get>(first_info.collider); const BoxCollider & box_collider = std::get>(second_info.collider); - return get_box_circle_collision(box_collider,circle_collider,first_info.transform,second_info.transform,second_info.rigidbody,second_info.rigidbody); + return this->get_box_circle_collision(box_collider,circle_collider,first_info.transform,second_info.transform,second_info.rigidbody,second_info.rigidbody); } } return false; @@ -401,14 +386,14 @@ bool CollisionSystem::get_collision(const CollisionInternal& first_info,const Co bool CollisionSystem::get_box_box_collision(const BoxCollider& box1, const BoxCollider& box2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2) const { // Get current positions of colliders - vec2 final_position1 = get_current_position(box1.offset,transform1,rigidbody1); - vec2 final_position2 = get_current_position(box2.offset,transform2,rigidbody2); + vec2 final_position1 = this->get_current_position(box1.offset,transform1,rigidbody1); + vec2 final_position2 = this->get_current_position(box2.offset,transform2,rigidbody2); // Calculate half-extents (half width and half height) - float half_width1 = box1.width / 2.0; - float half_height1 = box1.height / 2.0; - float half_width2 = box2.width / 2.0; - float half_height2 = box2.height / 2.0; + float half_width1 = box1.dimensions.x / 2.0; + float half_height1 = box1.dimensions.y / 2.0; + float half_width2 = box2.dimensions.x / 2.0; + float half_height2 = box2.dimensions.y / 2.0; // Check if the boxes overlap along the X and Y axes return (final_position1.x + half_width1 > final_position2.x - half_width2 && @@ -419,12 +404,12 @@ bool CollisionSystem::get_box_box_collision(const BoxCollider& box1, const BoxCo bool CollisionSystem::get_box_circle_collision(const BoxCollider& box1, const CircleCollider& circle2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2) const { // Get current positions of colliders - vec2 final_position1 = get_current_position(box1.offset, transform1, rigidbody1); - vec2 final_position2 = get_current_position(circle2.offset, transform2, rigidbody2); + vec2 final_position1 = this->get_current_position(box1.offset, transform1, rigidbody1); + vec2 final_position2 = this->get_current_position(circle2.offset, transform2, rigidbody2); // Calculate box half-extents - float half_width = box1.width / 2.0; - float half_height = box1.height / 2.0; + float half_width = box1.dimensions.x / 2.0; + float half_height = box1.dimensions.y / 2.0; // Find the closest point on the box to the circle's center float closest_x = std::max(final_position1.x - half_width, std::min(final_position2.x, final_position1.x + half_width)); @@ -441,8 +426,8 @@ bool CollisionSystem::get_box_circle_collision(const BoxCollider& box1, const Ci bool CollisionSystem::get_circle_circle_collision(const CircleCollider& circle1, const CircleCollider& circle2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2) const { // Get current positions of colliders - vec2 final_position1 = get_current_position(circle1.offset,transform1,rigidbody1); - vec2 final_position2 = get_current_position(circle2.offset,transform2,rigidbody2); + vec2 final_position1 = this->get_current_position(circle1.offset,transform1,rigidbody1); + vec2 final_position2 = this->get_current_position(circle2.offset,transform2,rigidbody2); float distance_x = final_position1.x - final_position2.x; float distance_y = final_position1.y - final_position2.y; diff --git a/src/crepe/system/CollisionSystem.h b/src/crepe/system/CollisionSystem.h index 7fb8b45..85ae5ad 100644 --- a/src/crepe/system/CollisionSystem.h +++ b/src/crepe/system/CollisionSystem.h @@ -8,6 +8,7 @@ #include "api/Transform.h" #include "api/BoxCollider.h" #include "api/CircleCollider.h" +#include "api/Metadata.h" #include "api/Vector2.h" #include "Collider.h" @@ -68,12 +69,14 @@ public: * Includes information about the colliding objects and the resolution data for handling the collision. */ struct CollisionInfo{ - Collider& first_collider; - Transform& first_transform; - Rigidbody& first_rigidbody; - Collider& second_collider; - Transform& second_transform; - Rigidbody& second_rigidbody; + Collider& this_collider; + Transform& this_transform; + Rigidbody& this_rigidbody; + Metadata& this_metadata; + Collider& other_collider; + Transform& other_transform; + Rigidbody& other_rigidbody; + Metadata& other_metadata; //! The resolution vector for the collision. vec2 resolution; //! The direction of movement for resolving the collision. @@ -213,23 +216,6 @@ private: */ bool get_collision(const CollisionInternal& first_info,const CollisionInternal& second_info, CollisionInternalType type) const; - /** - * \brief Retrieves the active Transform and Rigidbody components for a given game object. - * - * This function looks up the Transform and Rigidbody components associated with the specified - * game object ID. It checks if both components are present and active. If both are found - * to be active, they are returned wrapped in reference wrappers; otherwise, an empty - * optional is returned. - * - * \param game_object_id The ID of the game object for which to retrieve the components. - * - * \return A std::optional containing a pair of reference wrappers to the active Transform - * and Rigidbody components, or std::nullopt if either component is not found - * or not active. - */ - std::optional, std::reference_wrapper>> get_active_transform_and_rigidbody(game_object_id_t game_object_id) const; - - /** * \brief Detects collisions between two BoxColliders. * diff --git a/src/crepe/system/PhysicsSystem.cpp b/src/crepe/system/PhysicsSystem.cpp index 8f21727..f3833cb 100644 --- a/src/crepe/system/PhysicsSystem.cpp +++ b/src/crepe/system/PhysicsSystem.cpp @@ -31,11 +31,11 @@ void PhysicsSystem::update() { * gravity); } // Add damping - if (rigidbody.data.angular_velocity_factor != 1 && rigidbody.data.angular_velocity_factor > 0) { - rigidbody.data.angular_velocity *= rigidbody.data.angular_velocity_factor; + if (rigidbody.data.angular_velocity_coefficient != 1 && rigidbody.data.angular_velocity_coefficient > 0) { + rigidbody.data.angular_velocity *= rigidbody.data.angular_velocity_coefficient; } - if (rigidbody.data.linear_velocity_factor != vec2{1, 1} && rigidbody.data.linear_velocity_factor.x > 0 && rigidbody.data.linear_velocity_factor.y > 0) { - rigidbody.data.linear_velocity *= rigidbody.data.linear_velocity_factor; + if (rigidbody.data.linear_velocity_coefficient != vec2{1, 1} && rigidbody.data.linear_velocity_coefficient.x > 0 && rigidbody.data.linear_velocity_coefficient.y > 0) { + rigidbody.data.linear_velocity *= rigidbody.data.linear_velocity_coefficient; } // Max velocity check diff --git a/src/example/game.cpp b/src/example/game.cpp index c439f5d..4e16d4a 100644 --- a/src/example/game.cpp +++ b/src/example/game.cpp @@ -18,7 +18,7 @@ using namespace std; class MyScript : public Script { bool oncollision(const CollisionEvent& test) { - Log::logf("Box {} script on_collision()", test.info.first_collider.game_object_id); + Log::logf("Box {} script on_collision()", test.info.this_collider.game_object_id); return true; } void init() { @@ -65,7 +65,7 @@ public: .body_type = Rigidbody::BodyType::DYNAMIC, .linear_velocity = {1,1}, .constraints = {0, 0, 0}, - .elastisity = 1, + .elastisity_coefficient = 1, .offset = {0,0}, }); game_object1.add_component(vec2{0, 0}, 20, 20); diff --git a/src/test/CollisionTest.cpp b/src/test/CollisionTest.cpp index 92ff7ba..fec42f3 100644 --- a/src/test/CollisionTest.cpp +++ b/src/test/CollisionTest.cpp @@ -68,10 +68,10 @@ public: .offset = {0,0}, }); // Create a box with an inner size of 10x10 units - world.add_component(vec2{0, -100}, 100, 100); // Top - world.add_component(vec2{0, 100}, 100, 100); // Bottom - world.add_component(vec2{-100, 0}, 100, 100); // Left - world.add_component(vec2{100, 0}, 100, 100); // right + world.add_component(vec2{0, -100}, vec2{100, 100}); // Top + world.add_component(vec2{0, 100}, vec2{100, 100}); // Bottom + world.add_component(vec2{-100, 0}, vec2{100, 100}); // Left + world.add_component(vec2{100, 0}, vec2{100, 100}); // right game_object1.add_component(Rigidbody::Data{ .mass = 1, @@ -79,10 +79,10 @@ public: .body_type = Rigidbody::BodyType::DYNAMIC, .linear_velocity = {0,0}, .constraints = {0, 0, 0}, - .elastisity = 1, + .elastisity_coefficient = 1, .offset = {0,0}, }); - game_object1.add_component(vec2{0, 0}, 10, 10); + game_object1.add_component(vec2{0, 0}, vec2{10, 10}); BehaviorScript & script_object1 = game_object1.add_component().set_script(1); script_object1_ref = static_cast(script_object1.script.get()); ASSERT_NE(script_object1_ref, nullptr); @@ -93,10 +93,10 @@ public: .body_type = Rigidbody::BodyType::DYNAMIC, .linear_velocity = {0,0}, .constraints = {0, 0, 0}, - .elastisity = 1, + .elastisity_coefficient = 1, .offset = {0,0}, }); - game_object2.add_component(vec2{0, 0}, 10, 10); + game_object2.add_component(vec2{0, 0}, vec2{10, 10}); BehaviorScript & script_object2 = game_object2.add_component().set_script(2); script_object2_ref = static_cast(script_object2.script.get()); ASSERT_NE(script_object2_ref, nullptr); @@ -110,11 +110,11 @@ TEST_F(CollisionTest, collision_example) { bool collision_happend = false; script_object1_ref->test_fn = [&collision_happend](const CollisionEvent & ev) { collision_happend = true; - EXPECT_EQ(ev.info.first_collider.game_object_id, 1); + EXPECT_EQ(ev.info.this_collider.game_object_id, 1); }; script_object2_ref->test_fn = [&collision_happend](const CollisionEvent & ev) { collision_happend = true; - EXPECT_EQ(ev.info.first_collider.game_object_id, 2); + EXPECT_EQ(ev.info.this_collider.game_object_id, 2); }; EXPECT_FALSE(collision_happend); collision_sys.update(); @@ -125,14 +125,14 @@ TEST_F(CollisionTest, collision_box_box_dynamic_both_no_velocity) { bool collision_happend = false; script_object1_ref->test_fn = [&collision_happend](const CollisionEvent & ev) { collision_happend = true; - EXPECT_EQ(ev.info.first_collider.game_object_id, 1); + EXPECT_EQ(ev.info.this_collider.game_object_id, 1); EXPECT_EQ(ev.info.resolution.x, 10); EXPECT_EQ(ev.info.resolution.y, 10); EXPECT_EQ(ev.info.resolution_direction, crepe::CollisionSystem::Direction::BOTH); }; script_object2_ref->test_fn = [&collision_happend](const CollisionEvent & ev) { collision_happend = true; - EXPECT_EQ(ev.info.first_collider.game_object_id, 2); + EXPECT_EQ(ev.info.this_collider.game_object_id, 2); EXPECT_EQ(ev.info.resolution.x, 10); EXPECT_EQ(ev.info.resolution.y, 10); EXPECT_EQ(ev.info.resolution_direction, crepe::CollisionSystem::Direction::BOTH); @@ -148,14 +148,14 @@ TEST_F(CollisionTest, collision_box_box_dynamic_x_direction_no_velocity) { bool collision_happend = false; script_object1_ref->test_fn = [&collision_happend](const CollisionEvent & ev) { collision_happend = true; - EXPECT_EQ(ev.info.first_collider.game_object_id, 1); + EXPECT_EQ(ev.info.this_collider.game_object_id, 1); EXPECT_EQ(ev.info.resolution.x, -5); EXPECT_EQ(ev.info.resolution.y, 0); EXPECT_EQ(ev.info.resolution_direction, crepe::CollisionSystem::Direction::X_DIRECTION); }; script_object2_ref->test_fn = [&collision_happend](const CollisionEvent & ev) { collision_happend = true; - EXPECT_EQ(ev.info.first_collider.game_object_id, 2); + EXPECT_EQ(ev.info.this_collider.game_object_id, 2); EXPECT_EQ(ev.info.resolution.x, 5); EXPECT_EQ(ev.info.resolution.y, 0); EXPECT_EQ(ev.info.resolution_direction, crepe::CollisionSystem::Direction::X_DIRECTION); @@ -171,14 +171,14 @@ TEST_F(CollisionTest, collision_box_box_dynamic_y_direction_no_velocity) { bool collision_happend = false; script_object1_ref->test_fn = [&collision_happend](const CollisionEvent & ev) { collision_happend = true; - EXPECT_EQ(ev.info.first_collider.game_object_id, 1); + EXPECT_EQ(ev.info.this_collider.game_object_id, 1); EXPECT_EQ(ev.info.resolution.x, 0); EXPECT_EQ(ev.info.resolution.y, -5); EXPECT_EQ(ev.info.resolution_direction, crepe::CollisionSystem::Direction::Y_DIRECTION); }; script_object2_ref->test_fn = [&collision_happend](const CollisionEvent & ev) { collision_happend = true; - EXPECT_EQ(ev.info.first_collider.game_object_id, 2); + EXPECT_EQ(ev.info.this_collider.game_object_id, 2); EXPECT_EQ(ev.info.resolution.x, 0); EXPECT_EQ(ev.info.resolution.y, 5); EXPECT_EQ(ev.info.resolution_direction, crepe::CollisionSystem::Direction::Y_DIRECTION); @@ -194,14 +194,14 @@ TEST_F(CollisionTest, collision_box_box_dynamic_both) { bool collision_happend = false; script_object1_ref->test_fn = [&collision_happend](const CollisionEvent & ev) { collision_happend = true; - EXPECT_EQ(ev.info.first_collider.game_object_id, 1); + EXPECT_EQ(ev.info.this_collider.game_object_id, 1); EXPECT_EQ(ev.info.resolution.x, 10); EXPECT_EQ(ev.info.resolution.y, 10); EXPECT_EQ(ev.info.resolution_direction, crepe::CollisionSystem::Direction::BOTH); }; script_object2_ref->test_fn = [&collision_happend](const CollisionEvent & ev) { collision_happend = true; - EXPECT_EQ(ev.info.first_collider.game_object_id, 2); + EXPECT_EQ(ev.info.this_collider.game_object_id, 2); EXPECT_EQ(ev.info.resolution.x, 10); EXPECT_EQ(ev.info.resolution.y, 10); EXPECT_EQ(ev.info.resolution_direction, crepe::CollisionSystem::Direction::BOTH); @@ -221,14 +221,14 @@ TEST_F(CollisionTest, collision_box_box_dynamic_x_direction) { bool collision_happend = false; script_object1_ref->test_fn = [&collision_happend](const CollisionEvent & ev) { collision_happend = true; - EXPECT_EQ(ev.info.first_collider.game_object_id, 1); + EXPECT_EQ(ev.info.this_collider.game_object_id, 1); EXPECT_EQ(ev.info.resolution.x, -5); EXPECT_EQ(ev.info.resolution.y, -5); EXPECT_EQ(ev.info.resolution_direction, crepe::CollisionSystem::Direction::X_DIRECTION); }; script_object2_ref->test_fn = [&collision_happend](const CollisionEvent & ev) { collision_happend = true; - EXPECT_EQ(ev.info.first_collider.game_object_id, 2); + EXPECT_EQ(ev.info.this_collider.game_object_id, 2); EXPECT_EQ(ev.info.resolution.x, 5); EXPECT_EQ(ev.info.resolution.y, 5); EXPECT_EQ(ev.info.resolution_direction, crepe::CollisionSystem::Direction::X_DIRECTION); @@ -248,14 +248,14 @@ TEST_F(CollisionTest, collision_box_box_dynamic_y_direction) { bool collision_happend = false; script_object1_ref->test_fn = [&collision_happend](const CollisionEvent & ev) { collision_happend = true; - EXPECT_EQ(ev.info.first_collider.game_object_id, 1); + EXPECT_EQ(ev.info.this_collider.game_object_id, 1); EXPECT_EQ(ev.info.resolution.x, -5); EXPECT_EQ(ev.info.resolution.y, -5); EXPECT_EQ(ev.info.resolution_direction, crepe::CollisionSystem::Direction::Y_DIRECTION); }; script_object2_ref->test_fn = [&collision_happend](const CollisionEvent & ev) { collision_happend = true; - EXPECT_EQ(ev.info.first_collider.game_object_id, 2); + EXPECT_EQ(ev.info.this_collider.game_object_id, 2); EXPECT_EQ(ev.info.resolution.x, 5); EXPECT_EQ(ev.info.resolution.y, 5); EXPECT_EQ(ev.info.resolution_direction, crepe::CollisionSystem::Direction::Y_DIRECTION); @@ -276,7 +276,7 @@ TEST_F(CollisionTest, collision_box_box_static_both) { bool collision_happend = false; script_object1_ref->test_fn = [&collision_happend](const CollisionEvent & ev) { collision_happend = true; - EXPECT_EQ(ev.info.first_collider.game_object_id, 1); + EXPECT_EQ(ev.info.this_collider.game_object_id, 1); EXPECT_EQ(ev.info.resolution.x, 10); EXPECT_EQ(ev.info.resolution.y, 10); EXPECT_EQ(ev.info.resolution_direction, crepe::CollisionSystem::Direction::BOTH); @@ -298,7 +298,7 @@ TEST_F(CollisionTest, collision_box_box_static_x_direction) { bool collision_happend = false; script_object1_ref->test_fn = [&collision_happend](const CollisionEvent & ev) { collision_happend = true; - EXPECT_EQ(ev.info.first_collider.game_object_id, 1); + EXPECT_EQ(ev.info.this_collider.game_object_id, 1); EXPECT_EQ(ev.info.resolution.x, -5); EXPECT_EQ(ev.info.resolution.y, -5); EXPECT_EQ(ev.info.resolution_direction, crepe::CollisionSystem::Direction::X_DIRECTION); @@ -322,7 +322,7 @@ TEST_F(CollisionTest, collision_box_box_static_y_direction) { bool collision_happend = false; script_object1_ref->test_fn = [&collision_happend](const CollisionEvent & ev) { collision_happend = true; - EXPECT_EQ(ev.info.first_collider.game_object_id, 1); + EXPECT_EQ(ev.info.this_collider.game_object_id, 1); EXPECT_EQ(ev.info.resolution.x, -5); EXPECT_EQ(ev.info.resolution.y, -5); EXPECT_EQ(ev.info.resolution_direction, crepe::CollisionSystem::Direction::Y_DIRECTION); @@ -348,8 +348,8 @@ TEST_F(CollisionTest, collision_box_box_static_multiple) {//todo check visually float resolution = 0; script_object1_ref->test_fn = [&](const CollisionEvent & ev) { collision_happend = true; - EXPECT_EQ(ev.info.first_collider.game_object_id, 1); - EXPECT_EQ(ev.info.first_collider.offset.x , offset_value); + EXPECT_EQ(ev.info.this_collider.game_object_id, 1); + EXPECT_EQ(ev.info.this_collider.offset.x , offset_value); EXPECT_EQ(ev.info.resolution.x , resolution); }; script_object2_ref->test_fn = [&](const CollisionEvent & ev) { @@ -365,7 +365,7 @@ TEST_F(CollisionTest, collision_box_box_static_multiple) {//todo check visually rg2.data.body_type = crepe::Rigidbody::BodyType::STATIC; BoxCollider & bxc = this->mgr.get_components_by_id(1).front().get(); bxc.offset = {5,0}; - this->game_object1.add_component(vec2{-5, 0}, 10, 10); + this->game_object1.add_component(vec2{-5, 0}, vec2{10, 10}); offset_value = 5; resolution = 10; collision_sys.update(); diff --git a/src/test/PhysicsTest.cpp b/src/test/PhysicsTest.cpp index 5dd448f..ad7cb03 100644 --- a/src/test/PhysicsTest.cpp +++ b/src/test/PhysicsTest.cpp @@ -103,16 +103,16 @@ TEST_F(PhysicsTest, movement) { EXPECT_EQ(transform.position.y, 1); EXPECT_EQ(transform.rotation, 1); - rigidbody.data.linear_velocity_factor.x = 0.5; - rigidbody.data.linear_velocity_factor.y = 0.5; - rigidbody.data.angular_velocity_factor = 0.5; + rigidbody.data.linear_velocity_coefficient.x = 0.5; + rigidbody.data.linear_velocity_coefficient.y = 0.5; + rigidbody.data.angular_velocity_coefficient = 0.5; system.update(); EXPECT_EQ(rigidbody.data.linear_velocity.x, 0.5); EXPECT_EQ(rigidbody.data.linear_velocity.y, 0.5); EXPECT_EQ(rigidbody.data.angular_velocity, 0.5); rigidbody.data.constraints = {1, 1, 0}; - rigidbody.data.angular_velocity_factor = 0; + rigidbody.data.angular_velocity_coefficient = 0; rigidbody.data.max_angular_velocity = 1000; rigidbody.data.angular_velocity = 360; system.update(); diff --git a/src/test/Profiling.cpp b/src/test/Profiling.cpp index e46d5ff..fa0f5f3 100644 --- a/src/test/Profiling.cpp +++ b/src/test/Profiling.cpp @@ -28,7 +28,7 @@ using namespace testing; class TestScript : public Script { bool oncollision(const CollisionEvent& test) { - Log::logf("Box {} script on_collision()", test.info.first_collider.game_object_id); + Log::logf("Box {} script on_collision()", test.info.this_collider.game_object_id); return true; } void init() { -- cgit v1.2.3 From 9416841ad776d9117bc3b12ee3ceb9a8c7af4c73 Mon Sep 17 00:00:00 2001 From: JAROWMR Date: Tue, 3 Dec 2024 19:44:01 +0100 Subject: removed part of if --- src/crepe/api/Rigidbody.h | 4 ++-- src/crepe/system/PhysicsSystem.cpp | 4 ++-- src/example/game.cpp | 13 ++++++------- 3 files changed, 10 insertions(+), 11 deletions(-) (limited to 'src/example/game.cpp') diff --git a/src/crepe/api/Rigidbody.h b/src/crepe/api/Rigidbody.h index 9cdf3f5..14b183b 100644 --- a/src/crepe/api/Rigidbody.h +++ b/src/crepe/api/Rigidbody.h @@ -109,8 +109,8 @@ public: * * \{ */ - //! Angular velocity of the object, representing the rate of rotation (in radians per second). - float angular_velocity = 1; + //! Angular velocity of the object, representing the rate of rotation (in degrees). + float angular_velocity = 0; //! Maximum angular velocity of the object. This limits the maximum rate of rotation. float max_angular_velocity = INFINITY; //! Angular velocity coefficient. This scales the object's angular velocity, typically used for damping. diff --git a/src/crepe/system/PhysicsSystem.cpp b/src/crepe/system/PhysicsSystem.cpp index f3833cb..b5da042 100644 --- a/src/crepe/system/PhysicsSystem.cpp +++ b/src/crepe/system/PhysicsSystem.cpp @@ -31,10 +31,10 @@ void PhysicsSystem::update() { * gravity); } // Add damping - if (rigidbody.data.angular_velocity_coefficient != 1 && rigidbody.data.angular_velocity_coefficient > 0) { + if (rigidbody.data.angular_velocity_coefficient > 0) { rigidbody.data.angular_velocity *= rigidbody.data.angular_velocity_coefficient; } - if (rigidbody.data.linear_velocity_coefficient != vec2{1, 1} && rigidbody.data.linear_velocity_coefficient.x > 0 && rigidbody.data.linear_velocity_coefficient.y > 0) { + if (rigidbody.data.linear_velocity_coefficient.x > 0 && rigidbody.data.linear_velocity_coefficient.y > 0) { rigidbody.data.linear_velocity *= rigidbody.data.linear_velocity_coefficient; } diff --git a/src/example/game.cpp b/src/example/game.cpp index 4e16d4a..5e3fab7 100644 --- a/src/example/game.cpp +++ b/src/example/game.cpp @@ -52,11 +52,11 @@ public: .constraints = {0, 0, 0}, .offset = {0,0} }); - world.add_component(vec2{0, 0-(screen_size_height/2+world_collider/2)}, world_collider, world_collider);; // Top - world.add_component(vec2{0, screen_size_height/2+world_collider/2}, world_collider, world_collider); // Bottom - world.add_component(vec2{0-(screen_size_width/2+world_collider/2), 0}, world_collider, world_collider); // Left - world.add_component(vec2{screen_size_width/2+world_collider/2, 0}, world_collider, world_collider); // right - + world.add_component(vec2{0, 0-(screen_size_height/2+world_collider/2)}, vec2{world_collider, world_collider});; // Top + world.add_component(vec2{0, screen_size_height/2+world_collider/2}, vec2{world_collider, world_collider}); // Bottom + world.add_component(vec2{0-(screen_size_width/2+world_collider/2), 0}, vec2{world_collider, world_collider}); // Left + world.add_component(vec2{screen_size_width/2+world_collider/2, 0}, vec2{world_collider, world_collider}); // right + world.add_component(Color::WHITE, ivec2{640, 480},vec2{640, 480}, 1.0f); GameObject game_object1 = mgr.new_object("Name", "Tag", vec2{screen_size_width/2, screen_size_height/2}, 0, 1); game_object1.add_component(Rigidbody::Data{ @@ -68,11 +68,10 @@ public: .elastisity_coefficient = 1, .offset = {0,0}, }); - game_object1.add_component(vec2{0, 0}, 20, 20); + game_object1.add_component(vec2{0, 0}, vec2{20, 20}); game_object1.add_component().set_script(); auto img = Texture("asset/texture/green_square.png"); game_object1.add_component(img, color, Sprite::FlipSettings{false, false}, 1, 1, 500); - game_object1.add_component(Color::WHITE, ivec2{1080, 720},vec2{2000, 2000}, 1.0f); } string get_name() const { return "scene1"; } -- cgit v1.2.3 From 322e9a8ceaa8b2ce5d3e6056be4a9739817d47cf Mon Sep 17 00:00:00 2001 From: JAROWMR Date: Tue, 3 Dec 2024 20:43:57 +0100 Subject: improved comments --- src/crepe/Collider.h | 12 +----------- src/crepe/api/Rigidbody.h | 36 +++--------------------------------- src/example/game.cpp | 4 ++-- 3 files changed, 6 insertions(+), 46 deletions(-) (limited to 'src/example/game.cpp') diff --git a/src/crepe/Collider.h b/src/crepe/Collider.h index f5f53d2..b3a09fb 100644 --- a/src/crepe/Collider.h +++ b/src/crepe/Collider.h @@ -14,18 +14,8 @@ public: * \brief Offset of the collider relative to the rigidbody position. * * The `offset` defines the positional shift applied to the collider relative to the position of the rigidbody it is attached to. - * This allows the collider to be placed at a different position than the rigidbody, which can be useful for scenarios - * where the collider's position needs to differ from the rigidbody's center, such as in non-centered colliders. + * This allows the collider to be placed at a different position than the rigidbody. * - * - The `offset` is typically used when the collider is not meant to be centered exactly on the rigidbody's position. - * - For example, the collider might need to be shifted to account for an object with an asymmetrical shape or for objects - * where the pivot point of the rigidbody is different from the collider's center. - * - * When multiple colliders are added to the same object (e.g., a character with separate body parts or a vehicle with multiple zones), - * the offset is important for properly positioning each collider relative to the rigidbody, allowing accurate collision detection. - * - * - Multiple colliders can be used on the same object, and each can have its own unique offset. - * - Overlap between colliders is allowed and does not impact performance. */ vec2 offset; }; diff --git a/src/crepe/api/Rigidbody.h b/src/crepe/api/Rigidbody.h index 14b183b..431e000 100644 --- a/src/crepe/api/Rigidbody.h +++ b/src/crepe/api/Rigidbody.h @@ -59,26 +59,10 @@ public: * The `gravity_scale` controls how much gravity affects the object. It is a multiplier applied to the default * gravity force, allowing for fine-grained control over how the object responds to gravity. * - * - A value of `0.0` means that gravity has **no effect** on the object (i.e., the object is completely immune to gravity). - * - A value of `1.0` means that gravity is applied at its **normal intensity** (the default behavior). - * - A value greater than `1.0` means the object is affected by gravity more strongly than normal. - * - A value less than `1.0` (but greater than `0.0`) reduces the effect of gravity on the object. - * - * This is useful in cases where you need objects to behave differently under gravity, such as lighter objects (like feathers), - * objects that float in water, or heavier objects that fall faster. */ float gravity_scale = 0; - /** - * \brief Defines the type of the physics body, which determines how the physics system interacts with the object. - * - * - **Static**: The object does not move and is not affected by forces. It is used for immovable objects like walls or terrain. Does not have collision detection. - * - **Dynamic**: The object is fully affected by physics forces, including gravity, collisions, and other physical interactions. It can move and be moved by forces. - * - **Kinematic**: The object does not move and is not affected by forces. It is typically controlled by external factors (e.g., animations or user input), and collision detection is handled without affecting its velocity. - * - * The `body_type` defines the behavior of the object in the physics system. - * - * \default BodyType::DYNAMIC - */ + + //! Defines the type of the physics body, which determines how the physics system interacts with the object. BodyType body_type = BodyType::DYNAMIC; /** @@ -124,12 +108,6 @@ public: * in certain directions or prevent rotation. These constraints effect only the physics system * to prevent the object from moving or rotating in specified ways. * - * - **X Constraint**: If enabled, the object cannot move along the X-axis. - * - **Y Constraint**: If enabled, the object cannot move along the Y-axis. - * - **Rotation Constraint**: If enabled, the object cannot rotate. - * - * These constraints allow you to restrict movement for specific scenarios (e.g., a platform that shouldn't move - * or a character that should only move horizontally). */ PhysicsConstraints constraints; @@ -138,13 +116,8 @@ public: * * The `elasticity_coefficient` controls how much of the object's velocity is retained after a collision. * It represents the material's ability to bounce or recover velocity upon impact. The coefficient is a value - * between 0.0 and 1.0, where: - * - * - **0.0** means no velocity is retained after the collision (all velocity is lost, and the object does not bounce). - * - **1.0** means the object retains its full velocity but in the opposite direction (perfect elastic bounce). - * - **0.5** means the object retains half of its velocity, resulting in a bounce with reduced speed. + * above 0.0. * - * This factor can be used to simulate different materials, such as rubber (high elasticity) or concrete (low elasticity). */ float elastisity_coefficient = 0.0; @@ -155,9 +128,6 @@ public: * transform position. This allows for the colliders to be placed at a different position than the object's actual * position, without modifying the object's transform itself. * - * - The `offset` is typically used to adjust the collider's position in cases where all colluders should be moved. - * - For example, if a character has a animation where all colliders should be moved this offset can be used to - * achieve this. */ vec2 offset; }; diff --git a/src/example/game.cpp b/src/example/game.cpp index 5e3fab7..de08a22 100644 --- a/src/example/game.cpp +++ b/src/example/game.cpp @@ -38,7 +38,7 @@ public: void load_scene() { ComponentManager & mgr = this->component_manager; - Color color(0, 0, 0, 0); + Color color(0, 0, 0, 255); float screen_size_width = 640; float screen_size_height = 480; @@ -71,7 +71,7 @@ public: game_object1.add_component(vec2{0, 0}, vec2{20, 20}); game_object1.add_component().set_script(); auto img = Texture("asset/texture/green_square.png"); - game_object1.add_component(img, color, Sprite::FlipSettings{false, false}, 1, 1, 500); + game_object1.add_component(img, color, Sprite::FlipSettings{false, false}, 1, 1, 20); } string get_name() const { return "scene1"; } -- cgit v1.2.3 From d76ab0bf77d0a61712dc25bbe1760995be4c4782 Mon Sep 17 00:00:00 2001 From: JAROWMR Date: Wed, 4 Dec 2024 20:11:02 +0100 Subject: make format --- src/crepe/Collider.cpp | 2 +- src/crepe/Collider.h | 2 +- src/crepe/api/BoxCollider.cpp | 7 +- src/crepe/api/BoxCollider.h | 6 +- src/crepe/api/CircleCollider.cpp | 6 +- src/crepe/api/CircleCollider.h | 3 +- src/crepe/api/Event.h | 4 +- src/crepe/api/LoopManager.cpp | 3 +- src/crepe/api/Rigidbody.cpp | 4 +- src/crepe/api/Rigidbody.h | 4 +- src/crepe/system/CollisionSystem.cpp | 514 ++++++++++++++++++++--------------- src/crepe/system/CollisionSystem.h | 121 +++++---- src/crepe/system/PhysicsSystem.cpp | 9 +- src/example/game.cpp | 97 ++++--- src/test/CollisionTest.cpp | 122 +++++---- src/test/Profiling.cpp | 121 +++++---- 16 files changed, 574 insertions(+), 451 deletions(-) (limited to 'src/example/game.cpp') diff --git a/src/crepe/Collider.cpp b/src/crepe/Collider.cpp index 9d94152..77e11c8 100644 --- a/src/crepe/Collider.cpp +++ b/src/crepe/Collider.cpp @@ -2,4 +2,4 @@ using namespace crepe; -Collider::Collider(game_object_id_t id, const vec2& offset) : Component(id), offset(offset) {} +Collider::Collider(game_object_id_t id, const vec2 & offset) : Component(id), offset(offset) {} diff --git a/src/crepe/Collider.h b/src/crepe/Collider.h index b3a09fb..a08a68e 100644 --- a/src/crepe/Collider.h +++ b/src/crepe/Collider.h @@ -7,7 +7,7 @@ namespace crepe { class Collider : public Component { public: - Collider(game_object_id_t id, const vec2& offset); + Collider(game_object_id_t id, const vec2 & offset); public: /** diff --git a/src/crepe/api/BoxCollider.cpp b/src/crepe/api/BoxCollider.cpp index f94ced7..c097a24 100644 --- a/src/crepe/api/BoxCollider.cpp +++ b/src/crepe/api/BoxCollider.cpp @@ -1,7 +1,10 @@ #include "BoxCollider.h" -#include "../Collider.h" +#include "../Collider.h" using namespace crepe; -BoxCollider::BoxCollider(game_object_id_t game_object_id,const vec2& offset, const vec2& dimensions) : Collider(game_object_id,offset), dimensions(dimensions) {} +BoxCollider::BoxCollider(game_object_id_t game_object_id, const vec2 & offset, + const vec2 & dimensions) + : Collider(game_object_id, offset), + dimensions(dimensions) {} diff --git a/src/crepe/api/BoxCollider.h b/src/crepe/api/BoxCollider.h index 1f5f1c1..89e43d8 100644 --- a/src/crepe/api/BoxCollider.h +++ b/src/crepe/api/BoxCollider.h @@ -1,7 +1,7 @@ #pragma once -#include "Vector2.h" #include "../Collider.h" +#include "Vector2.h" #include "types.h" namespace crepe { @@ -13,9 +13,9 @@ namespace crepe { */ class BoxCollider : public Collider { public: - BoxCollider(game_object_id_t game_object_id,const vec2& offset, const vec2& dimensions); + BoxCollider(game_object_id_t game_object_id, const vec2 & offset, const vec2 & dimensions); - //! Width and height of the box collider + //! Width and height of the box collider vec2 dimensions; }; diff --git a/src/crepe/api/CircleCollider.cpp b/src/crepe/api/CircleCollider.cpp index 473734e..a4271e9 100644 --- a/src/crepe/api/CircleCollider.cpp +++ b/src/crepe/api/CircleCollider.cpp @@ -2,5 +2,7 @@ using namespace crepe; - -CircleCollider::CircleCollider(game_object_id_t game_object_id,const vec2& offset, float radius) : Collider(game_object_id,offset), radius(radius) {} +CircleCollider::CircleCollider(game_object_id_t game_object_id, const vec2 & offset, + float radius) + : Collider(game_object_id, offset), + radius(radius) {} diff --git a/src/crepe/api/CircleCollider.h b/src/crepe/api/CircleCollider.h index bbcc330..ebd1cb2 100644 --- a/src/crepe/api/CircleCollider.h +++ b/src/crepe/api/CircleCollider.h @@ -13,8 +13,7 @@ namespace crepe { */ class CircleCollider : public Collider { public: - - CircleCollider(game_object_id_t game_object_id,const vec2& offset, float radius); + CircleCollider(game_object_id_t game_object_id, const vec2 & offset, float radius); //! Radius of the circle collider. float radius; diff --git a/src/crepe/api/Event.h b/src/crepe/api/Event.h index 259acba..152bc2c 100644 --- a/src/crepe/api/Event.h +++ b/src/crepe/api/Event.h @@ -98,8 +98,8 @@ public: class CollisionEvent : public Event { public: crepe::CollisionSystem::CollisionInfo info; - CollisionEvent(const crepe::CollisionSystem::CollisionInfo& collisionInfo) - : info(collisionInfo) {} + CollisionEvent(const crepe::CollisionSystem::CollisionInfo & collisionInfo) + : info(collisionInfo) {} }; /** diff --git a/src/crepe/api/LoopManager.cpp b/src/crepe/api/LoopManager.cpp index feb1338..d4819ea 100644 --- a/src/crepe/api/LoopManager.cpp +++ b/src/crepe/api/LoopManager.cpp @@ -1,13 +1,12 @@ #include "../facade/SDLContext.h" +#include "../system/PhysicsSystem.h" #include "../system/AnimatorSystem.h" #include "../system/CollisionSystem.h" #include "../system/ParticleSystem.h" #include "../system/PhysicsSystem.h" #include "../system/RenderSystem.h" #include "../system/ScriptSystem.h" -#include "..//system/PhysicsSystem.h" -#include "../system/CollisionSystem.h" #include "LoopManager.h" #include "LoopTimer.h" diff --git a/src/crepe/api/Rigidbody.cpp b/src/crepe/api/Rigidbody.cpp index c4b1d6f..8213afb 100644 --- a/src/crepe/api/Rigidbody.cpp +++ b/src/crepe/api/Rigidbody.cpp @@ -10,6 +10,4 @@ void crepe::Rigidbody::add_force_linear(const vec2 & force) { this->data.linear_velocity += force; } -void crepe::Rigidbody::add_force_angular(float force) { - this->data.angular_velocity += force; -} +void crepe::Rigidbody::add_force_angular(float force) { this->data.angular_velocity += force; } diff --git a/src/crepe/api/Rigidbody.h b/src/crepe/api/Rigidbody.h index 431e000..756cc28 100644 --- a/src/crepe/api/Rigidbody.h +++ b/src/crepe/api/Rigidbody.h @@ -78,9 +78,9 @@ public: //! Linear velocity of the object (speed and direction). vec2 linear_velocity; //! Maximum linear velocity of the object. This limits the object's speed. - vec2 max_linear_velocity = {INFINITY ,INFINITY}; + vec2 max_linear_velocity = {INFINITY, INFINITY}; //! Linear velocity coefficient. This scales the object's velocity for adjustment or damping. - vec2 linear_velocity_coefficient = {1,1}; + vec2 linear_velocity_coefficient = {1, 1}; //! \} /** diff --git a/src/crepe/system/CollisionSystem.cpp b/src/crepe/system/CollisionSystem.cpp index 2d5ce9d..34cd125 100644 --- a/src/crepe/system/CollisionSystem.cpp +++ b/src/crepe/system/CollisionSystem.cpp @@ -1,23 +1,23 @@ -#include #include +#include #include #include +#include #include #include -#include -#include "api/Event.h" -#include "api/EventManager.h" #include "api/BoxCollider.h" #include "api/CircleCollider.h" +#include "api/Event.h" +#include "api/EventManager.h" #include "api/Metadata.h" -#include "api/Vector2.h" #include "api/Rigidbody.h" #include "api/Transform.h" +#include "api/Vector2.h" -#include "ComponentManager.h" -#include "CollisionSystem.h" #include "Collider.h" +#include "CollisionSystem.h" +#include "ComponentManager.h" #include "types.h" #include "util/OptionalRef.h" @@ -26,158 +26,191 @@ using namespace crepe; void CollisionSystem::update() { std::vector all_colliders; game_object_id_t id = 0; - RefVector rigidbodies = this->component_manager.get_components_by_type(); + RefVector rigidbodies + = this->component_manager.get_components_by_type(); // Collisions can only happen on object with a rigidbody - for(Rigidbody& rigidbody : rigidbodies) { + for (Rigidbody & rigidbody : rigidbodies) { if (!rigidbody.active) continue; id = rigidbody.game_object_id; - Transform& transform = this->component_manager.get_components_by_id(id).front().get(); + Transform & transform + = this->component_manager.get_components_by_id(id).front().get(); // Check if the boxcollider is active and has the same id as the rigidbody. - RefVector boxcolliders = this->component_manager.get_components_by_type(); - for (BoxCollider& boxcollider : boxcolliders) { - if(boxcollider.game_object_id != id) continue; - if(!boxcollider.active) continue; - all_colliders.push_back( - { - .id = id, - .collider = collider_variant{boxcollider}, - .transform = transform, - .rigidbody = rigidbody - } - ); + RefVector boxcolliders + = this->component_manager.get_components_by_type(); + for (BoxCollider & boxcollider : boxcolliders) { + if (boxcollider.game_object_id != id) continue; + if (!boxcollider.active) continue; + all_colliders.push_back({.id = id, + .collider = collider_variant{boxcollider}, + .transform = transform, + .rigidbody = rigidbody}); } // Check if the circlecollider is active and has the same id as the rigidbody. - RefVector circlecolliders = this->component_manager.get_components_by_type(); - for (CircleCollider& circlecollider : circlecolliders) { - if(circlecollider.game_object_id != id) continue; - if(!circlecollider.active) continue; - all_colliders.push_back( - { - .id = id, - .collider = collider_variant{circlecollider}, - .transform = transform, - .rigidbody = rigidbody - } - ); + RefVector circlecolliders + = this->component_manager.get_components_by_type(); + for (CircleCollider & circlecollider : circlecolliders) { + if (circlecollider.game_object_id != id) continue; + if (!circlecollider.active) continue; + all_colliders.push_back({.id = id, + .collider = collider_variant{circlecollider}, + .transform = transform, + .rigidbody = rigidbody}); } } // Check between all colliders if there is a collision - std::vector> collided = this->gather_collisions(all_colliders); + std::vector> collided + = this->gather_collisions(all_colliders); - // For both objects call the collision handler - for (auto& collision_pair : collided) { - this->collision_handler_request(collision_pair.first,collision_pair.second); - this->collision_handler_request(collision_pair.second,collision_pair.first); + // For both objects call the collision handler + for (auto & collision_pair : collided) { + this->collision_handler_request(collision_pair.first, collision_pair.second); + this->collision_handler_request(collision_pair.second, collision_pair.first); } } -void CollisionSystem::collision_handler_request(CollisionInternal& this_data,CollisionInternal& other_data){ +void CollisionSystem::collision_handler_request(CollisionInternal & this_data, + CollisionInternal & other_data) { - CollisionInternalType type = this->get_collider_type(this_data.collider,other_data.collider); - std::pair resolution_data = this->collision_handler(this_data,other_data,type); + CollisionInternalType type + = this->get_collider_type(this_data.collider, other_data.collider); + std::pair resolution_data + = this->collision_handler(this_data, other_data, type); - OptionalRef this_metadata = this->component_manager.get_components_by_id(this_data.id).front().get(); - OptionalRef other_metadata = this->component_manager.get_components_by_id(other_data.id).front().get(); + OptionalRef this_metadata + = this->component_manager.get_components_by_id(this_data.id).front().get(); + OptionalRef other_metadata + = this->component_manager.get_components_by_id(other_data.id).front().get(); OptionalRef this_collider; OptionalRef other_collider; switch (type) { - case CollisionInternalType::BOX_BOX:{ + case CollisionInternalType::BOX_BOX: { this_collider = std::get>(this_data.collider); - other_collider = std::get>(other_data.collider); + other_collider + = std::get>(other_data.collider); break; } - case CollisionInternalType::BOX_CIRCLE:{ + case CollisionInternalType::BOX_CIRCLE: { this_collider = std::get>(this_data.collider); - other_collider = std::get>(other_data.collider); + other_collider + = std::get>(other_data.collider); break; } - case CollisionInternalType::CIRCLE_BOX:{ - this_collider = std::get>(this_data.collider); - other_collider = std::get>(other_data.collider); + case CollisionInternalType::CIRCLE_BOX: { + this_collider + = std::get>(this_data.collider); + other_collider + = std::get>(other_data.collider); break; } - case CollisionInternalType::CIRCLE_CIRCLE:{ - this_collider = std::get>(this_data.collider); - other_collider = std::get>(other_data.collider); + case CollisionInternalType::CIRCLE_CIRCLE: { + this_collider + = std::get>(this_data.collider); + other_collider + = std::get>(other_data.collider); break; } } // collision info crepe::CollisionSystem::CollisionInfo collision_info{ - .this_collider = this_collider, - .this_transform = this_data.transform, - .this_rigidbody = this_data.rigidbody, - .this_metadata = this_metadata, - .other_collider = other_collider, - .other_transform = other_data.transform, - .other_rigidbody = other_data.rigidbody, - .other_metadata = other_metadata, - .resolution = resolution_data.first, - .resolution_direction = resolution_data.second, - }; + .this_collider = this_collider, + .this_transform = this_data.transform, + .this_rigidbody = this_data.rigidbody, + .this_metadata = this_metadata, + .other_collider = other_collider, + .other_transform = other_data.transform, + .other_rigidbody = other_data.rigidbody, + .other_metadata = other_metadata, + .resolution = resolution_data.first, + .resolution_direction = resolution_data.second, + }; // Determine if static needs to be called - this->determine_collision_handler(collision_info); + this->determine_collision_handler(collision_info); } - -std::pair CollisionSystem::collision_handler(CollisionInternal& data1,CollisionInternal& data2,CollisionInternalType type) { +std::pair +CollisionSystem::collision_handler(CollisionInternal & data1, CollisionInternal & data2, + CollisionInternalType type) { vec2 resolution; switch (type) { - case CollisionInternalType::BOX_BOX: { - const BoxCollider & collider1 = std::get>(data1.collider); - const BoxCollider & collider2 = std::get>(data2.collider); - vec2 collider_pos1 = this->get_current_position(collider1.offset, data1.transform, data1.rigidbody); - vec2 collider_pos2 = this->get_current_position(collider2.offset, data2.transform, data2.rigidbody); - resolution = this->get_box_box_resolution(collider1,collider2,collider_pos1,collider_pos2); + case CollisionInternalType::BOX_BOX: { + const BoxCollider & collider1 + = std::get>(data1.collider); + const BoxCollider & collider2 + = std::get>(data2.collider); + vec2 collider_pos1 = this->get_current_position(collider1.offset, data1.transform, + data1.rigidbody); + vec2 collider_pos2 = this->get_current_position(collider2.offset, data2.transform, + data2.rigidbody); + resolution = this->get_box_box_resolution(collider1, collider2, collider_pos1, + collider_pos2); break; } case CollisionInternalType::BOX_CIRCLE: { - const BoxCollider & collider1 = std::get>(data1.collider); - const CircleCollider & collider2 = std::get>(data2.collider); - vec2 collider_pos1 = this->get_current_position(collider1.offset, data1.transform, data1.rigidbody); - vec2 collider_pos2 = this->get_current_position(collider2.offset, data2.transform, data2.rigidbody); - resolution = this->get_circle_box_resolution(collider2,collider1,collider_pos2,collider_pos1); + const BoxCollider & collider1 + = std::get>(data1.collider); + const CircleCollider & collider2 + = std::get>(data2.collider); + vec2 collider_pos1 = this->get_current_position(collider1.offset, data1.transform, + data1.rigidbody); + vec2 collider_pos2 = this->get_current_position(collider2.offset, data2.transform, + data2.rigidbody); + resolution = this->get_circle_box_resolution(collider2, collider1, collider_pos2, + collider_pos1); break; } - case CollisionInternalType::CIRCLE_CIRCLE: { - const CircleCollider & collider1 = std::get>(data1.collider); - const CircleCollider & collider2 = std::get>(data2.collider); - vec2 collider_pos1 = this->get_current_position(collider1.offset, data1.transform, data1.rigidbody); - vec2 collider_pos2 = this->get_current_position(collider2.offset, data2.transform, data2.rigidbody); - resolution = this->get_circle_circle_resolution(collider1,collider2,collider_pos1,collider_pos2); + case CollisionInternalType::CIRCLE_CIRCLE: { + const CircleCollider & collider1 + = std::get>(data1.collider); + const CircleCollider & collider2 + = std::get>(data2.collider); + vec2 collider_pos1 = this->get_current_position(collider1.offset, data1.transform, + data1.rigidbody); + vec2 collider_pos2 = this->get_current_position(collider2.offset, data2.transform, + data2.rigidbody); + resolution = this->get_circle_circle_resolution(collider1, collider2, + collider_pos1, collider_pos2); break; } - case CollisionInternalType::CIRCLE_BOX: { - const CircleCollider & collider1 = std::get>(data1.collider); - const BoxCollider & collider2 = std::get>(data2.collider); - vec2 collider_pos1 = this->get_current_position(collider1.offset, data1.transform, data1.rigidbody); - vec2 collider_pos2 = this->get_current_position(collider2.offset, data2.transform, data2.rigidbody); - resolution = this->get_circle_box_resolution(collider1,collider2,collider_pos1,collider_pos2); + case CollisionInternalType::CIRCLE_BOX: { + const CircleCollider & collider1 + = std::get>(data1.collider); + const BoxCollider & collider2 + = std::get>(data2.collider); + vec2 collider_pos1 = this->get_current_position(collider1.offset, data1.transform, + data1.rigidbody); + vec2 collider_pos2 = this->get_current_position(collider2.offset, data2.transform, + data2.rigidbody); + resolution = this->get_circle_box_resolution(collider1, collider2, collider_pos1, + collider_pos2); break; } } Direction resolution_direction = Direction::NONE; - if(resolution.x != 0 && resolution.y > 0) { + if (resolution.x != 0 && resolution.y > 0) { resolution_direction = Direction::BOTH; } else if (resolution.x != 0) { resolution_direction = Direction::X_DIRECTION; - if(data1.rigidbody.data.linear_velocity.y != 0) - resolution.y = data1.rigidbody.data.linear_velocity.y * (resolution.x/data1.rigidbody.data.linear_velocity.x); + if (data1.rigidbody.data.linear_velocity.y != 0) + resolution.y = data1.rigidbody.data.linear_velocity.y + * (resolution.x / data1.rigidbody.data.linear_velocity.x); } else if (resolution.y != 0) { resolution_direction = Direction::Y_DIRECTION; - if(data1.rigidbody.data.linear_velocity.x != 0) - resolution.x = data1.rigidbody.data.linear_velocity.x * (resolution.y/data1.rigidbody.data.linear_velocity.y); + if (data1.rigidbody.data.linear_velocity.x != 0) + resolution.x = data1.rigidbody.data.linear_velocity.x + * (resolution.y / data1.rigidbody.data.linear_velocity.y); } - return std::make_pair(resolution,resolution_direction); + return std::make_pair(resolution, resolution_direction); } -vec2 CollisionSystem::get_box_box_resolution(const BoxCollider& box_collider1,const BoxCollider& box_collider2,const vec2& final_position1,const vec2& final_position2) const -{ +vec2 CollisionSystem::get_box_box_resolution(const BoxCollider & box_collider1, + const BoxCollider & box_collider2, + const vec2 & final_position1, + const vec2 & final_position2) const { vec2 resolution; // Default resolution vector vec2 delta = final_position2 - final_position1; @@ -210,97 +243,107 @@ vec2 CollisionSystem::get_box_box_resolution(const BoxCollider& box_collider1,co return resolution; } -vec2 CollisionSystem::get_circle_circle_resolution(const CircleCollider& circle_collider1, const CircleCollider& circle_collider2, const vec2& final_position1, const vec2& final_position2) const -{ - vec2 delta = final_position2 - final_position1; +vec2 CollisionSystem::get_circle_circle_resolution(const CircleCollider & circle_collider1, + const CircleCollider & circle_collider2, + const vec2 & final_position1, + const vec2 & final_position2) const { + vec2 delta = final_position2 - final_position1; - // Compute the distance between the two circle centers - float distance = std::sqrt(delta.x * delta.x + delta.y * delta.y); + // Compute the distance between the two circle centers + float distance = std::sqrt(delta.x * delta.x + delta.y * delta.y); - // Compute the combined radii of the two circles - float combined_radius = circle_collider1.radius + circle_collider2.radius; + // Compute the combined radii of the two circles + float combined_radius = circle_collider1.radius + circle_collider2.radius; - // Compute the penetration depth - float penetration_depth = combined_radius - distance; + // Compute the penetration depth + float penetration_depth = combined_radius - distance; - // Normalize the delta vector to get the collision direction - vec2 collision_normal = delta / distance; + // Normalize the delta vector to get the collision direction + vec2 collision_normal = delta / distance; - // Compute the resolution vector - vec2 resolution = collision_normal * penetration_depth; + // Compute the resolution vector + vec2 resolution = collision_normal * penetration_depth; - return resolution; + return resolution; } -vec2 CollisionSystem::get_circle_box_resolution(const CircleCollider& circle_collider, const BoxCollider& box_collider, const vec2& circle_position, const vec2& box_position) const -{ - vec2 delta = circle_position - box_position; +vec2 CollisionSystem::get_circle_box_resolution(const CircleCollider & circle_collider, + const BoxCollider & box_collider, + const vec2 & circle_position, + const vec2 & box_position) const { + vec2 delta = circle_position - box_position; - // Compute half-dimensions of the box - float half_width = box_collider.dimensions.x / 2.0f; - float half_height = box_collider.dimensions.y / 2.0f; + // Compute half-dimensions of the box + float half_width = box_collider.dimensions.x / 2.0f; + float half_height = box_collider.dimensions.y / 2.0f; - // Clamp circle center to the nearest point on the box - vec2 closest_point; - closest_point.x = std::clamp(delta.x, -half_width, half_width); - closest_point.y = std::clamp(delta.y, -half_height, half_height); + // Clamp circle center to the nearest point on the box + vec2 closest_point; + closest_point.x = std::clamp(delta.x, -half_width, half_width); + closest_point.y = std::clamp(delta.y, -half_height, half_height); - // Find the vector from the circle center to the closest point - vec2 closest_delta = delta - closest_point; + // Find the vector from the circle center to the closest point + vec2 closest_delta = delta - closest_point; - // Normalize the delta to get the collision direction - float distance = std::sqrt(closest_delta.x * closest_delta.x + closest_delta.y * closest_delta.y); - vec2 collision_normal = closest_delta / distance; + // Normalize the delta to get the collision direction + float distance + = std::sqrt(closest_delta.x * closest_delta.x + closest_delta.y * closest_delta.y); + vec2 collision_normal = closest_delta / distance; - // Compute penetration depth - float penetration_depth = circle_collider.radius - distance; + // Compute penetration depth + float penetration_depth = circle_collider.radius - distance; - // Compute the resolution vector - vec2 resolution = collision_normal * penetration_depth; + // Compute the resolution vector + vec2 resolution = collision_normal * penetration_depth; - return resolution; + return resolution; } - -void CollisionSystem::determine_collision_handler(CollisionInfo& info){ +void CollisionSystem::determine_collision_handler(CollisionInfo & info) { // Check rigidbody type for static - if(info.this_rigidbody.data.body_type == Rigidbody::BodyType::STATIC) return; + if (info.this_rigidbody.data.body_type == Rigidbody::BodyType::STATIC) return; // If second body is static perform the static collision handler in this system - if(info.other_rigidbody.data.body_type == Rigidbody::BodyType::STATIC){ + if (info.other_rigidbody.data.body_type == Rigidbody::BodyType::STATIC) { static_collision_handler(info); - }; + }; // Call collision event for user CollisionEvent data(info); - EventManager::get_instance().trigger_event(data, info.this_collider.game_object_id); + EventManager::get_instance().trigger_event( + data, info.this_collider.game_object_id); } -void CollisionSystem::static_collision_handler(CollisionInfo& info){ - // Move object back using calculate move back value +void CollisionSystem::static_collision_handler(CollisionInfo & info) { + // Move object back using calculate move back value info.this_transform.position += info.resolution; // If bounce is enabled mirror velocity - if(info.this_rigidbody.data.elastisity_coefficient > 0) { - if(info.resolution_direction == Direction::BOTH) - { - info.this_rigidbody.data.linear_velocity.y = -info.this_rigidbody.data.linear_velocity.y * info.this_rigidbody.data.elastisity_coefficient; - info.this_rigidbody.data.linear_velocity.x = -info.this_rigidbody.data.linear_velocity.x * info.this_rigidbody.data.elastisity_coefficient; - } - else if(info.resolution_direction == Direction::Y_DIRECTION) { - info.this_rigidbody.data.linear_velocity.y = -info.this_rigidbody.data.linear_velocity.y * info.this_rigidbody.data.elastisity_coefficient; - } - else if(info.resolution_direction == Direction::X_DIRECTION){ - info.this_rigidbody.data.linear_velocity.x = -info.this_rigidbody.data.linear_velocity.x * info.this_rigidbody.data.elastisity_coefficient; + if (info.this_rigidbody.data.elastisity_coefficient > 0) { + if (info.resolution_direction == Direction::BOTH) { + info.this_rigidbody.data.linear_velocity.y + = -info.this_rigidbody.data.linear_velocity.y + * info.this_rigidbody.data.elastisity_coefficient; + info.this_rigidbody.data.linear_velocity.x + = -info.this_rigidbody.data.linear_velocity.x + * info.this_rigidbody.data.elastisity_coefficient; + } else if (info.resolution_direction == Direction::Y_DIRECTION) { + info.this_rigidbody.data.linear_velocity.y + = -info.this_rigidbody.data.linear_velocity.y + * info.this_rigidbody.data.elastisity_coefficient; + } else if (info.resolution_direction == Direction::X_DIRECTION) { + info.this_rigidbody.data.linear_velocity.x + = -info.this_rigidbody.data.linear_velocity.x + * info.this_rigidbody.data.elastisity_coefficient; } } // Stop movement if bounce is disabled else { - info.this_rigidbody.data.linear_velocity = {0,0}; + info.this_rigidbody.data.linear_velocity = {0, 0}; } } -std::vector> CollisionSystem::gather_collisions(std::vector & colliders) { - - +std::vector> +CollisionSystem::gather_collisions(std::vector & colliders) { + // TODO: // If no colliders skip // Check if colliders has rigidbody if not skip @@ -311,83 +354,103 @@ std::vector> collisions_ret; - //using visit to visit the variant to access the active and id. + std::vector> collisions_ret; + //using visit to visit the variant to access the active and id. for (size_t i = 0; i < colliders.size(); ++i) { for (size_t j = i + 1; j < colliders.size(); ++j) { - if(colliders[i].id == colliders[j].id) continue; - CollisionInternalType type = get_collider_type(colliders[i].collider,colliders[j].collider); - if(!get_collision({ - .collider = colliders[i].collider, - .transform = colliders[i].transform, - .rigidbody = colliders[i].rigidbody, + if (colliders[i].id == colliders[j].id) continue; + CollisionInternalType type + = get_collider_type(colliders[i].collider, colliders[j].collider); + if (!get_collision( + { + .collider = colliders[i].collider, + .transform = colliders[i].transform, + .rigidbody = colliders[i].rigidbody, }, { - .collider = colliders[j].collider, - .transform = colliders[j].transform, - .rigidbody = colliders[j].rigidbody, + .collider = colliders[j].collider, + .transform = colliders[j].transform, + .rigidbody = colliders[j].rigidbody, }, - type)) continue; - collisions_ret.emplace_back(colliders[i],colliders[j]); + type)) + continue; + collisions_ret.emplace_back(colliders[i], colliders[j]); } } - + return collisions_ret; } -CollisionSystem::CollisionInternalType CollisionSystem::get_collider_type(const collider_variant& collider1,const collider_variant& collider2) const{ - if(std::holds_alternative>(collider1)){ - if(std::holds_alternative>(collider2)) - { +CollisionSystem::CollisionInternalType +CollisionSystem::get_collider_type(const collider_variant & collider1, + const collider_variant & collider2) const { + if (std::holds_alternative>(collider1)) { + if (std::holds_alternative>(collider2)) { return CollisionInternalType::CIRCLE_CIRCLE; - } - else { + } else { return CollisionInternalType::CIRCLE_BOX; } - } - else { - if(std::holds_alternative>(collider2)) - { + } else { + if (std::holds_alternative>(collider2)) { return CollisionInternalType::BOX_CIRCLE; - } - else { + } else { return CollisionInternalType::BOX_BOX; } } } -bool CollisionSystem::get_collision(const CollisionInternal& first_info,const CollisionInternal& second_info, CollisionInternalType type) const{ +bool CollisionSystem::get_collision(const CollisionInternal & first_info, + const CollisionInternal & second_info, + CollisionInternalType type) const { switch (type) { - case CollisionInternalType::BOX_BOX: { - const BoxCollider & box_collider1 = std::get>(first_info.collider); - const BoxCollider & box_collider2 = std::get>(second_info.collider); - return this->get_box_box_collision(box_collider1,box_collider2,first_info.transform,second_info.transform,second_info.rigidbody,second_info.rigidbody); + case CollisionInternalType::BOX_BOX: { + const BoxCollider & box_collider1 + = std::get>(first_info.collider); + const BoxCollider & box_collider2 + = std::get>(second_info.collider); + return this->get_box_box_collision(box_collider1, box_collider2, + first_info.transform, second_info.transform, + second_info.rigidbody, second_info.rigidbody); } case CollisionInternalType::BOX_CIRCLE: { - const BoxCollider & box_collider = std::get>(first_info.collider); - const CircleCollider & circle_collider = std::get>(second_info.collider); - return this->get_box_circle_collision(box_collider,circle_collider,first_info.transform,second_info.transform,second_info.rigidbody,second_info.rigidbody); + const BoxCollider & box_collider + = std::get>(first_info.collider); + const CircleCollider & circle_collider + = std::get>(second_info.collider); + return this->get_box_circle_collision( + box_collider, circle_collider, first_info.transform, second_info.transform, + second_info.rigidbody, second_info.rigidbody); } - case CollisionInternalType::CIRCLE_CIRCLE: { - const CircleCollider & circle_collider1 = std::get>(first_info.collider); - const CircleCollider & circle_collider2 = std::get>(second_info.collider); - return this->get_circle_circle_collision(circle_collider1,circle_collider2,first_info.transform,second_info.transform,second_info.rigidbody,second_info.rigidbody); + case CollisionInternalType::CIRCLE_CIRCLE: { + const CircleCollider & circle_collider1 + = std::get>(first_info.collider); + const CircleCollider & circle_collider2 + = std::get>(second_info.collider); + return this->get_circle_circle_collision( + circle_collider1, circle_collider2, first_info.transform, + second_info.transform, second_info.rigidbody, second_info.rigidbody); } - case CollisionInternalType::CIRCLE_BOX: { - const CircleCollider & circle_collider = std::get>(first_info.collider); - const BoxCollider & box_collider = std::get>(second_info.collider); - return this->get_box_circle_collision(box_collider,circle_collider,first_info.transform,second_info.transform,second_info.rigidbody,second_info.rigidbody); + case CollisionInternalType::CIRCLE_BOX: { + const CircleCollider & circle_collider + = std::get>(first_info.collider); + const BoxCollider & box_collider + = std::get>(second_info.collider); + return this->get_box_circle_collision( + box_collider, circle_collider, first_info.transform, second_info.transform, + second_info.rigidbody, second_info.rigidbody); } } return false; } - -bool CollisionSystem::get_box_box_collision(const BoxCollider& box1, const BoxCollider& box2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2) const -{ +bool CollisionSystem::get_box_box_collision(const BoxCollider & box1, const BoxCollider & box2, + const Transform & transform1, + const Transform & transform2, + const Rigidbody & rigidbody1, + const Rigidbody & rigidbody2) const { // Get current positions of colliders - vec2 final_position1 = this->get_current_position(box1.offset,transform1,rigidbody1); - vec2 final_position2 = this->get_current_position(box2.offset,transform2,rigidbody2); + vec2 final_position1 = this->get_current_position(box1.offset, transform1, rigidbody1); + vec2 final_position2 = this->get_current_position(box2.offset, transform2, rigidbody2); // Calculate half-extents (half width and half height) float half_width1 = box1.dimensions.x / 2.0; @@ -396,13 +459,18 @@ bool CollisionSystem::get_box_box_collision(const BoxCollider& box1, const BoxCo float half_height2 = box2.dimensions.y / 2.0; // Check if the boxes overlap along the X and Y axes - return (final_position1.x + half_width1 > final_position2.x - half_width2 && - final_position1.x - half_width1 < final_position2.x + half_width2 && - final_position1.y + half_height1 > final_position2.y - half_height2 && - final_position1.y - half_height1 < final_position2.y + half_height2); + return (final_position1.x + half_width1 > final_position2.x - half_width2 + && final_position1.x - half_width1 < final_position2.x + half_width2 + && final_position1.y + half_height1 > final_position2.y - half_height2 + && final_position1.y - half_height1 < final_position2.y + half_height2); } -bool CollisionSystem::get_box_circle_collision(const BoxCollider& box1, const CircleCollider& circle2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2) const { +bool CollisionSystem::get_box_circle_collision(const BoxCollider & box1, + const CircleCollider & circle2, + const Transform & transform1, + const Transform & transform2, + const Rigidbody & rigidbody1, + const Rigidbody & rigidbody2) const { // Get current positions of colliders vec2 final_position1 = this->get_current_position(box1.offset, transform1, rigidbody1); vec2 final_position2 = this->get_current_position(circle2.offset, transform2, rigidbody2); @@ -412,8 +480,10 @@ bool CollisionSystem::get_box_circle_collision(const BoxCollider& box1, const Ci float half_height = box1.dimensions.y / 2.0; // Find the closest point on the box to the circle's center - float closest_x = std::max(final_position1.x - half_width, std::min(final_position2.x, final_position1.x + half_width)); - float closest_y = std::max(final_position1.y - half_height, std::min(final_position2.y, final_position1.y + half_height)); + float closest_x = std::max(final_position1.x - half_width, + std::min(final_position2.x, final_position1.x + half_width)); + float closest_y = std::max(final_position1.y - half_height, + std::min(final_position2.y, final_position1.y + half_height)); // Calculate the distance squared between the circle's center and the closest point on the box float distance_x = final_position2.x - closest_x; @@ -424,10 +494,15 @@ bool CollisionSystem::get_box_circle_collision(const BoxCollider& box1, const Ci return distance_squared <= circle2.radius * circle2.radius; } -bool CollisionSystem::get_circle_circle_collision(const CircleCollider& circle1, const CircleCollider& circle2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2) const { +bool CollisionSystem::get_circle_circle_collision(const CircleCollider & circle1, + const CircleCollider & circle2, + const Transform & transform1, + const Transform & transform2, + const Rigidbody & rigidbody1, + const Rigidbody & rigidbody2) const { // Get current positions of colliders - vec2 final_position1 = this->get_current_position(circle1.offset,transform1,rigidbody1); - vec2 final_position2 = this->get_current_position(circle2.offset,transform2,rigidbody2); + vec2 final_position1 = this->get_current_position(circle1.offset, transform1, rigidbody1); + vec2 final_position2 = this->get_current_position(circle2.offset, transform2, rigidbody2); float distance_x = final_position1.x - final_position2.x; float distance_y = final_position1.y - final_position2.y; @@ -440,7 +515,9 @@ bool CollisionSystem::get_circle_circle_collision(const CircleCollider& circle1, return distance_squared <= radius_sum * radius_sum; } -vec2 CollisionSystem::get_current_position(const vec2& collider_offset, const Transform& transform, const Rigidbody& rigidbody) const { +vec2 CollisionSystem::get_current_position(const vec2 & collider_offset, + const Transform & transform, + const Rigidbody & rigidbody) const { // Get the rotation in radians float radians1 = transform.rotation * (M_PI / 180.0); @@ -448,10 +525,11 @@ vec2 CollisionSystem::get_current_position(const vec2& collider_offset, const Tr vec2 total_offset = (rigidbody.data.offset + collider_offset) * transform.scale; // Rotate - float rotated_total_offset_x1 = total_offset.x * cos(radians1) - total_offset.y * sin(radians1); - float rotated_total_offset_y1 = total_offset.x * sin(radians1) + total_offset.y * cos(radians1); + float rotated_total_offset_x1 + = total_offset.x * cos(radians1) - total_offset.y * sin(radians1); + float rotated_total_offset_y1 + = total_offset.x * sin(radians1) + total_offset.y * cos(radians1); // Final positions considering scaling and rotation - return(transform.position + vec2(rotated_total_offset_x1, rotated_total_offset_y1)); - + return (transform.position + vec2(rotated_total_offset_x1, rotated_total_offset_y1)); } diff --git a/src/crepe/system/CollisionSystem.h b/src/crepe/system/CollisionSystem.h index 85ae5ad..6b5a4bb 100644 --- a/src/crepe/system/CollisionSystem.h +++ b/src/crepe/system/CollisionSystem.h @@ -1,38 +1,37 @@ #pragma once -#include -#include #include +#include +#include -#include "api/Rigidbody.h" -#include "api/Transform.h" #include "api/BoxCollider.h" #include "api/CircleCollider.h" #include "api/Metadata.h" +#include "api/Rigidbody.h" +#include "api/Transform.h" #include "api/Vector2.h" #include "Collider.h" #include "System.h" - namespace crepe { - //! A system responsible for detecting and handling collisions between colliders. class CollisionSystem : public System { public: using System::System; + private: - //! A variant type that can hold either a BoxCollider or a CircleCollider. - using collider_variant = std::variant, std::reference_wrapper>; + using collider_variant = std::variant, + std::reference_wrapper>; //! Enum representing the types of collider pairs for collision detection. enum class CollisionInternalType { - BOX_BOX, - CIRCLE_CIRCLE, - BOX_CIRCLE, - CIRCLE_BOX, + BOX_BOX, + CIRCLE_CIRCLE, + BOX_CIRCLE, + CIRCLE_BOX, }; /** @@ -45,21 +44,21 @@ private: */ struct CollisionInternal { game_object_id_t id = 0; - collider_variant collider; - Transform& transform; - Rigidbody& rigidbody; + collider_variant collider; + Transform & transform; + Rigidbody & rigidbody; }; - + //! Enum representing movement directions during collision resolution. enum class Direction { //! No movement required. - NONE, + NONE, //! Movement in the X direction. - X_DIRECTION, + X_DIRECTION, //! Movement in the Y direction. - Y_DIRECTION, + Y_DIRECTION, //! Movement in both X and Y directions. - BOTH + BOTH }; public: @@ -68,15 +67,15 @@ public: * * Includes information about the colliding objects and the resolution data for handling the collision. */ - struct CollisionInfo{ - Collider& this_collider; - Transform& this_transform; - Rigidbody& this_rigidbody; - Metadata& this_metadata; - Collider& other_collider; - Transform& other_transform; - Rigidbody& other_rigidbody; - Metadata& other_metadata; + struct CollisionInfo { + Collider & this_collider; + Transform & this_transform; + Rigidbody & this_rigidbody; + Metadata & this_metadata; + Collider & other_collider; + Transform & other_transform; + Rigidbody & other_rigidbody; + Metadata & other_metadata; //! The resolution vector for the collision. vec2 resolution; //! The direction of movement for resolving the collision. @@ -84,11 +83,10 @@ public: }; public: - //! Updates the collision system by checking for collisions between colliders and handling them. void update() override; -private: +private: /** * \brief Determines the type of collider pair from two colliders. * @@ -98,7 +96,8 @@ private: * \param collider2 Second collider variant (BoxCollider or CircleCollider). * \return The combined type of the two colliders. */ - CollisionInternalType get_collider_type(const collider_variant& collider1,const collider_variant& collider2) const; + CollisionInternalType get_collider_type(const collider_variant & collider1, + const collider_variant & collider2) const; /** * \brief Calculates the current position of a collider. @@ -110,10 +109,10 @@ private: * \param rigidbody The Rigidbody of the associated game object. * \return The calculated position of the collider. */ - vec2 get_current_position(const vec2& collider_offset, const Transform& transform, const Rigidbody& rigidbody) const; + vec2 get_current_position(const vec2 & collider_offset, const Transform & transform, + const Rigidbody & rigidbody) const; private: - /** * \brief Handles collision resolution between two colliders. * @@ -122,7 +121,7 @@ private: * \param data1 Collision data for the first collider. * \param data2 Collision data for the second collider. */ - void collision_handler_request(CollisionInternal& data1,CollisionInternal& data2); + void collision_handler_request(CollisionInternal & data1, CollisionInternal & data2); /** * \brief Resolves collision between two colliders and calculates the movement required. @@ -134,7 +133,9 @@ private: * \param type The type of collider pair. * \return A pair containing the resolution vector and direction for the first collider. */ - std::pair collision_handler(CollisionInternal& data1,CollisionInternal& data2 ,CollisionInternalType type); + std::pair collision_handler(CollisionInternal & data1, + CollisionInternal & data2, + CollisionInternalType type); /** * \brief Calculates the resolution vector for two BoxColliders. @@ -147,7 +148,9 @@ private: * \param position2 The position of the second BoxCollider. * \return The resolution vector for the collision. */ - vec2 get_box_box_resolution(const BoxCollider& box_collider1,const BoxCollider& box_collider2,const vec2& position1,const vec2& position2) const; + vec2 get_box_box_resolution(const BoxCollider & box_collider1, + const BoxCollider & box_collider2, const vec2 & position1, + const vec2 & position2) const; /** * \brief Calculates the resolution vector for two CircleCollider. @@ -160,7 +163,10 @@ private: * \param position2 The position of the second CircleCollider. * \return The resolution vector for the collision. */ - vec2 get_circle_circle_resolution(const CircleCollider& circle_collider1, const CircleCollider& circle_collider2, const vec2& final_position1, const vec2& final_position2) const; + vec2 get_circle_circle_resolution(const CircleCollider & circle_collider1, + const CircleCollider & circle_collider2, + const vec2 & final_position1, + const vec2 & final_position2) const; /** * \brief Calculates the resolution vector for two CircleCollider. @@ -173,7 +179,10 @@ private: * \param box_position The position of the BocCollider. * \return The resolution vector for the collision. */ - vec2 get_circle_box_resolution(const CircleCollider& circle_collider, const BoxCollider& box_collider, const vec2& circle_position, const vec2& box_position) const; + vec2 get_circle_box_resolution(const CircleCollider & circle_collider, + const BoxCollider & box_collider, + const vec2 & circle_position, + const vec2 & box_position) const; /** * \brief Determines the appropriate collision handler for a collision. @@ -182,7 +191,7 @@ private: * * \param info Collision information containing data about both colliders. */ - void determine_collision_handler(CollisionInfo& info); + void determine_collision_handler(CollisionInfo & info); /** * \brief Handles collisions involving static objects. @@ -191,9 +200,9 @@ private: * * \param info Collision information containing data about both colliders. */ - void static_collision_handler(CollisionInfo& info); + void static_collision_handler(CollisionInfo & info); + private: - /** * \brief Checks for collisions between colliders. * @@ -202,7 +211,8 @@ private: * \param colliders A collection of all active colliders. * \return A list of collision pairs with their associated data. */ - std::vector> gather_collisions(std::vector & colliders); + std::vector> + gather_collisions(std::vector & colliders); /** * \brief Checks for collision between two colliders. @@ -214,8 +224,10 @@ private: * \param type The type of collider pair. * \return True if a collision is detected, otherwise false. */ - bool get_collision(const CollisionInternal& first_info,const CollisionInternal& second_info, CollisionInternalType type) const; - + bool get_collision(const CollisionInternal & first_info, + const CollisionInternal & second_info, + CollisionInternalType type) const; + /** * \brief Detects collisions between two BoxColliders. * @@ -227,8 +239,11 @@ private: * \param rigidbody2 Rigidbody of the second object. * \return True if a collision is detected, otherwise false. */ - bool get_box_box_collision(const BoxCollider& box1, const BoxCollider& box2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2) const; - + bool get_box_box_collision(const BoxCollider & box1, const BoxCollider & box2, + const Transform & transform1, const Transform & transform2, + const Rigidbody & rigidbody1, + const Rigidbody & rigidbody2) const; + /** * \brief Check collision for box on circle collider * @@ -240,7 +255,10 @@ private: * \param rigidbody2 Rigidbody of the second object. * \return True if a collision is detected, otherwise false. */ - bool get_box_circle_collision(const BoxCollider& box1, const CircleCollider& circle2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2) const; + bool get_box_circle_collision(const BoxCollider & box1, const CircleCollider & circle2, + const Transform & transform1, const Transform & transform2, + const Rigidbody & rigidbody1, + const Rigidbody & rigidbody2) const; /** * \brief Check collision for circle on circle collider @@ -255,7 +273,12 @@ private: * * \return status of collision */ - bool get_circle_circle_collision(const CircleCollider& circle1, const CircleCollider& circle2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2) const; + bool get_circle_circle_collision(const CircleCollider & circle1, + const CircleCollider & circle2, + const Transform & transform1, + const Transform & transform2, + const Rigidbody & rigidbody1, + const Rigidbody & rigidbody2) const; }; } // namespace crepe diff --git a/src/crepe/system/PhysicsSystem.cpp b/src/crepe/system/PhysicsSystem.cpp index b5da042..b3adfa1 100644 --- a/src/crepe/system/PhysicsSystem.cpp +++ b/src/crepe/system/PhysicsSystem.cpp @@ -32,10 +32,13 @@ void PhysicsSystem::update() { } // Add damping if (rigidbody.data.angular_velocity_coefficient > 0) { - rigidbody.data.angular_velocity *= rigidbody.data.angular_velocity_coefficient; + rigidbody.data.angular_velocity + *= rigidbody.data.angular_velocity_coefficient; } - if (rigidbody.data.linear_velocity_coefficient.x > 0 && rigidbody.data.linear_velocity_coefficient.y > 0) { - rigidbody.data.linear_velocity *= rigidbody.data.linear_velocity_coefficient; + if (rigidbody.data.linear_velocity_coefficient.x > 0 + && rigidbody.data.linear_velocity_coefficient.y > 0) { + rigidbody.data.linear_velocity + *= rigidbody.data.linear_velocity_coefficient; } // Max velocity check diff --git a/src/example/game.cpp b/src/example/game.cpp index de08a22..70c562e 100644 --- a/src/example/game.cpp +++ b/src/example/game.cpp @@ -1,77 +1,84 @@ -#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 { - bool oncollision(const CollisionEvent& test) { + bool oncollision(const CollisionEvent & test) { Log::logf("Box {} script on_collision()", test.info.this_collider.game_object_id); return true; } void init() { - subscribe([this](const CollisionEvent& ev) -> bool { - return this->oncollision(ev); - }); + subscribe( + [this](const CollisionEvent & ev) -> bool { return this->oncollision(ev); }); } 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, 255); + ComponentManager & mgr = this->component_manager; + Color color(0, 0, 0, 255); - float screen_size_width = 640; - float screen_size_height = 480; - float world_collider = 1000; - //define playable world - GameObject world = mgr.new_object("Name", "Tag", vec2{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}, - .offset = {0,0} - }); - world.add_component(vec2{0, 0-(screen_size_height/2+world_collider/2)}, vec2{world_collider, world_collider});; // Top - world.add_component(vec2{0, screen_size_height/2+world_collider/2}, vec2{world_collider, world_collider}); // Bottom - world.add_component(vec2{0-(screen_size_width/2+world_collider/2), 0}, vec2{world_collider, world_collider}); // Left - world.add_component(vec2{screen_size_width/2+world_collider/2, 0}, vec2{world_collider, world_collider}); // right - world.add_component(Color::WHITE, ivec2{640, 480},vec2{640, 480}, 1.0f); + float screen_size_width = 640; + float screen_size_height = 480; + float world_collider = 1000; + //define playable world + GameObject world = mgr.new_object( + "Name", "Tag", vec2{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}, + .offset = {0, 0}}); + world.add_component( + vec2{0, 0 - (screen_size_height / 2 + world_collider / 2)}, + vec2{world_collider, world_collider}); + ; // Top + world.add_component(vec2{0, screen_size_height / 2 + world_collider / 2}, + vec2{world_collider, world_collider}); // Bottom + world.add_component( + vec2{0 - (screen_size_width / 2 + world_collider / 2), 0}, + vec2{world_collider, world_collider}); // Left + world.add_component(vec2{screen_size_width / 2 + world_collider / 2, 0}, + vec2{world_collider, world_collider}); // right + world.add_component(Color::WHITE, ivec2{640, 480}, vec2{640, 480}, 1.0f); - GameObject game_object1 = mgr.new_object("Name", "Tag", vec2{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,1}, - .constraints = {0, 0, 0}, - .elastisity_coefficient = 1, - .offset = {0,0}, - }); - game_object1.add_component(vec2{0, 0}, vec2{20, 20}); - game_object1.add_component().set_script(); - auto img = Texture("asset/texture/green_square.png"); - game_object1.add_component(img, color, Sprite::FlipSettings{false, false}, 1, 1, 20); + GameObject game_object1 = mgr.new_object( + "Name", "Tag", vec2{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, 1}, + .constraints = {0, 0, 0}, + .elastisity_coefficient = 1, + .offset = {0, 0}, + }); + game_object1.add_component(vec2{0, 0}, vec2{20, 20}); + game_object1.add_component().set_script(); + auto img = Texture("asset/texture/green_square.png"); + game_object1.add_component(img, color, Sprite::FlipSettings{false, false}, 1, + 1, 20); } string get_name() const { return "scene1"; } diff --git a/src/test/CollisionTest.cpp b/src/test/CollisionTest.cpp index fec42f3..74edaf7 100644 --- a/src/test/CollisionTest.cpp +++ b/src/test/CollisionTest.cpp @@ -26,22 +26,19 @@ using namespace testing; class CollisionHandler : public Script { public: int box_id; - function test_fn = [](const CollisionEvent & ev) { }; + function test_fn = [](const CollisionEvent & ev) {}; - CollisionHandler(int box_id) { - this->box_id = box_id; - } + CollisionHandler(int box_id) { this->box_id = box_id; } - bool on_collision(const CollisionEvent& ev) { + bool on_collision(const CollisionEvent & ev) { //Log::logf("Box {} script on_collision()", box_id); test_fn(ev); return true; } void init() { - subscribe([this](const CollisionEvent& ev) -> bool { - return this->on_collision(ev); - }); + subscribe( + [this](const CollisionEvent & ev) -> bool { return this->on_collision(ev); }); } void update() { // Retrieve component from the same GameObject this script is on @@ -54,18 +51,18 @@ public: CollisionSystem collision_sys{mgr}; ScriptSystem script_sys{mgr}; - GameObject world = mgr.new_object("world","",{50,50}); - GameObject game_object1 = mgr.new_object("object1", "", { 50, 50}); - GameObject game_object2 = mgr.new_object("object2", "", { 50, 30}); + GameObject world = mgr.new_object("world", "", {50, 50}); + GameObject game_object1 = mgr.new_object("object1", "", {50, 50}); + GameObject game_object2 = mgr.new_object("object2", "", {50, 30}); CollisionHandler * script_object1_ref = nullptr; CollisionHandler * script_object2_ref = nullptr; - + void SetUp() override { world.add_component(Rigidbody::Data{ // TODO: remove unrelated properties: .body_type = Rigidbody::BodyType::STATIC, - .offset = {0,0}, + .offset = {0, 0}, }); // Create a box with an inner size of 10x10 units world.add_component(vec2{0, -100}, vec2{100, 100}); // Top @@ -77,28 +74,30 @@ public: .mass = 1, .gravity_scale = 0.01, .body_type = Rigidbody::BodyType::DYNAMIC, - .linear_velocity = {0,0}, + .linear_velocity = {0, 0}, .constraints = {0, 0, 0}, .elastisity_coefficient = 1, - .offset = {0,0}, + .offset = {0, 0}, }); game_object1.add_component(vec2{0, 0}, vec2{10, 10}); - BehaviorScript & script_object1 = game_object1.add_component().set_script(1); - script_object1_ref = static_cast(script_object1.script.get()); + BehaviorScript & script_object1 + = game_object1.add_component().set_script(1); + script_object1_ref = static_cast(script_object1.script.get()); ASSERT_NE(script_object1_ref, nullptr); - + game_object2.add_component(Rigidbody::Data{ .mass = 1, .gravity_scale = 0.01, .body_type = Rigidbody::BodyType::DYNAMIC, - .linear_velocity = {0,0}, + .linear_velocity = {0, 0}, .constraints = {0, 0, 0}, .elastisity_coefficient = 1, - .offset = {0,0}, + .offset = {0, 0}, }); game_object2.add_component(vec2{0, 0}, vec2{10, 10}); - BehaviorScript & script_object2 = game_object2.add_component().set_script(2); - script_object2_ref = static_cast(script_object2.script.get()); + BehaviorScript & script_object2 + = game_object2.add_component().set_script(2); + script_object2_ref = static_cast(script_object2.script.get()); ASSERT_NE(script_object2_ref, nullptr); // Ensure Script::init() is called on all BehaviorScript instances @@ -139,7 +138,7 @@ TEST_F(CollisionTest, collision_box_box_dynamic_both_no_velocity) { }; EXPECT_FALSE(collision_happend); Transform & tf = this->mgr.get_components_by_id(1).front().get(); - tf.position = {50,30}; + tf.position = {50, 30}; collision_sys.update(); EXPECT_TRUE(collision_happend); } @@ -151,18 +150,20 @@ TEST_F(CollisionTest, collision_box_box_dynamic_x_direction_no_velocity) { EXPECT_EQ(ev.info.this_collider.game_object_id, 1); EXPECT_EQ(ev.info.resolution.x, -5); EXPECT_EQ(ev.info.resolution.y, 0); - EXPECT_EQ(ev.info.resolution_direction, crepe::CollisionSystem::Direction::X_DIRECTION); + EXPECT_EQ(ev.info.resolution_direction, + crepe::CollisionSystem::Direction::X_DIRECTION); }; script_object2_ref->test_fn = [&collision_happend](const CollisionEvent & ev) { collision_happend = true; EXPECT_EQ(ev.info.this_collider.game_object_id, 2); EXPECT_EQ(ev.info.resolution.x, 5); EXPECT_EQ(ev.info.resolution.y, 0); - EXPECT_EQ(ev.info.resolution_direction, crepe::CollisionSystem::Direction::X_DIRECTION); + EXPECT_EQ(ev.info.resolution_direction, + crepe::CollisionSystem::Direction::X_DIRECTION); }; EXPECT_FALSE(collision_happend); Transform & tf = this->mgr.get_components_by_id(1).front().get(); - tf.position = {45,30}; + tf.position = {45, 30}; collision_sys.update(); EXPECT_TRUE(collision_happend); } @@ -174,18 +175,20 @@ TEST_F(CollisionTest, collision_box_box_dynamic_y_direction_no_velocity) { EXPECT_EQ(ev.info.this_collider.game_object_id, 1); EXPECT_EQ(ev.info.resolution.x, 0); EXPECT_EQ(ev.info.resolution.y, -5); - EXPECT_EQ(ev.info.resolution_direction, crepe::CollisionSystem::Direction::Y_DIRECTION); + EXPECT_EQ(ev.info.resolution_direction, + crepe::CollisionSystem::Direction::Y_DIRECTION); }; script_object2_ref->test_fn = [&collision_happend](const CollisionEvent & ev) { collision_happend = true; EXPECT_EQ(ev.info.this_collider.game_object_id, 2); EXPECT_EQ(ev.info.resolution.x, 0); EXPECT_EQ(ev.info.resolution.y, 5); - EXPECT_EQ(ev.info.resolution_direction, crepe::CollisionSystem::Direction::Y_DIRECTION); + EXPECT_EQ(ev.info.resolution_direction, + crepe::CollisionSystem::Direction::Y_DIRECTION); }; EXPECT_FALSE(collision_happend); Transform & tf = this->mgr.get_components_by_id(1).front().get(); - tf.position = {50,25}; + tf.position = {50, 25}; collision_sys.update(); EXPECT_TRUE(collision_happend); } @@ -208,11 +211,11 @@ TEST_F(CollisionTest, collision_box_box_dynamic_both) { }; EXPECT_FALSE(collision_happend); Transform & tf = this->mgr.get_components_by_id(1).front().get(); - tf.position = {50,30}; + tf.position = {50, 30}; Rigidbody & rg1 = this->mgr.get_components_by_id(1).front().get(); - rg1.data.linear_velocity = {10,10}; + rg1.data.linear_velocity = {10, 10}; Rigidbody & rg2 = this->mgr.get_components_by_id(2).front().get(); - rg2.data.linear_velocity = {10,10}; + rg2.data.linear_velocity = {10, 10}; collision_sys.update(); EXPECT_TRUE(collision_happend); } @@ -224,22 +227,24 @@ TEST_F(CollisionTest, collision_box_box_dynamic_x_direction) { EXPECT_EQ(ev.info.this_collider.game_object_id, 1); EXPECT_EQ(ev.info.resolution.x, -5); EXPECT_EQ(ev.info.resolution.y, -5); - EXPECT_EQ(ev.info.resolution_direction, crepe::CollisionSystem::Direction::X_DIRECTION); + EXPECT_EQ(ev.info.resolution_direction, + crepe::CollisionSystem::Direction::X_DIRECTION); }; script_object2_ref->test_fn = [&collision_happend](const CollisionEvent & ev) { collision_happend = true; EXPECT_EQ(ev.info.this_collider.game_object_id, 2); EXPECT_EQ(ev.info.resolution.x, 5); EXPECT_EQ(ev.info.resolution.y, 5); - EXPECT_EQ(ev.info.resolution_direction, crepe::CollisionSystem::Direction::X_DIRECTION); + EXPECT_EQ(ev.info.resolution_direction, + crepe::CollisionSystem::Direction::X_DIRECTION); }; EXPECT_FALSE(collision_happend); Transform & tf = this->mgr.get_components_by_id(1).front().get(); - tf.position = {45,30}; + tf.position = {45, 30}; Rigidbody & rg1 = this->mgr.get_components_by_id(1).front().get(); - rg1.data.linear_velocity = {10,10}; + rg1.data.linear_velocity = {10, 10}; Rigidbody & rg2 = this->mgr.get_components_by_id(2).front().get(); - rg2.data.linear_velocity = {10,10}; + rg2.data.linear_velocity = {10, 10}; collision_sys.update(); EXPECT_TRUE(collision_happend); } @@ -251,27 +256,28 @@ TEST_F(CollisionTest, collision_box_box_dynamic_y_direction) { EXPECT_EQ(ev.info.this_collider.game_object_id, 1); EXPECT_EQ(ev.info.resolution.x, -5); EXPECT_EQ(ev.info.resolution.y, -5); - EXPECT_EQ(ev.info.resolution_direction, crepe::CollisionSystem::Direction::Y_DIRECTION); + EXPECT_EQ(ev.info.resolution_direction, + crepe::CollisionSystem::Direction::Y_DIRECTION); }; script_object2_ref->test_fn = [&collision_happend](const CollisionEvent & ev) { collision_happend = true; EXPECT_EQ(ev.info.this_collider.game_object_id, 2); EXPECT_EQ(ev.info.resolution.x, 5); EXPECT_EQ(ev.info.resolution.y, 5); - EXPECT_EQ(ev.info.resolution_direction, crepe::CollisionSystem::Direction::Y_DIRECTION); + EXPECT_EQ(ev.info.resolution_direction, + crepe::CollisionSystem::Direction::Y_DIRECTION); }; EXPECT_FALSE(collision_happend); Transform & tf = this->mgr.get_components_by_id(1).front().get(); - tf.position = {50,25}; + tf.position = {50, 25}; Rigidbody & rg1 = this->mgr.get_components_by_id(1).front().get(); - rg1.data.linear_velocity = {10,10}; + rg1.data.linear_velocity = {10, 10}; Rigidbody & rg2 = this->mgr.get_components_by_id(2).front().get(); - rg2.data.linear_velocity = {10,10}; + rg2.data.linear_velocity = {10, 10}; collision_sys.update(); EXPECT_TRUE(collision_happend); } - TEST_F(CollisionTest, collision_box_box_static_both) { bool collision_happend = false; script_object1_ref->test_fn = [&collision_happend](const CollisionEvent & ev) { @@ -287,7 +293,7 @@ TEST_F(CollisionTest, collision_box_box_static_both) { }; EXPECT_FALSE(collision_happend); Transform & tf = this->mgr.get_components_by_id(1).front().get(); - tf.position = {50,30}; + tf.position = {50, 30}; Rigidbody & rg2 = this->mgr.get_components_by_id(2).front().get(); rg2.data.body_type = crepe::Rigidbody::BodyType::STATIC; collision_sys.update(); @@ -301,7 +307,8 @@ TEST_F(CollisionTest, collision_box_box_static_x_direction) { EXPECT_EQ(ev.info.this_collider.game_object_id, 1); EXPECT_EQ(ev.info.resolution.x, -5); EXPECT_EQ(ev.info.resolution.y, -5); - EXPECT_EQ(ev.info.resolution_direction, crepe::CollisionSystem::Direction::X_DIRECTION); + EXPECT_EQ(ev.info.resolution_direction, + crepe::CollisionSystem::Direction::X_DIRECTION); }; script_object2_ref->test_fn = [&collision_happend](const CollisionEvent & ev) { // is static should not be called @@ -309,9 +316,9 @@ TEST_F(CollisionTest, collision_box_box_static_x_direction) { }; EXPECT_FALSE(collision_happend); Transform & tf = this->mgr.get_components_by_id(1).front().get(); - tf.position = {45,30}; + tf.position = {45, 30}; Rigidbody & rg1 = this->mgr.get_components_by_id(1).front().get(); - rg1.data.linear_velocity = {10,10}; + rg1.data.linear_velocity = {10, 10}; Rigidbody & rg2 = this->mgr.get_components_by_id(2).front().get(); rg2.data.body_type = crepe::Rigidbody::BodyType::STATIC; collision_sys.update(); @@ -325,7 +332,8 @@ TEST_F(CollisionTest, collision_box_box_static_y_direction) { EXPECT_EQ(ev.info.this_collider.game_object_id, 1); EXPECT_EQ(ev.info.resolution.x, -5); EXPECT_EQ(ev.info.resolution.y, -5); - EXPECT_EQ(ev.info.resolution_direction, crepe::CollisionSystem::Direction::Y_DIRECTION); + EXPECT_EQ(ev.info.resolution_direction, + crepe::CollisionSystem::Direction::Y_DIRECTION); }; script_object2_ref->test_fn = [&collision_happend](const CollisionEvent & ev) { // is static should not be called @@ -333,24 +341,24 @@ TEST_F(CollisionTest, collision_box_box_static_y_direction) { }; EXPECT_FALSE(collision_happend); Transform & tf = this->mgr.get_components_by_id(1).front().get(); - tf.position = {50,25}; + tf.position = {50, 25}; Rigidbody & rg1 = this->mgr.get_components_by_id(1).front().get(); - rg1.data.linear_velocity = {10,10}; + rg1.data.linear_velocity = {10, 10}; Rigidbody & rg2 = this->mgr.get_components_by_id(2).front().get(); rg2.data.body_type = crepe::Rigidbody::BodyType::STATIC; collision_sys.update(); EXPECT_TRUE(collision_happend); } -TEST_F(CollisionTest, collision_box_box_static_multiple) {//todo check visually +TEST_F(CollisionTest, collision_box_box_static_multiple) { //todo check visually bool collision_happend = false; float offset_value = 0; float resolution = 0; script_object1_ref->test_fn = [&](const CollisionEvent & ev) { collision_happend = true; EXPECT_EQ(ev.info.this_collider.game_object_id, 1); - EXPECT_EQ(ev.info.this_collider.offset.x , offset_value); - EXPECT_EQ(ev.info.resolution.x , resolution); + EXPECT_EQ(ev.info.this_collider.offset.x, offset_value); + EXPECT_EQ(ev.info.resolution.x, resolution); }; script_object2_ref->test_fn = [&](const CollisionEvent & ev) { // is static should not be called @@ -358,20 +366,20 @@ TEST_F(CollisionTest, collision_box_box_static_multiple) {//todo check visually }; EXPECT_FALSE(collision_happend); Transform & tf = this->mgr.get_components_by_id(1).front().get(); - tf.position = {45,30}; + tf.position = {45, 30}; Rigidbody & rg1 = this->mgr.get_components_by_id(1).front().get(); - rg1.data.linear_velocity = {10,10}; + rg1.data.linear_velocity = {10, 10}; Rigidbody & rg2 = this->mgr.get_components_by_id(2).front().get(); rg2.data.body_type = crepe::Rigidbody::BodyType::STATIC; BoxCollider & bxc = this->mgr.get_components_by_id(1).front().get(); - bxc.offset = {5,0}; + bxc.offset = {5, 0}; this->game_object1.add_component(vec2{-5, 0}, vec2{10, 10}); offset_value = 5; resolution = 10; collision_sys.update(); offset_value = -5; resolution = 10; - tf.position = {55,30}; + tf.position = {55, 30}; collision_sys.update(); EXPECT_TRUE(collision_happend); } diff --git a/src/test/Profiling.cpp b/src/test/Profiling.cpp index fa0f5f3..d2f219e 100644 --- a/src/test/Profiling.cpp +++ b/src/test/Profiling.cpp @@ -1,8 +1,8 @@ #include "system/ParticleSystem.h" #include "system/PhysicsSystem.h" #include "system/RenderSystem.h" -#include #include +#include #include #define private public @@ -12,10 +12,10 @@ #include #include #include +#include #include #include #include -#include #include #include #include @@ -27,14 +27,13 @@ using namespace crepe; using namespace testing; class TestScript : public Script { - bool oncollision(const CollisionEvent& test) { + bool oncollision(const CollisionEvent & test) { Log::logf("Box {} script on_collision()", test.info.this_collider.game_object_id); return true; } void init() { - subscribe([this](const CollisionEvent& ev) -> bool { - return this->oncollision(ev); - }); + subscribe( + [this](const CollisionEvent & ev) -> bool { return this->oncollision(ev); }); } void update() { // Retrieve component from the same GameObject this script is on @@ -52,10 +51,9 @@ public: const int average = 5; // Maximum duration to stop test const std::chrono::microseconds duration = 16000us; - ComponentManager mgr; - // Add system used for profling tests + // Add system used for profling tests CollisionSystem collision_sys{mgr}; PhysicsSystem physics_sys{mgr}; ParticleSystem particle_sys{mgr}; @@ -67,12 +65,11 @@ public: int game_object_count = 0; std::chrono::microseconds total_time = 0us; - void SetUp() override { - - GameObject do_not_use = mgr.new_object("DO_NOT_USE","",{0,0}); - do_not_use.add_component(Color::WHITE, ivec2{1080, 720}, - vec2{2000, 2000}, 1.0f); + + GameObject do_not_use = mgr.new_object("DO_NOT_USE", "", {0, 0}); + do_not_use.add_component(Color::WHITE, ivec2{1080, 720}, vec2{2000, 2000}, + 1.0f); // initialize systems here: //calls init script_sys.update(); @@ -82,11 +79,12 @@ public: // Helper function to time an update call and store its duration template - std::chrono::microseconds time_function(const std::string& name, Func&& func) { + std::chrono::microseconds time_function(const std::string & name, Func && func) { auto start = std::chrono::steady_clock::now(); func(); auto end = std::chrono::steady_clock::now(); - std::chrono::microseconds duration = std::chrono::duration_cast(end - start); + std::chrono::microseconds duration + = std::chrono::duration_cast(end - start); timings[name] += duration; return duration; } @@ -95,8 +93,10 @@ public: std::chrono::microseconds run_all_systems() { std::chrono::microseconds total_microseconds = 0us; 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("CollisionSystem", [&]() { collision_sys.update(); }); + total_microseconds + += time_function("ParticleSystem", [&]() { particle_sys.update(); }); total_microseconds += time_function("RenderSystem", [&]() { render_sys.update(); }); return total_microseconds; } @@ -104,34 +104,33 @@ public: // Print timings of all functions void log_timings() const { std::string result = "\nFunction timings:\n"; - - for (const auto& [name, duration] : timings) { - result += name + " took " + std::to_string(duration.count() / 1000.0 / average) + " ms (" + - std::to_string(duration.count() / average) + " µs).\n"; - } - - result += "Total time: " + std::to_string(this->total_time.count() / 1000.0 / average) + " ms (" + - std::to_string(this->total_time.count() / average) + " µs)\n"; - - result += "Amount of gameobjects: " + std::to_string(game_object_count) + "\n"; - - GTEST_LOG_(INFO) << result; + + for (const auto & [name, duration] : timings) { + result += name + " took " + std::to_string(duration.count() / 1000.0 / average) + + " ms (" + std::to_string(duration.count() / average) + " µs).\n"; + } + + result += "Total time: " + std::to_string(this->total_time.count() / 1000.0 / average) + + " ms (" + std::to_string(this->total_time.count() / average) + " µs)\n"; + + result += "Amount of gameobjects: " + std::to_string(game_object_count) + "\n"; + + GTEST_LOG_(INFO) << result; } void clear_timings() { - for (auto& [key, value] : timings) { - value = std::chrono::microseconds(0); + for (auto & [key, value] : timings) { + value = std::chrono::microseconds(0); } } }; TEST_F(Profiling, Profiling_1) { - while (this->total_time/this->average < this->duration) { - + while (this->total_time / this->average < this->duration) { { //define gameobject used for testing - GameObject gameobject = mgr.new_object("gameobject","",{0,0}); + GameObject gameobject = mgr.new_object("gameobject", "", {0, 0}); } this->game_object_count++; @@ -143,18 +142,19 @@ TEST_F(Profiling, Profiling_1) { this->total_time += run_all_systems(); } - if(this->game_object_count >= this->max_gameobject_count) break; + if (this->game_object_count >= this->max_gameobject_count) break; } log_timings(); EXPECT_GE(this->game_object_count, this->min_gameobject_count); } TEST_F(Profiling, Profiling_2) { - while (this->total_time/this->average < this->duration) { - + while (this->total_time / this->average < this->duration) { + { //define gameobject used for testing - GameObject gameobject = mgr.new_object("gameobject","",{static_cast(game_object_count*2),0}); + GameObject gameobject = mgr.new_object( + "gameobject", "", {static_cast(game_object_count * 2), 0}); gameobject.add_component(Rigidbody::Data{ .gravity_scale = 0.0, .body_type = Rigidbody::BodyType::STATIC, @@ -163,7 +163,8 @@ TEST_F(Profiling, Profiling_2) { gameobject.add_component().set_script(); Color color(0, 0, 0, 0); auto img = Texture("asset/texture/green_square.png"); - Sprite & test_sprite = gameobject.add_component(img, color, Sprite::FlipSettings{false, false}, 1, 1, 500); + Sprite & test_sprite = gameobject.add_component( + img, color, Sprite::FlipSettings{false, false}, 1, 1, 500); } this->game_object_count++; @@ -174,50 +175,52 @@ TEST_F(Profiling, Profiling_2) { this->total_time += run_all_systems(); } - if(this->game_object_count >= this->max_gameobject_count) break; + if (this->game_object_count >= this->max_gameobject_count) break; } log_timings(); EXPECT_GE(this->game_object_count, this->min_gameobject_count); } TEST_F(Profiling, Profiling_3) { - while (this->total_time/this->average < this->duration) { - + while (this->total_time / this->average < this->duration) { + { //define gameobject used for testing - GameObject gameobject = mgr.new_object("gameobject","",{static_cast(game_object_count*2),0}); + GameObject gameobject = mgr.new_object( + "gameobject", "", {static_cast(game_object_count * 2), 0}); gameobject.add_component(Rigidbody::Data{ - .gravity_scale = 0, - .body_type = Rigidbody::BodyType::STATIC, + .gravity_scale = 0, + .body_type = Rigidbody::BodyType::STATIC, }); gameobject.add_component(vec2{0, 0}, 1, 1); gameobject.add_component().set_script(); Color color(0, 0, 0, 0); auto img = Texture("asset/texture/green_square.png"); - Sprite & test_sprite = gameobject.add_component(img, color, Sprite::FlipSettings{false, false}, 1, 1, 500); + Sprite & test_sprite = gameobject.add_component( + img, color, Sprite::FlipSettings{false, false}, 1, 1, 500); auto & test = gameobject.add_component(ParticleEmitter::Data{ - .max_particles = 10, - .emission_rate = 100, - .end_lifespan = 100000, - .boundary{ - .width = 1000, - .height = 1000, - .offset = vec2{0, 0}, - .reset_on_exit = false, - }, - .sprite = test_sprite, - }); + .max_particles = 10, + .emission_rate = 100, + .end_lifespan = 100000, + .boundary{ + .width = 1000, + .height = 1000, + .offset = vec2{0, 0}, + .reset_on_exit = false, + }, + .sprite = test_sprite, + }); } render_sys.update(); this->game_object_count++; - + this->total_time = 0us; clear_timings(); for (int amount = 0; amount < this->average; amount++) { this->total_time += run_all_systems(); } - if(this->game_object_count >= this->max_gameobject_count) break; + if (this->game_object_count >= this->max_gameobject_count) break; } log_timings(); EXPECT_GE(this->game_object_count, this->min_gameobject_count); -- cgit v1.2.3 From 69634f05b00e0e01ab84ab14b6293c7a88c5fbe0 Mon Sep 17 00:00:00 2001 From: JAROWMR Date: Wed, 4 Dec 2024 20:48:38 +0100 Subject: added collision layers to example and unit test --- src/example/game.cpp | 14 ++++++++------ src/test/CollisionTest.cpp | 2 ++ 2 files changed, 10 insertions(+), 6 deletions(-) (limited to 'src/example/game.cpp') diff --git a/src/example/game.cpp b/src/example/game.cpp index 70c562e..a8d6d1b 100644 --- a/src/example/game.cpp +++ b/src/example/game.cpp @@ -44,12 +44,13 @@ public: //define playable world GameObject world = mgr.new_object( "Name", "Tag", vec2{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}, - .offset = {0, 0}}); + world.add_component(Rigidbody::Data{ + .mass = 0, + .gravity_scale = 0, + .body_type = Rigidbody::BodyType::STATIC, + .offset = {0, 0}, + .collision_layers = {0}, + }); world.add_component( vec2{0, 0 - (screen_size_height / 2 + world_collider / 2)}, vec2{world_collider, world_collider}); @@ -73,6 +74,7 @@ public: .constraints = {0, 0, 0}, .elastisity_coefficient = 1, .offset = {0, 0}, + .collision_layers = {0}, }); game_object1.add_component(vec2{0, 0}, vec2{20, 20}); game_object1.add_component().set_script(); diff --git a/src/test/CollisionTest.cpp b/src/test/CollisionTest.cpp index 74edaf7..3da04b5 100644 --- a/src/test/CollisionTest.cpp +++ b/src/test/CollisionTest.cpp @@ -78,6 +78,7 @@ public: .constraints = {0, 0, 0}, .elastisity_coefficient = 1, .offset = {0, 0}, + .collision_layers = {0}, }); game_object1.add_component(vec2{0, 0}, vec2{10, 10}); BehaviorScript & script_object1 @@ -93,6 +94,7 @@ public: .constraints = {0, 0, 0}, .elastisity_coefficient = 1, .offset = {0, 0}, + .collision_layers = {0}, }); game_object2.add_component(vec2{0, 0}, vec2{10, 10}); BehaviorScript & script_object2 -- cgit v1.2.3 From 453aeafda1503aeafa54b8f6e293936c1a3db5ea Mon Sep 17 00:00:00 2001 From: JAROWMR Date: Thu, 5 Dec 2024 22:15:38 +0100 Subject: dynamic and static bug fixes --- asset/texture/circle.png | Bin 0 -> 509 bytes asset/texture/green_square.png | Bin 135 -> 0 bytes asset/texture/red_square.png | Bin 135 -> 0 bytes asset/texture/square.png | Bin 0 -> 162 bytes src/crepe/system/CollisionSystem.cpp | 15 ++-- src/crepe/system/CollisionSystem.h | 5 +- src/example/game.cpp | 143 +++++++++++++++++++++++++++++++++-- 7 files changed, 147 insertions(+), 16 deletions(-) create mode 100755 asset/texture/circle.png delete mode 100755 asset/texture/green_square.png delete mode 100755 asset/texture/red_square.png create mode 100755 asset/texture/square.png (limited to 'src/example/game.cpp') diff --git a/asset/texture/circle.png b/asset/texture/circle.png new file mode 100755 index 0000000..0a92ac7 Binary files /dev/null and b/asset/texture/circle.png differ diff --git a/asset/texture/green_square.png b/asset/texture/green_square.png deleted file mode 100755 index 7772c87..0000000 Binary files a/asset/texture/green_square.png and /dev/null differ diff --git a/asset/texture/red_square.png b/asset/texture/red_square.png deleted file mode 100755 index 6ffbbec..0000000 Binary files a/asset/texture/red_square.png and /dev/null differ diff --git a/asset/texture/square.png b/asset/texture/square.png new file mode 100755 index 0000000..d07ec98 Binary files /dev/null and b/asset/texture/square.png differ diff --git a/src/crepe/system/CollisionSystem.cpp b/src/crepe/system/CollisionSystem.cpp index 86eafc0..f75d0ad 100644 --- a/src/crepe/system/CollisionSystem.cpp +++ b/src/crepe/system/CollisionSystem.cpp @@ -159,7 +159,7 @@ CollisionSystem::collision_handler(CollisionInternal & data1, CollisionInternal vec2 collider_pos2 = this->get_current_position(collider2.offset, data2.transform, data2.rigidbody); resolution = this->get_circle_box_resolution(collider2, collider1, collider_pos2, - collider_pos1); + collider_pos1,true); break; } case CollisionInternalType::CIRCLE_CIRCLE: { @@ -185,7 +185,7 @@ CollisionSystem::collision_handler(CollisionInternal & data1, CollisionInternal vec2 collider_pos2 = this->get_current_position(collider2.offset, data2.transform, data2.rigidbody); resolution = this->get_circle_box_resolution(collider1, collider2, collider_pos1, - collider_pos2); + collider_pos2,false); break; } } @@ -261,9 +261,10 @@ vec2 CollisionSystem::get_circle_circle_resolution(const CircleCollider & circle // Normalize the delta vector to get the collision direction vec2 collision_normal = delta / distance; + // Compute the resolution vector - vec2 resolution = collision_normal * penetration_depth; + vec2 resolution = -collision_normal * penetration_depth; return resolution; } @@ -271,7 +272,7 @@ vec2 CollisionSystem::get_circle_circle_resolution(const CircleCollider & circle vec2 CollisionSystem::get_circle_box_resolution(const CircleCollider & circle_collider, const BoxCollider & box_collider, const vec2 & circle_position, - const vec2 & box_position) const { + const vec2 & box_position,bool inverse) const { vec2 delta = circle_position - box_position; // Compute half-dimensions of the box @@ -293,7 +294,7 @@ vec2 CollisionSystem::get_circle_box_resolution(const CircleCollider & circle_co // Compute penetration depth float penetration_depth = circle_collider.radius - distance; - + if(inverse) collision_normal = -collision_normal; // Compute the resolution vector vec2 resolution = collision_normal * penetration_depth; @@ -511,7 +512,7 @@ bool CollisionSystem::get_box_circle_collision(const BoxCollider & box1, float distance_squared = distance_x * distance_x + distance_y * distance_y; // Compare distance squared with the square of the circle's radius - return distance_squared <= circle2.radius * circle2.radius; + return distance_squared <= circle2.radius * circle2.radius-1; } bool CollisionSystem::get_circle_circle_collision(const CircleCollider & circle1, @@ -532,7 +533,7 @@ bool CollisionSystem::get_circle_circle_collision(const CircleCollider & circle1 float radius_sum = circle1.radius + circle2.radius; // Check if the distance between the centers is less than or equal to the sum of the radii - return distance_squared <= radius_sum * radius_sum; + return distance_squared <= radius_sum * radius_sum - 1; } vec2 CollisionSystem::get_current_position(const vec2 & collider_offset, diff --git a/src/crepe/system/CollisionSystem.h b/src/crepe/system/CollisionSystem.h index 6995bb5..b978dbb 100644 --- a/src/crepe/system/CollisionSystem.h +++ b/src/crepe/system/CollisionSystem.h @@ -177,13 +177,14 @@ private: * \param circle_collider The first CircleCollider. * \param box_collider The second CircleCollider. * \param circle_position The position of the CircleCollider. - * \param box_position The position of the BocCollider. + * \param box_position The position of the BoxCollider. + * \param inverse Inverted true if box circle collision, false if circle box collision (inverts the direction). * \return The resolution vector for the collision. */ vec2 get_circle_box_resolution(const CircleCollider & circle_collider, const BoxCollider & box_collider, const vec2 & circle_position, - const vec2 & box_position) const; + const vec2 & box_position,bool inverse) const; /** * \brief Determines the appropriate collision handler for a collision. diff --git a/src/example/game.cpp b/src/example/game.cpp index ade90c9..be756bd 100644 --- a/src/example/game.cpp +++ b/src/example/game.cpp @@ -1,3 +1,4 @@ +#include "api/CircleCollider.h" #include "manager/ComponentManager.h" #include "api/Scene.h" #include "manager/Mediator.h" @@ -18,7 +19,8 @@ using namespace crepe; using namespace std; -class MyScript : public Script { +class MyScript1 : public Script { + bool flip = false; bool oncollision(const CollisionEvent & test) { Log::logf("Box {} script on_collision()", test.info.this_collider.game_object_id); return true; @@ -50,6 +52,98 @@ class MyScript : public Script { tf.position.x += 1; break; } + case Keycode::E: + { + if(flip){ + flip = false; + this->get_component().active = true; + this->get_components()[0].get().active = true; + this->get_component().active = false; + this->get_components()[1].get().active = false; + } + else { + flip = true; + this->get_component().active = false; + this->get_components()[0].get().active = false; + this->get_component().active = true; + this->get_components()[1].get().active = true; + } + + + //add collider switch + break; + } + default: + break; + } + return false; + } + + void init() { + Log::logf("init"); + subscribe([this](const CollisionEvent & ev) -> bool { return this->oncollision(ev); }); + subscribe([this](const KeyPressEvent & ev) -> bool { return this->keypressed(ev); }); + } + void update() { + // Retrieve component from the same GameObject this script is on + } + +}; + +class MyScript2 : public Script { + bool flip = false; + bool oncollision(const CollisionEvent & test) { + Log::logf("Box {} script on_collision()", test.info.this_collider.game_object_id); + return true; + } + bool keypressed(const KeyPressEvent & test) { + Log::logf("Box script keypressed()"); + switch (test.key) { + case Keycode::LEFT: + { + Transform & tf = this->get_component(); + tf.position.x -= 1; + break; + } + case Keycode::UP: + { + Transform & tf = this->get_component(); + tf.position.y -= 1; + break; + } + case Keycode::DOWN: + { + Transform & tf = this->get_component(); + tf.position.y += 1; + break; + } + case Keycode::RIGHT: + { + Transform & tf = this->get_component(); + tf.position.x += 1; + break; + } + case Keycode::PAUSE: + { + if(flip){ + flip = false; + this->get_component().active = true; + this->get_components()[0].get().active = true; + this->get_component().active = false; + this->get_components()[1].get().active = false; + } + else { + flip = true; + this->get_component().active = false; + this->get_components()[0].get().active = false; + this->get_component().active = true; + this->get_components()[1].get().active = true; + } + + + //add collider switch + break; + } default: break; } @@ -77,8 +171,8 @@ public: ComponentManager & mgr = m.component_manager; Color color(0, 0, 0, 255); - float screen_size_width = 640; - float screen_size_height = 480; + float screen_size_width = 320; + float screen_size_height = 240; float world_collider = 1000; //define playable world GameObject world = mgr.new_object( @@ -101,7 +195,7 @@ public: vec2{world_collider, world_collider}); // Left world.add_component(vec2{screen_size_width / 2 + world_collider / 2, 0}, vec2{world_collider, world_collider}); // right - world.add_component(Color::WHITE, ivec2{640, 480}, vec2{640, 480}, 1.0f); + world.add_component(Color::WHITE, ivec2{static_cast(screen_size_width), static_cast(screen_size_height)}, vec2{screen_size_width, screen_size_height}, 1.0f); GameObject game_object1 = mgr.new_object( "Name", "Tag", vec2{screen_size_width / 2, screen_size_height / 2}, 0, 1); @@ -115,11 +209,46 @@ public: .offset = {0, 0}, .collision_layers = {0}, }); + // add box with boxcollider game_object1.add_component(vec2{0, 0}, vec2{20, 20}); - game_object1.add_component().set_script(); - auto img = Texture("asset/texture/green_square.png"); - game_object1.add_component(img, color, Sprite::FlipSettings{false, false}, 1, + game_object1.add_component().set_script(); + auto img1 = Texture("asset/texture/square.png"); + game_object1.add_component(img1, color, Sprite::FlipSettings{false, false}, 1, 1, 20); + + //add circle with cirlcecollider deactiveated + game_object1.add_component(vec2{0, 0}, 10).active = false; + auto img2 = Texture("asset/texture/circle.png"); + game_object1.add_component(img2, color, Sprite::FlipSettings{false, false}, 1, + 1, 20).active = false; + + + + GameObject game_object2 = mgr.new_object( + "Name", "Tag", vec2{screen_size_width / 2, screen_size_height / 2}, 0, 1); + game_object2.add_component(Rigidbody::Data{ + .mass = 1, + .gravity_scale = 0, + .body_type = Rigidbody::BodyType::STATIC, + .linear_velocity = {0, 0}, + .constraints = {0, 0, 0}, + .elastisity_coefficient = 1, + .offset = {0, 0}, + .collision_layers = {0}, + }); + // add box with boxcollider + game_object2.add_component(vec2{0, 0}, vec2{20, 20}); + game_object2.add_component().set_script(); + auto img3 = Texture("asset/texture/square.png"); + game_object2.add_component(img3, color, Sprite::FlipSettings{false, false}, 1, + 1, 20); + + //add circle with cirlcecollider deactiveated + game_object2.add_component(vec2{0, 0}, 10).active = false; + auto img4 = Texture("asset/texture/circle.png"); + game_object2.add_component(img4, color, Sprite::FlipSettings{false, false}, 1, + 1, 20).active = false; + } string get_name() const { return "scene1"; } -- cgit v1.2.3