diff options
Diffstat (limited to 'src/crepe')
-rw-r--r-- | src/crepe/Collider.cpp | 2 | ||||
-rw-r--r-- | src/crepe/Collider.h | 6 | ||||
-rw-r--r-- | src/crepe/api/BoxCollider.cpp | 7 | ||||
-rw-r--r-- | src/crepe/api/BoxCollider.h | 15 | ||||
-rw-r--r-- | src/crepe/api/CMakeLists.txt | 10 | ||||
-rw-r--r-- | src/crepe/api/CircleCollider.cpp | 6 | ||||
-rw-r--r-- | src/crepe/api/CircleCollider.h | 8 | ||||
-rw-r--r-- | src/crepe/api/Rigidbody.h | 2 | ||||
-rw-r--r-- | src/crepe/api/Vector2.cpp | 4 | ||||
-rw-r--r-- | src/crepe/api/Vector2.h | 3 | ||||
-rw-r--r-- | src/crepe/system/CollisionSystem.cpp | 275 | ||||
-rw-r--r-- | src/crepe/system/CollisionSystem.h | 25 |
12 files changed, 358 insertions, 5 deletions
diff --git a/src/crepe/Collider.cpp b/src/crepe/Collider.cpp index bbec488..0706371 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) : Component(id) {} +Collider::Collider(game_object_id_t id, Vector2 offset) : Component(id), offset(offset) {} diff --git a/src/crepe/Collider.h b/src/crepe/Collider.h index 827f83d..54695b1 100644 --- a/src/crepe/Collider.h +++ b/src/crepe/Collider.h @@ -1,14 +1,14 @@ #pragma once #include "Component.h" +#include "api/Vector2.h" namespace crepe { class Collider : public Component { public: - Collider(game_object_id_t id); - - int size; + Collider(game_object_id_t id, Vector2 offset); + Vector2 offset; }; } // namespace crepe diff --git a/src/crepe/api/BoxCollider.cpp b/src/crepe/api/BoxCollider.cpp new file mode 100644 index 0000000..eafbdb2 --- /dev/null +++ b/src/crepe/api/BoxCollider.cpp @@ -0,0 +1,7 @@ +#include "BoxCollider.h" +#include "../Collider.h" + +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) {} diff --git a/src/crepe/api/BoxCollider.h b/src/crepe/api/BoxCollider.h new file mode 100644 index 0000000..357c979 --- /dev/null +++ b/src/crepe/api/BoxCollider.h @@ -0,0 +1,15 @@ +#pragma once + +#include "Vector2.h" +#include "../Collider.h" + +namespace crepe { + +class BoxCollider : public Collider { +public: + BoxCollider(game_object_id_t game_object_id,Vector2 offset, double width, double height); + double width; + double height; +}; + +} // namespace crepe diff --git a/src/crepe/api/CMakeLists.txt b/src/crepe/api/CMakeLists.txt index 85696c4..de1b4b3 100644 --- a/src/crepe/api/CMakeLists.txt +++ b/src/crepe/api/CMakeLists.txt @@ -18,8 +18,13 @@ target_sources(crepe PUBLIC Vector2.cpp Camera.cpp Animator.cpp +<<<<<<< HEAD + BoxCollider.cpp + CircleCollider.cpp +======= LoopManager.cpp LoopTimer.cpp +>>>>>>> be1e97bc7a494963ab1567492fafcda99e36f683 ) target_sources(crepe PUBLIC FILE_SET HEADERS FILES @@ -44,6 +49,11 @@ target_sources(crepe PUBLIC FILE_SET HEADERS FILES SceneManager.hpp Camera.h Animator.h +<<<<<<< HEAD + BoxCollider.h + CircleCollider.h +======= LoopManager.h LoopTimer.h +>>>>>>> be1e97bc7a494963ab1567492fafcda99e36f683 ) diff --git a/src/crepe/api/CircleCollider.cpp b/src/crepe/api/CircleCollider.cpp new file mode 100644 index 0000000..04a4995 --- /dev/null +++ b/src/crepe/api/CircleCollider.cpp @@ -0,0 +1,6 @@ +#include "CircleCollider.h" + +using namespace crepe; + + +CircleCollider::CircleCollider(game_object_id_t game_object_id,Vector2 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 e77a592..e4f0452 100644 --- a/src/crepe/api/CircleCollider.h +++ b/src/crepe/api/CircleCollider.h @@ -1,14 +1,22 @@ #pragma once + +#include "Vector2.h" + #include "../Collider.h" namespace crepe { class CircleCollider : public Collider { public: +<<<<<<< HEAD + CircleCollider(game_object_id_t game_object_id,Vector2 offset, int radius); + double radius; +======= CircleCollider(game_object_id_t game_object_id, int radius) : Collider(game_object_id), radius(radius) {} int radius; +>>>>>>> be1e97bc7a494963ab1567492fafcda99e36f683 }; } // namespace crepe diff --git a/src/crepe/api/Rigidbody.h b/src/crepe/api/Rigidbody.h index 68481f4..b9edec2 100644 --- a/src/crepe/api/Rigidbody.h +++ b/src/crepe/api/Rigidbody.h @@ -75,6 +75,8 @@ public: bool use_gravity = true; //! if object bounces bool bounce = false; + //! offset of all colliders + Vector2 offset; }; public: diff --git a/src/crepe/api/Vector2.cpp b/src/crepe/api/Vector2.cpp index 09b3fa3..947c49e 100644 --- a/src/crepe/api/Vector2.cpp +++ b/src/crepe/api/Vector2.cpp @@ -54,4 +54,8 @@ bool Vector2::operator!=(const Vector2 & other) const { return !(*this == other); } +double Vector2::dot(const Vector2& other) const { + return this->x * other.x + this->y * other.y; +} + } // namespace crepe diff --git a/src/crepe/api/Vector2.h b/src/crepe/api/Vector2.h index 5a57484..90d9d57 100644 --- a/src/crepe/api/Vector2.h +++ b/src/crepe/api/Vector2.h @@ -42,6 +42,9 @@ public: //! Checks if this vector is not equal to another vector. bool operator!=(const Vector2 & other) const; + + //! + double dot(const Vector2& other) const; }; } // namespace crepe diff --git a/src/crepe/system/CollisionSystem.cpp b/src/crepe/system/CollisionSystem.cpp index 55e0fdc..ac35026 100644 --- a/src/crepe/system/CollisionSystem.cpp +++ b/src/crepe/system/CollisionSystem.cpp @@ -1,7 +1,280 @@ +#include <cmath> +#include <algorithm> +#include <cstddef> +#include <tuple> +#include <utility> +#include <variant> + #include "CollisionSystem.h" +#include "../ComponentManager.h" +#include "../api/BoxCollider.h" +#include "../api/CircleCollider.h" +#include "../api/Vector2.h" +#include "../api/Rigidbody.h" +#include "../api/Transform.h" + +#include "Collider.h" +#include "iostream" + using namespace crepe; CollisionSystem::CollisionSystem() {} -void CollisionSystem::update() {} +void CollisionSystem::update() { + ComponentManager & mgr = ComponentManager::get_instance(); + std::vector<std::reference_wrapper<BoxCollider>> boxcolliders = mgr.get_components_by_type<BoxCollider>(); + 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) { + call_collision_handler(collision_pair.first,collision_pair.second); // First collider + call_collision_handler(collision_pair.second,collision_pair.first); // First collider + } + + if(collided.empty()) { + std::cout << "No objects collided" << std::endl; + } +} + +void CollisionSystem::call_collision_handler(const CollidedInfoStor& data1,const CollidedInfoStor& data2){ + + // Check collision type and get values for handler + game_object_id_t first = 0,second = 0; + if (std::holds_alternative<BoxCollider>(data1.collider)) { + if (std::holds_alternative<BoxCollider>(data2.collider)) { + const BoxCollider& box_collider1 = std::get<BoxCollider>(data1.collider); + const BoxCollider& box_collider2 = std::get<BoxCollider>(data2.collider); + first = box_collider1.game_object_id; + second = box_collider2.game_object_id; + } + else { + const BoxCollider& box_collider = std::get<BoxCollider>(data1.collider); + const CircleCollider& circle_collider = std::get<CircleCollider>(data2.collider); + first = box_collider.game_object_id; + second = circle_collider.game_object_id; + } + } + else { + if (std::holds_alternative<CircleCollider>(data2.collider)) { + const CircleCollider& circle_collider1 = std::get<CircleCollider>(data1.collider); + const CircleCollider& circle_collider2 = std::get<CircleCollider>(data2.collider); + first = circle_collider1.game_object_id; + second = circle_collider2.game_object_id; + } + else { + const CircleCollider& circle_collider = std::get<CircleCollider>(data1.collider); + const BoxCollider& box_collider = std::get<BoxCollider>(data2.collider); + first = circle_collider.game_object_id; + second = box_collider.game_object_id; + } + } + + // check rigidbody type + if(data1.rigidbody.data.body_type != Rigidbody::BodyType::STATIC) + { + // If second body is static move back + if(data2.rigidbody.data.body_type == Rigidbody::BodyType::STATIC) return; + //call static handler (is bounce true?) + + // call script handler + } +} + +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; + //if no colliders skip + //check if colliders has rigibocdy if not skip + + //if amount is higer than lets say 16 for now use quadtree otwerwise skip + //quadtree code + //quadtree is placed over the input vector + + // Check collisions + for (size_t i = 0; i < boxcolliders.size(); ++i) { + // Fetch components for the first box collider + if(!boxcolliders[i].get().active) continue; + int game_object_id_1 = boxcolliders[i].get().game_object_id; + Transform& transform1 = mgr.get_components_by_id<Transform>(game_object_id_1).front().get(); + if(!transform1.active) continue; + Rigidbody& rigidbody1 = mgr.get_components_by_id<Rigidbody>(game_object_id_1).front().get(); + if(!rigidbody1.active) continue; + + // Check CircleCollider vs CircleCollider + 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<Transform>(boxcolliders[j].get().game_object_id).front().get(); + if(!transform2.active) continue; + Rigidbody & rigidbody2 = mgr.get_components_by_id<Rigidbody>(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], transform1, rigidbody1}, + CollidedInfoStor{boxcolliders[j], transform2, rigidbody2} + )); + } + } + + // 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<Transform>(circlecolliders[j].get().game_object_id).front().get(); + if(!transform2.active) continue; + Rigidbody & rigidbody2 = mgr.get_components_by_id<Rigidbody>(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], transform1, rigidbody1}, + CollidedInfoStor{circlecolliders[j], transform2, rigidbody2} + )); + } + } + } + // 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<Transform>(circlecolliders[i].get().game_object_id).front().get(); + if(!transform1.active) continue; + Rigidbody & rigidbody1 = mgr.get_components_by_id<Rigidbody>(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<Transform>(circlecolliders[j].get().game_object_id).front().get(); + if(!transform2.active) continue; + Rigidbody & rigidbody2 = mgr.get_components_by_id<Rigidbody>(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], transform1, rigidbody1}, + CollidedInfoStor{circlecolliders[j], transform2, rigidbody2} + )); + } + } + } + return collisions_ret; +} + +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 + Vector2 final_position1 = current_position(box1,transform1,rigidbody1); + 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; + + // 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; + + + // Calculate half-extents (half width and half height) + double half_width1 = box1.width / 2.0; + double half_height1 = box1.height / 2.0; + double half_width2 = box2.width / 2.0; + double half_height2 = box2.height / 2.0; + + // 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 +} + +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 + Vector2 final_position1 = current_position(box1, transform1, rigidbody1); + Vector2 final_position2 = current_position(circle2, transform2, rigidbody2); + + // Log final positions for debugging purposes + std::cout << "Final Position of Box: (" << final_position1.x << ", " << final_position1.y << ")" << std::endl; + std::cout << "Final Position of Circle: (" << final_position2.x << ", " << final_position2.y << ")" << std::endl; + + // Calculate box half-extents + double half_width = box1.width / 2.0; + double half_height = box1.height / 2.0; + + // Find the closest point on the box to the circle's center + double closest_x = std::max(final_position1.x - half_width, std::min(final_position2.x, final_position1.x + half_width)); + double 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 + double distance_x = final_position2.x - closest_x; + double distance_y = final_position2.y - closest_y; + double 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; +} + +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 + Vector2 final_position1 = current_position(circle1,transform1,rigidbody1); + Vector2 final_position2 = current_position(circle2,transform2,rigidbody2); + + // Log final positions for debugging purposes + std::cout << "Final Position of Circle 1: (" << final_position1.x << ", " << final_position1.y << ")" << std::endl; + std::cout << "Final Position of Circle 2: (" << final_position2.x << ", " << final_position2.y << ")" << std::endl; + + // Log rotation values for debugging (circles do not rotate, so this might not be needed for circles) + std::cout << "Rotation of Circle 1: " << transform1.rotation << " degrees" << std::endl; + std::cout << "Rotation of Circle 2: " << transform2.rotation << " degrees" << std::endl; + + double distance_x = final_position1.x - final_position2.x; + double distance_y = final_position1.y - final_position2.y; + double distance_squared = distance_x * distance_x + distance_y * distance_y; + + // Calculate the sum of the radii + double 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; +} + +Vector2 CollisionSystem::current_position(const Collider& collider, const Transform& transform, const Rigidbody& rigidbody) { + // Function to convert degrees to radians + auto degrees_to_radians = [](double degrees) { + return degrees * (M_PI / 180.0); + }; + + // Get the rotation in radians + double radians1 = degrees_to_radians(transform.rotation); + + // Calculate total offset with scale + Vector2 total_offset = (rigidbody.data.offset + collider.offset) * transform.scale; + + // Rotate + double rotated_total_offset_x1 = total_offset.x * cos(radians1) - total_offset.y * sin(radians1); + double rotated_total_offset_y1 = total_offset.x * sin(radians1) + total_offset.y * cos(radians1); + + // Final positions considering scaling and rotation + return(transform.position + Vector2(rotated_total_offset_x1, rotated_total_offset_y1)); + +} diff --git a/src/crepe/system/CollisionSystem.h b/src/crepe/system/CollisionSystem.h index 1e9f1aa..9a72948 100644 --- a/src/crepe/system/CollisionSystem.h +++ b/src/crepe/system/CollisionSystem.h @@ -1,11 +1,36 @@ #pragma once +#include "Collider.h" +#include "api/Rigidbody.h" +#include "api/Transform.h" +#include "api/BoxCollider.h" +#include "api/CircleCollider.h" +#include <tuple> +#include <vector> +#include <variant> + namespace crepe { + class CollisionSystem { +private: + using collider_stor = std::variant<BoxCollider, CircleCollider>; +private: + struct CollidedInfoStor { + collider_stor collider; // Store either BoxCollider or CircleCollider + Transform transform; // Transform data + 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); }; } // namespace crepe |