aboutsummaryrefslogtreecommitdiff
path: root/src/crepe/system/CollisionSystem.h
diff options
context:
space:
mode:
authorLoek Le Blansch <loek@pipeframe.xyz>2024-12-06 19:19:56 +0100
committerLoek Le Blansch <loek@pipeframe.xyz>2024-12-06 19:19:56 +0100
commitb9f22bb78b2d5f565451d9cd97c523fbedadaa18 (patch)
treef8c406cdcf12a9a996b7aa2eaa3f7036c9697c5d /src/crepe/system/CollisionSystem.h
parent0bed469e2ececfa240085a34252dd7ed23519de3 (diff)
parent70c1cd14ec4c4aca185d5a7e4a3749169f6425f4 (diff)
Merge branch 'jaro/collision-system' of github.com:lonkaars/crepe
Diffstat (limited to 'src/crepe/system/CollisionSystem.h')
-rw-r--r--src/crepe/system/CollisionSystem.h299
1 files changed, 299 insertions, 0 deletions
diff --git a/src/crepe/system/CollisionSystem.h b/src/crepe/system/CollisionSystem.h
index c1a70d8..7e893c8 100644
--- a/src/crepe/system/CollisionSystem.h
+++ b/src/crepe/system/CollisionSystem.h
@@ -1,13 +1,312 @@
#pragma once
+#include <optional>
+#include <variant>
+#include <vector>
+
+#include "api/BoxCollider.h"
+#include "api/CircleCollider.h"
+#include "api/Event.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<BoxCollider>,
+ std::reference_wrapper<CircleCollider>>;
+
+ //! Enum representing the types of collider pairs for collision detection.
+ enum class CollisionInternalType {
+ BOX_BOX,
+ CIRCLE_CIRCLE,
+ BOX_CIRCLE,
+ CIRCLE_BOX,
+ };
+
+ /**
+ * \brief A structure to store the collision data of a single collider.
+ *
+ * This structure all components and id that are for needed within this system when calculating or handeling collisions.
+ * The transform and rigidbody are mostly needed for location and rotation.
+ * In rigidbody additional info is written about what the body of the object is,
+ * and how it should respond on a collision.
+ */
+ struct CollisionInternal {
+ game_object_id_t id = 0;
+ collider_variant collider;
+ Transform & transform;
+ Rigidbody & rigidbody;
+ };
+
+ //! Enum representing movement directions during collision resolution.
+ enum class Direction {
+ //! No movement required.
+ NONE,
+ //! Movement in the X direction.
+ X_DIRECTION,
+ //! Movement in the Y direction.
+ Y_DIRECTION,
+ //! Movement in both X and Y directions.
+ BOTH
+ };
+
+public:
+ /**
+ * \brief Structure representing detailed collision information between two colliders.
+ *
+ * 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;
+ //! The resolution vector for the collision.
+ vec2 resolution;
+ //! The direction of movement for resolving the collision.
+ Direction resolution_direction = Direction::NONE;
+ };
+
+public:
+ //! Updates the collision system by checking for collisions between colliders and handling them.
void update() override;
+
+private:
+ /**
+ * \brief Determines the type of collider pair from two colliders.
+ *
+ * Uses std::holds_alternative to identify the types of the provided colliders.
+ *
+ * \param collider1 First collider variant (BoxCollider or CircleCollider).
+ * \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;
+
+ /**
+ * \brief Calculates the current position of a collider.
+ *
+ * Combines the Collider offset, Transform position, and Rigidbody offset to compute the position of the collider.
+ *
+ * \param collider_offset The offset of the collider.
+ * \param transform The Transform of the associated game object.
+ * \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;
+
+private:
+ /**
+ * \brief Handles collision resolution between two colliders.
+ *
+ * Processes collision data and adjusts objects to resolve collisions and/or calls the user oncollision script function.
+ *
+ * \param data1 Collision data for the first collider.
+ * \param data2 Collision data for the second collider.
+ */
+ void collision_handler_request(CollisionInternal & data1, CollisionInternal & data2);
+
+ /**
+ * \brief Resolves collision between two colliders and calculates the movement required.
+ *
+ * Determines the displacement and direction needed to separate colliders based on their types.
+ *
+ * \param data1 Collision data for the first collider.
+ * \param data2 Collision data for the second collider.
+ * \param type The type of collider pair.
+ * \return A pair containing the resolution vector and direction for the first collider.
+ */
+ std::pair<vec2, Direction> collision_handler(CollisionInternal & data1,
+ CollisionInternal & data2,
+ CollisionInternalType type);
+
+ /**
+ * \brief Calculates the resolution vector for two BoxColliders.
+ *
+ * Computes the displacement required to separate two overlapping BoxColliders.
+ *
+ * \param box_collider1 The first BoxCollider.
+ * \param box_collider2 The second BoxCollider.
+ * \param position1 The position of the first BoxCollider.
+ * \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;
+
+ /**
+ * \brief Calculates the resolution vector for two CircleCollider.
+ *
+ * Computes the displacement required to separate two overlapping CircleCollider.
+ *
+ * \param circle_collider1 The first CircleCollider.
+ * \param circle_collider2 The second CircleCollider.
+ * \param position1 The position of the first CircleCollider.
+ * \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;
+
+ /**
+ * \brief Calculates the resolution vector for two CircleCollider.
+ *
+ * Computes the displacement required to separate two overlapping CircleCollider.
+ *
+ * \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 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;
+
+ /**
+ * \brief Determines the appropriate collision handler for a collision.
+ *
+ * Decides the correct resolution process based on the dynamic or static nature of the colliders involved.
+ *
+ * \param info Collision information containing data about both colliders.
+ */
+ void determine_collision_handler(CollisionInfo & info);
+
+ /**
+ * \brief Handles collisions involving static objects.
+ *
+ * Resolves collisions by adjusting positions and modifying velocities if bounce is enabled.
+ *
+ * \param info Collision information containing data about both colliders.
+ */
+ void static_collision_handler(CollisionInfo & info);
+
+private:
+ /**
+ * \brief Checks for collisions between colliders.
+ *
+ * Identifies collisions and generates pairs of colliding objects for further processing.
+ *
+ * \param colliders A collection of all active colliders.
+ * \return A list of collision pairs with their associated data.
+ */
+ std::vector<std::pair<CollisionInternal, CollisionInternal>>
+ gather_collisions(std::vector<CollisionInternal> & colliders);
+
+ /**
+ * \brief Checks if two collision layers have at least one common layer.
+ *
+ * This function checks if there is any overlapping layer between the two inputs.
+ * It compares each layer from the first input to see
+ * if it exists in the second input. If at least one common layer is found,
+ * the function returns true, indicating that the two colliders share a common
+ * collision layer.
+ *
+ * \param layers1 all collision layers for the first collider.
+ * \param layers2 all collision layers for the second collider.
+ * \return Returns true if there is at least one common layer, false otherwise.
+ */
+
+ bool have_common_layer(const std::set<int> & layers1, const std::set<int> & layers2);
+
+ /**
+ * \brief Checks for collision between two colliders.
+ *
+ * Calls the appropriate collision detection function based on the collider types.
+ *
+ * \param first_info Collision data for the first collider.
+ * \param second_info Collision data for the second collider.
+ * \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;
+
+ /**
+ * \brief Detects collisions between two BoxColliders.
+ *
+ * \param box1 The first BoxCollider.
+ * \param box2 The second BoxCollider.
+ * \param transform1 Transform of the first object.
+ * \param transform2 Transform of the second object.
+ * \param rigidbody1 Rigidbody of the first object.
+ * \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;
+
+ /**
+ * \brief Check collision for box on circle collider
+ *
+ * \param box1 The BoxCollider
+ * \param circle2 The CircleCollider
+ * \param transform1 Transform of the first object.
+ * \param transform2 Transform of the second object.
+ * \param rigidbody1 Rigidbody of the first object.
+ * \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;
+
+ /**
+ * \brief Check collision for circle on circle collider
+ *
+ * \param circle1 First CircleCollider
+ * \param circle2 Second CircleCollider
+ * \param transform1 Transform of the first object.
+ * \param transform2 Transform of the second object.
+ * \param rigidbody1 Rigidbody of the first object.
+ * \param rigidbody2 Rigidbody of the second object.
+ * \return True if a collision is detected, otherwise false.
+ *
+ * \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;
+};
+
+/**
+ * \brief Event triggered during a collision between objects.
+ */
+class CollisionEvent : public Event {
+public:
+ crepe::CollisionSystem::CollisionInfo info;
+ CollisionEvent(const crepe::CollisionSystem::CollisionInfo & collisionInfo)
+ : info(collisionInfo) {}
};
} // namespace crepe