diff options
Diffstat (limited to 'src/crepe/system')
-rw-r--r-- | src/crepe/system/CollisionSystem.cpp | 378 | ||||
-rw-r--r-- | src/crepe/system/CollisionSystem.h | 233 |
2 files changed, 610 insertions, 1 deletions
diff --git a/src/crepe/system/CollisionSystem.cpp b/src/crepe/system/CollisionSystem.cpp index c74ca1d..6f2c39d 100644 --- a/src/crepe/system/CollisionSystem.cpp +++ b/src/crepe/system/CollisionSystem.cpp @@ -1,5 +1,381 @@ +#include <cmath> +#include <algorithm> +#include <cstddef> +#include <functional> +#include <utility> +#include <variant> +#include <optional> + +#include "api/Event.h" +#include "api/EventManager.h" +#include "api/BoxCollider.h" +#include "api/CircleCollider.h" +#include "api/Vector2.h" +#include "api/Rigidbody.h" +#include "api/Transform.h" + +#include "ComponentManager.h" #include "CollisionSystem.h" +#include "Collider.h" +#include "types.h" +#include "util/OptionalRef.h" using namespace crepe; -void CollisionSystem::update() {} +void CollisionSystem::update() { + // Get collider components and keep them seperate + ComponentManager & mgr = this->component_manager; + 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<collider_stor> 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<std::pair<CollidedInfoStor,CollidedInfoStor>> collided = check_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); + } +} + +void CollisionSystem::collision_handler_request(CollidedInfoStor& data1,CollidedInfoStor& data2){ + + ColliderStorType type = check_collider_type(data1.collider,data2.collider); + std::pair<vec2,CollisionSystem::Direction> move_back_data = collision_handler(data1,data2,type); + + OptionalRef<Collider> collider1; + OptionalRef<Collider> collider2; + switch (type) { + case ColliderStorType::BOX_BOX:{ + collider1 = std::get<std::reference_wrapper<BoxCollider>>(data1.collider); + collider2 = std::get<std::reference_wrapper<BoxCollider>>(data2.collider); + break; + } + case ColliderStorType::BOX_CIRCLE:{ + collider1 = std::get<std::reference_wrapper<BoxCollider>>(data1.collider); + collider2 = std::get<std::reference_wrapper<CircleCollider>>(data2.collider); + break; + } + case ColliderStorType::CIRCLE_BOX:{ + collider1 = std::get<std::reference_wrapper<CircleCollider>>(data1.collider); + collider2 = std::get<std::reference_wrapper<BoxCollider>>(data2.collider); + break; + } + case ColliderStorType::CIRCLE_CIRCLE:{ + collider1 = std::get<std::reference_wrapper<CircleCollider>>(data1.collider); + collider2 = std::get<std::reference_wrapper<CircleCollider>>(data2.collider); + break; + } + } + + // 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<vec2,CollisionSystem::Direction> CollisionSystem::collision_handler(CollidedInfoStor& data1,CollidedInfoStor& data2,ColliderStorType type) { + vec2 move_back; + switch (type) { + case ColliderStorType::BOX_BOX: { + const BoxCollider & collider1 = std::get<std::reference_wrapper<BoxCollider>>(data1.collider); + const BoxCollider & collider2 = std::get<std::reference_wrapper<BoxCollider>>(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); + } + case ColliderStorType::BOX_CIRCLE: { + + } + case ColliderStorType::CIRCLE_CIRCLE: { + + } + case ColliderStorType::CIRCLE_BOX: { + + } + } + + Direction move_back_direction = Direction::NONE; + if(move_back.x != 0 && move_back.y > 0) { + move_back_direction = Direction::BOTH; + } else if (move_back.x != 0) { + move_back_direction = Direction::X_DIRECTION; + if(data1.rigidbody.data.linear_velocity.y != 0) + move_back.y = data1.rigidbody.data.linear_velocity.y * (move_back.x/data1.rigidbody.data.linear_velocity.x); + } else if (move_back.y != 0) { + move_back_direction = Direction::Y_DIRECTION; + if(data1.rigidbody.data.linear_velocity.x != 0) + move_back.x = data1.rigidbody.data.linear_velocity.x * (move_back.y/data1.rigidbody.data.linear_velocity.y); + } + + return {move_back,move_back_direction}; +} + +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; + + // 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; + + // Calculate overlaps along X and Y axes + 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 + // Determine the direction of resolution + if (overlap_x < overlap_y) { + // Resolve along the X-axis (smallest overlap) + resolution.x = (delta.x > 0) ? -overlap_x : overlap_x; + } else if (overlap_y < overlap_x) { + // Resolve along the Y-axis (smallest overlap) + resolution.y = (delta.y > 0) ? -overlap_y : overlap_y; + } else { + // Equal overlap, resolve both directions with preference + resolution.x = (delta.x > 0) ? -overlap_x : overlap_x; + resolution.y = (delta.y > 0) ? -overlap_y : overlap_y; + } + } + + return resolution; +} + +void CollisionSystem::determine_collision_handler(CollisionInfo& info){ + // Check rigidbody type for static + if(info.first.rigidbody.data.body_type != Rigidbody::BodyType::STATIC) + { + // If second body is static perform the static collision handler in this system + if(info.second.rigidbody.data.body_type == Rigidbody::BodyType::STATIC){ + static_collision_handler(info); + }; + // Call collision event for user + CollisionEvent data(info); + EventManager::get_instance().trigger_event<CollisionEvent>(data, info.first.collider.game_object_id); + } +} + +void CollisionSystem::static_collision_handler(CollisionInfo& info){ + // Move object back using calculate move back value + info.first.transform.position += info.move_back_value; + + // If bounce is enabled mirror velocity + if(info.first.rigidbody.data.bounce) { + if(info.move_back_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; + } + else if(info.move_back_direction == Direction::Y_DIRECTION) { + info.first.rigidbody.data.linear_velocity.y = -info.first.rigidbody.data.linear_velocity.y * info.first.rigidbody.data.elastisity; + } + else if(info.move_back_direction == Direction::X_DIRECTION){ + info.first.rigidbody.data.linear_velocity.x = -info.first.rigidbody.data.linear_velocity.x * info.first.rigidbody.data.elastisity; + } + } + // Stop movement if bounce is disabled + else { + info.first.rigidbody.data.linear_velocity = {0,0}; + } +} + +std::vector<std::pair<CollisionSystem::CollidedInfoStor,CollisionSystem::CollidedInfoStor>> CollisionSystem::check_collisions(std::vector<collider_stor> & colliders) { + + + // TODO: + // If no colliders skip + // Check if colliders has rigidbody if not skip + + // TODO: + // If amount is higer than lets say 16 for now use quadtree otwerwise skip + // Quadtree code + // Quadtree is placed over the input vector + + // 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::pair<std::reference_wrapper<Transform>, std::reference_wrapper<Rigidbody>>> { + RefVector<Transform> transforms = this->component_manager.get_components_by_id<Transform>(game_object_id); + if (transforms.empty()) return std::nullopt; + + RefVector<Rigidbody> rigidbodies = this->component_manager.get_components_by_id<Rigidbody>(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; + + // Return the active components + return std::make_pair(std::ref(transform), std::ref(rigidbody)); + }; + + + std::vector<std::pair<CollidedInfoStor,CollidedInfoStor>> 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(outer_collider_ref.get().game_object_id); + if (!outer_components) return; + ColliderStorType type = check_collider_type(colliders[i],colliders[j]); + if(!check_collision(colliders[i],*inner_components,colliders[j],*outer_components,type)) return; + 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<std::reference_wrapper<CircleCollider>>(collider1)){ + if(std::holds_alternative<std::reference_wrapper<CircleCollider>>(collider2)) + { + return ColliderStorType::CIRCLE_CIRCLE; + } + else { + return ColliderStorType::CIRCLE_BOX; + } + } + else { + if(std::holds_alternative<std::reference_wrapper<CircleCollider>>(collider2)) + { + return ColliderStorType::BOX_CIRCLE; + } + else { + return ColliderStorType::BOX_BOX; + } + } +} + +bool CollisionSystem::check_collision(const collider_stor& collider1,std::pair<std::reference_wrapper<Transform>, std::reference_wrapper<Rigidbody>> components1,const collider_stor& collider2,std::pair<std::reference_wrapper<Transform>, std::reference_wrapper<Rigidbody>> components2, ColliderStorType type){ + switch (type) { + case ColliderStorType::BOX_BOX: { + const BoxCollider & box_collider1 = std::get<std::reference_wrapper<BoxCollider>>(collider1); + const BoxCollider & box_collider2 = std::get<std::reference_wrapper<BoxCollider>>(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<std::reference_wrapper<BoxCollider>>(collider1); + const CircleCollider & circle_collider = std::get<std::reference_wrapper<CircleCollider>>(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<std::reference_wrapper<CircleCollider>>(collider1); + const CircleCollider & circle_collider2 = std::get<std::reference_wrapper<CircleCollider>>(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 CircleCollider & circle_collider = std::get<std::reference_wrapper<CircleCollider>>(collider1); + const BoxCollider & box_collider = std::get<std::reference_wrapper<BoxCollider>>(collider2); + return check_box_circle_collision(box_collider,circle_collider,components1.first.get(),components2.first.get(),components1.second.get(),components2.second.get()); + } + } + return false; +} + + +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.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; + float half_height1 = box1.height / 2.0; + float half_width2 = box2.width / 2.0; + float 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 && // not left + final_position1.x - half_width1 < final_position2.x + half_width2 && // not right + final_position1.y + half_height1 > final_position2.y - half_height2 && // not above + final_position1.y - half_height1 < final_position2.y + half_height2); // not below +} + +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.offset, transform1, rigidbody1); + vec2 final_position2 = current_position(circle2.offset, transform2, rigidbody2); + + // Calculate box half-extents + float half_width = box1.width / 2.0; + float half_height = box1.height / 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)); + + // Calculate the distance squared between the circle's center and the closest point on the box + float distance_x = final_position2.x - closest_x; + float distance_y = final_position2.y - closest_y; + 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; +} + +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.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; + float distance_squared = distance_x * distance_x + distance_y * distance_y; + + // Calculate the sum of the radii + 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; +} + +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; + + // 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); + + // Final positions considering scaling and rotation + 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 c1a70d8..6334ba1 100644 --- a/src/crepe/system/CollisionSystem.h +++ b/src/crepe/system/CollisionSystem.h @@ -1,13 +1,246 @@ #pragma once +#include <vector> +#include <variant> + +#include "api/Rigidbody.h" +#include "api/Transform.h" +#include "api/BoxCollider.h" +#include "api/CircleCollider.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_stor = std::variant<BoxCollider, CircleCollider>; + using collider_stor = std::variant<std::reference_wrapper<BoxCollider>, std::reference_wrapper<CircleCollider>>; + + //! 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. + * + * This structure stores the collider type, its associated transform, and its rigidbody. + */ + struct CollidedInfoStor { + //! Store either BoxCollider or CircleCollider + collider_stor& collider; + Transform& transform; + Rigidbody& rigidbody; + }; + + //! Enum representing movement directions during collision resolution. + enum class Direction { + NONE, + X_DIRECTION, + Y_DIRECTION, + BOTH + }; + +public: + /** + * \brief A structure representing the collision information between two colliders. + * + * This structure contains both colliders, their associated transforms and rigidbodies, + * as well as the movement vector to resolve the collision. + */ + struct ColliderInfo { + const Collider& collider; + Transform& transform; + Rigidbody& rigidbody; + }; + /** + * \brief A structure representing detailed collision information between two colliders. + * + * This includes the movement data required to resolve the collision. + */ + struct CollisionInfo{ + ColliderInfo first; + ColliderInfo second; + vec2 move_back_value; + Direction move_back_direction = Direction::NONE; + }; + +public: + + //! Updates the collision system by checking for collisions between colliders and handling them. void update() override; +private: //generic + + /** + * \brief Returns a type of the colliders combined into a pair. + * + * This function uses the holds_alternative to determine what both colliders are. + * This caluclated value is returned so get can be savely used. + * + * \param collider1 Variant of collider. Can be a box or circle collider + * \param collider2 Variant of collider. Can be a box or circle collider + * + * \return collider pair type. + */ + ColliderStorType check_collider_type(const collider_stor& collider1,const collider_stor& collider2); + + /** + * \brief Calculates the position of the Collider + * + * Using the \c Collider offset, \c Transform position and \c Rigidbody offset the place of the collider is calculated. + * + * \param collider_offset Collider offset value. + * \param transform Transform of same gameobject as collider. + * \param rigidbody Rigidbody of same gameobject as collider. + * + * \return Postion of collider. + */ + vec2 current_position(vec2 collider_offset, const Transform& transform, const Rigidbody& rigidbody); + +private:// handeling + + /** + * \brief Calculates the position of the Collider + * + * Using the \c Collider offset, \c Transform position and \c Rigidbody offset the place of the collider is calculated. + * + * \param collider_offset Collider offset value. + * \param transform Transform of same gameobject as collider. + * \param rigidbody Rigidbody of same gameobject as collider. + * + * \return Postion of collider. + */ + void collision_handler_request(CollidedInfoStor& data1,CollidedInfoStor& data2); + + /** + * \brief Calculates the move back value and direction of the Collision + * + * Uses data from both gameobjects to calculate the value of the gameobject to move out of other collider. + * + * \param data1 Has data about the first gameobject of the collision + * \param data2 Has data about the second gameobject of the collision + * \param type Type of collider pair used for variant + * + * \return Move back value and direction for first gameobject + */ + std::pair<vec2,Direction> collision_handler(CollidedInfoStor& data1,CollidedInfoStor& data2 ,ColliderStorType type); + + /** + * \brief Calculates the move back value for box box collision + * + * Uses both collider and positions to calculate move back value + * + * \param box_collider1 First boxcollider of collision + * \param box_collider2 Second boxcollider of collision + * \param position1 Position of first boxcollider + * \param position2 Position of second boxcollider + * + * \return Move back value and direction for first gameobject + */ + vec2 box_box_move_back(const BoxCollider& box_collider1,const BoxCollider& box_collider2,vec2 position1,vec2 position2); + + /** + * \brief Determines what collision handler is called + * + * If the object is static is does nothing. + * If the object is dynamic and collides with not static object it calls the script collision handeler. + * If the object is dynamic and collides with static it handles it and calls the script collision handeler. + * + * \param info Collision info of both gameobjects + */ + void determine_collision_handler(CollisionInfo& info); + + /** + * \brief handles static collision + * + * Moves the object back out of static gameobject. + * If bounce is active change velocity. + * + * \param info Collision info of both gameobjects + */ + void static_collision_handler(CollisionInfo& info); +private: // detection + + /** + * \brief Checks if there is an collision between two colliders + * + * Does not use the type of a collider to determine if there is collision. + * uses variant with comment data to determine if even collision needs to be checked. + * + * \param colliders Holds all colliders + * + * \return Move back value and direction for first gameobject + */ + std::vector<std::pair<CollidedInfoStor,CollidedInfoStor>> check_collisions(std::vector<collider_stor> & colliders); + + /** + * \brief Calls the correct check collision function. + * + * Uses the type to check what colliders are used, converts the colliders and calls the check function. + * + * \param collider1 First collider + * \param components1 Transform and rigidbody from first object + * \param collider2 Second collider + * \param components2 Transform and rigidbody from second object + * \param type Type of collider pair + * + * \return status of collision + */ + bool check_collision(const collider_stor& collider1,std::pair<std::reference_wrapper<Transform>, std::reference_wrapper<Rigidbody>> components1,const collider_stor& collider2,std::pair<std::reference_wrapper<Transform>, std::reference_wrapper<Rigidbody>> components2,CollisionSystem::ColliderStorType type); + + /** + * \brief Check collision for box on box collider + * + * \param box1 First collider + * \param box2 Second collider + * \param transform1 Transform of first object + * \param transform2 Transform of second object + * \param rigidbody1 Rigidbody of first object + * \param rigidbody2 Rigidbody of second object + * + * \return status of collision + */ + bool check_box_box_collision(const BoxCollider& box1, const BoxCollider& box2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2); + + /** + * \brief Check collision for box on circle collider + * + * \param box1 First collider + * \param circle2 Second collider + * \param transform1 Transform of first object + * \param transform2 Transform of second object + * \param rigidbody1 Rigidbody of first object + * \param rigidbody2 Rigidbody of second object + * + * \return status of collision + */ + bool check_box_circle_collision(const BoxCollider& box1, const CircleCollider& circle2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2); + + /** + * \brief Check collision for circle on circle collider + * + * \param circle1 First collider + * \param circle2 Second collider + * \param transform1 Transform of first object + * \param transform2 Transform of second object + * \param rigidbody1 Rigidbody of first object + * \param rigidbody2 Rigidbody of second object + * + * \return status of collision + */ + bool check_circle_circle_collision(const CircleCollider& circle1, const CircleCollider& circle2, const Transform& transform1, const Transform& transform2, const Rigidbody& rigidbody1, const Rigidbody& rigidbody2); }; } // namespace crepe |