diff options
-rw-r--r-- | src/crepe/system/CollisionSystem.cpp | 97 | ||||
-rw-r--r-- | src/crepe/system/CollisionSystem.h | 37 | ||||
-rw-r--r-- | src/example/collision.cpp | 33 |
3 files changed, 124 insertions, 43 deletions
diff --git a/src/crepe/system/CollisionSystem.cpp b/src/crepe/system/CollisionSystem.cpp index d59539e..4b74e67 100644 --- a/src/crepe/system/CollisionSystem.cpp +++ b/src/crepe/system/CollisionSystem.cpp @@ -28,7 +28,7 @@ void CollisionSystem::update() { std::vector<std::reference_wrapper<CircleCollider>> circlecolliders = mgr.get_components_by_type<CircleCollider>(); std::vector<std::pair<CollidedInfoStor,CollidedInfoStor>> collided = check_collisions(boxcolliders,circlecolliders); // std::cout << "DEBUG INFO" << std::endl; - for (const auto& collision_pair : collided) { + for (auto& collision_pair : collided) { call_collision_handler(collision_pair.first,collision_pair.second); // First collider call_collision_handler(collision_pair.second,collision_pair.first); // First collider } @@ -38,9 +38,14 @@ void CollisionSystem::update() { } } -void CollisionSystem::call_collision_handler(const CollidedInfoStor& data1,const CollidedInfoStor& data2){ +void CollisionSystem::call_collision_handler(CollidedInfoStor& data1,CollidedInfoStor& data2){ const Collider* collider1 = nullptr; const Collider* collider2 = nullptr; + double height1 = 0,width1 = 0; + double height2 = 0,width2 = 0; + Vector2 final_position1; + Vector2 final_position2; + Vector2 temp; // Check collision type and get values for handler game_object_id_t first = 0,second = 0; if (std::holds_alternative<BoxCollider>(data1.collider)) { @@ -51,6 +56,38 @@ void CollisionSystem::call_collision_handler(const CollidedInfoStor& data1,const collider2 = &box_collider2; first = box_collider1.game_object_id; second = box_collider2.game_object_id; + height1 = box_collider1.height; + height2 = box_collider2.height; + width1 = box_collider1.width; + width2 = box_collider2.width; + final_position1 = current_position(box_collider1,data1.transform,data1.rigidbody); + final_position2 = current_position(box_collider2,data2.transform,data2.rigidbody); + + Vector2 delta = final_position2 - final_position1; + + double half_width1 = width1 / 2.0; + double half_height1 = height1 / 2.0; + double half_width2 = width2 / 2.0; + double half_height2 = height2 / 2.0; + + // Compute overlap in X and Y directions + double overlap_x = (half_width1 + half_width2) - std::abs(delta.x); + double overlap_y = (half_height1 + half_height2) - std::abs(delta.y); + + // Check if there is actually a collision + if (overlap_x > 0 && overlap_y > 0) { + // Resolve in the smallest overlap direction + if (overlap_x < overlap_y) { + // Resolve along X-axis + temp = {delta.x > 0 ? -overlap_x : overlap_x, 0}; + } else { + // Resolve along Y-axis + temp = {0, delta.y > 0 ? -overlap_y : overlap_y}; + } + } + + + } else { const BoxCollider& box_collider = std::get<BoxCollider>(data1.collider); @@ -59,6 +96,10 @@ void CollisionSystem::call_collision_handler(const CollidedInfoStor& data1,const collider2 = &circle_collider; first = box_collider.game_object_id; second = circle_collider.game_object_id; + height1 = box_collider.height; + height2 = circle_collider.radius + circle_collider.radius; + width1 = box_collider.width; + width2 = circle_collider.radius + circle_collider.radius; } } else { @@ -69,6 +110,10 @@ void CollisionSystem::call_collision_handler(const CollidedInfoStor& data1,const collider2 = &circle_collider2; first = circle_collider1.game_object_id; second = circle_collider2.game_object_id; + height1 = circle_collider1.radius + circle_collider1.radius; + height2 = circle_collider2.radius + circle_collider2.radius; + width1 = circle_collider1.radius + circle_collider1.radius; + width2 = circle_collider2.radius + circle_collider2.radius; } else { const CircleCollider& circle_collider = std::get<CircleCollider>(data1.collider); @@ -77,8 +122,17 @@ void CollisionSystem::call_collision_handler(const CollidedInfoStor& data1,const collider2 = &box_collider; first = circle_collider.game_object_id; second = box_collider.game_object_id; + height1 = circle_collider.radius + circle_collider.radius; + height2 = box_collider.height; + width1 = circle_collider.radius + circle_collider.radius; + width2 = box_collider.width; } } + crepe::CollisionSystem::CollisionInfo collision_info{ + .first={ *collider1, data1.transform, data1.rigidbody }, + .second={ *collider2, data2.transform, data2.rigidbody }, + .move_back_value = temp, + }; // check rigidbody type if(data1.rigidbody.data.body_type != Rigidbody::BodyType::STATIC) @@ -86,17 +140,21 @@ void CollisionSystem::call_collision_handler(const CollidedInfoStor& data1,const // If second body is static move back if(data2.rigidbody.data.body_type == Rigidbody::BodyType::STATIC){ //call static handler (is bounce true?) + static_collision_handler(collision_info); }; - crepe::CollisionSystem::CollisionInfo collision_info{ - { *collider1, data1.transform, data1.rigidbody }, - { *collider2, data2.transform, data2.rigidbody } - }; + CollisionEvent data(collision_info); EventManager::get_instance().trigger_event<CollisionEvent>(data, first); } } +void CollisionSystem::static_collision_handler(CollisionInfo& info){ + std::cout << "INFO: x:" << info.first.transform.position.x << "y:" << info.first.transform.position.y << std::endl; + info.first.transform.position += info.move_back_value; + info.first.rigidbody.data.linear_velocity = {0,0}; +} + std::vector<std::pair<CollisionSystem::CollidedInfoStor,CollisionSystem::CollidedInfoStor>> CollisionSystem::check_collisions(const std::vector<std::reference_wrapper<BoxCollider>>& boxcolliders, const std::vector<std::reference_wrapper<CircleCollider>>& circlecolliders) { ComponentManager & mgr = ComponentManager::get_instance(); std::vector<std::pair<CollidedInfoStor,CollidedInfoStor>> collisions_ret; @@ -202,12 +260,12 @@ bool CollisionSystem::check_box_box_collision(const BoxCollider& box1, const Box Vector2 final_position2 = current_position(box2,transform2,rigidbody2); // Log final positions for debugging purposes - // std::cout << "Final Position of Box 1: (" << final_position1.x << ", " << final_position1.y << ")" << std::endl; - // std::cout << "Final Position of Box 2: (" << final_position2.x << ", " << final_position2.y << ")" << std::endl; + std::cout << "Final Position of Box 1: (" << final_position1.x << ", " << final_position1.y << ")" << std::endl; + std::cout << "Final Position of Box 2: (" << final_position2.x << ", " << final_position2.y << ")" << std::endl; // Log rotation values for debugging - // std::cout << "Rotation of Box 1: " << transform1.rotation << " degrees" << std::endl; - // std::cout << "Rotation of Box 2: " << transform2.rotation << " degrees" << std::endl; + std::cout << "Rotation of Box 1: " << transform1.rotation << " degrees" << std::endl; + std::cout << "Rotation of Box 2: " << transform2.rotation << " degrees" << std::endl; // Calculate half-extents (half width and half height) @@ -216,11 +274,22 @@ bool CollisionSystem::check_box_box_collision(const BoxCollider& box1, const Box double half_width2 = box2.width / 2.0; double half_height2 = box2.height / 2.0; + std::cout << "half_width of Box 1: " << half_width1 << std::endl; + std::cout << "half_height of Box 2: " << half_height1 << std::endl; + std::cout << "half_width of Box 1: " << half_width2 << std::endl; + std::cout << "half_height of Box 2: " << half_height2 << std::endl; + + + std::cout << "final_position1.x + half_width1 < final_position2.x - half_width2 " << (final_position1.x + half_width1 < final_position2.x - half_width2) << std::endl; + std::cout << "final_position1.x - half_width1 > final_position2.x + half_width2 " << (final_position1.x - half_width1 > final_position2.x + half_width2) << std::endl; + std::cout << "final_position1.y + half_height1 < final_position2.y - half_height2 " << (final_position1.y + half_height1 < final_position2.y - half_height2) << std::endl; + std::cout << "final_position1.y - half_height1 > final_position2.y + half_height2 " << (final_position1.y - half_height1 > final_position2.y + half_height2) << std::endl; + // Check if the boxes overlap along the X and Y axes - return !(final_position1.x + half_width1 < final_position2.x - half_width2 || // box1 is left of box2 - final_position1.x - half_width1 > final_position2.x + half_width2 || // box1 is right of box2 - final_position1.y + half_height1 < final_position2.y - half_height2 || // box1 is above box2 - final_position1.y - half_height1 > final_position2.y + half_height2); // box1 is below box2 + return !(final_position1.x + half_width1 <= final_position2.x - half_width2 || // box1 is left of box2 + final_position1.x - half_width1 >= final_position2.x + half_width2 || // box1 is right of box2 + final_position1.y + half_height1 <= final_position2.y - half_height2 || // box1 is above box2 + final_position1.y - half_height1 >= final_position2.y + half_height2); // box1 is below box2 } bool CollisionSystem::check_box_circle_collision(const BoxCollider& box1, const CircleCollider& circle2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2) { diff --git a/src/crepe/system/CollisionSystem.h b/src/crepe/system/CollisionSystem.h index a31ac48..cfa599e 100644 --- a/src/crepe/system/CollisionSystem.h +++ b/src/crepe/system/CollisionSystem.h @@ -5,6 +5,7 @@ #include "api/Transform.h" #include "api/BoxCollider.h" #include "api/CircleCollider.h" +#include "api/Vector2.h" #include <tuple> #include <vector> #include <variant> @@ -19,29 +20,35 @@ private: struct CollidedInfoStor { //! Store either BoxCollider or CircleCollider collider_stor collider; - Transform transform; - Rigidbody rigidbody; // Rigidbody data + Transform& transform; + Rigidbody& rigidbody; // Rigidbody data }; public: - CollisionSystem(); - void update(); -private: - void call_collision_handler(const CollidedInfoStor& data1,const CollidedInfoStor& data2); - std::vector<std::pair<CollidedInfoStor,CollidedInfoStor>> check_collisions(const std::vector<std::reference_wrapper<BoxCollider>>& boxcolliders, const std::vector<std::reference_wrapper<CircleCollider>>& circlecolliders); - bool check_box_box_collision(const BoxCollider& box1, const BoxCollider& box2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2); - bool check_box_circle_collision(const BoxCollider& box1, const CircleCollider& circle2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2); - bool check_circle_circle_collision(const CircleCollider& circle1, const CircleCollider& circle2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2); - Vector2 current_position(const Collider& collider, const Transform& transform, const Rigidbody& rigidbody); -public: struct ColliderInfo { - Collider collider; - Transform transform; - Rigidbody rigidbody; + const Collider& collider; + Transform& transform; + Rigidbody& rigidbody; }; struct CollisionInfo{ ColliderInfo first; ColliderInfo second; + Vector2 move_back_value; }; +public: + CollisionSystem(); + void update(); +private: //handling + void call_collision_handler(CollidedInfoStor& data1,CollidedInfoStor& data2); + void static_collision_handler(CollisionInfo& info); +private: //detection + + std::vector<std::pair<CollidedInfoStor,CollidedInfoStor>> check_collisions(const std::vector<std::reference_wrapper<BoxCollider>>& boxcolliders, const std::vector<std::reference_wrapper<CircleCollider>>& circlecolliders); + bool check_box_box_collision(const BoxCollider& box1, const BoxCollider& box2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2); + bool check_box_circle_collision(const BoxCollider& box1, const CircleCollider& circle2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2); + bool check_circle_circle_collision(const CircleCollider& circle1, const CircleCollider& circle2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2); + Vector2 current_position(const Collider& collider, const Transform& transform, const Rigidbody& rigidbody); + + }; } // namespace crepe diff --git a/src/example/collision.cpp b/src/example/collision.cpp index a1b22f0..a5cec83 100644 --- a/src/example/collision.cpp +++ b/src/example/collision.cpp @@ -49,8 +49,11 @@ int main(int argc, char * argv[]) { LoopManager gameloop; Color color(0, 0, 0, 0); + double screen_size_width = 1280; + double screen_size_height = 960; + double world_collider = 1000; //define playable world - GameObject World(0, "Name", "Tag", Vector2{0, 0}, 0, 1); + GameObject World(0, "Name", "Tag", Vector2{screen_size_width/2, screen_size_height/2}, 0, 1); World.add_component<Rigidbody>(Rigidbody::Data{ .mass = 0, .gravity_scale = 0, @@ -58,46 +61,48 @@ int main(int argc, char * argv[]) { .constraints = {0, 0, 0}, .use_gravity = false, .bounce = false, - .offset = {320,240} + .offset = {0,0} }); - World.add_component<BoxCollider>(Vector2{0, -740}, 1000, 1000); // Top - World.add_component<BoxCollider>(Vector2{0, 740}, 1000, 1000); // Bottom - World.add_component<BoxCollider>(Vector2{-820, 0}, 1000, 1000); // Left - World.add_component<BoxCollider>(Vector2{820, 0}, 1000, 1000); // right + // World.add_component<BoxCollider>(Vector2{0, -740}, 1000, 1000); // Top + World.add_component<BoxCollider>(Vector2{0, screen_size_height/2+world_collider/2}, world_collider, world_collider); // Bottom + // World.add_component<BoxCollider>(Vector2{-820, 0}, 1000, 1000); // Left + // World.add_component<BoxCollider>(Vector2{820, 0}, 1000, 1000); // right - GameObject game_object1(1, "Name", "Tag", Vector2{320, 240}, 0, 1); + GameObject game_object1(1, "Name", "Tag", Vector2{screen_size_width/2, screen_size_height/2}, 0, 1); game_object1.add_component<Rigidbody>(Rigidbody::Data{ .mass = 1, .gravity_scale = 1, .body_type = Rigidbody::BodyType::DYNAMIC, + .linear_velocity = {0,1}, .constraints = {0, 0, 0}, .use_gravity = false, .bounce = false, - .offset = {0,0} + .offset = {0,0}, }); - game_object1.add_component<BoxCollider>(Vector2{5, 5}, 5, 5); + game_object1.add_component<BoxCollider>(Vector2{0, 0}, 40, 40); game_object1.add_component<BehaviorScript>().set_script<MyScript>(); game_object1.add_component<Sprite>( - make_shared<Texture>("/home/jaro/crepe/asset/texture/img.png"), color, + make_shared<Texture>("/home/jaro/crepe/asset/texture/green_square.png"), color, FlipSettings{true, true}); game_object1.add_component<Camera>(Color::get_white()); - // GameObject game_object2(2, "Name", "Tag", Vector2{10, 10}, 0, 1); + // GameObject game_object2(2, "Name", "Tag", Vector2{screen_size_width/2, screen_size_height/2+100}, 0, 1); // game_object2.add_component<Rigidbody>(Rigidbody::Data{ // .mass = 1, // .gravity_scale = 1, // .body_type = Rigidbody::BodyType::DYNAMIC, + // .linear_velocity = {0,0}, // .constraints = {0, 0, 0}, // .use_gravity = false, // .bounce = false, - // .offset = {0,0} + // .offset = {0,0}, // }); - // game_object2.add_component<BoxCollider>(Vector2{5, 5}, 5, 5); + // game_object2.add_component<BoxCollider>(Vector2{0, 0}, 40, 40); // game_object2.add_component<BehaviorScript>().set_script<MyScript>(); // game_object2.add_component<Sprite>( - // make_shared<Texture>("/home/jaro/crepe/asset/texture/img.png"), color, + // make_shared<Texture>("/home/jaro/crepe/asset/texture/red_square.png"), color, // FlipSettings{true, true}); |