aboutsummaryrefslogtreecommitdiff
path: root/src/crepe/system/CollisionSystem.h
diff options
context:
space:
mode:
Diffstat (limited to 'src/crepe/system/CollisionSystem.h')
-rw-r--r--src/crepe/system/CollisionSystem.h292
1 files changed, 291 insertions, 1 deletions
diff --git a/src/crepe/system/CollisionSystem.h b/src/crepe/system/CollisionSystem.h
index c1a70d8..ff2d35f 100644
--- a/src/crepe/system/CollisionSystem.h
+++ b/src/crepe/system/CollisionSystem.h
@@ -1,13 +1,303 @@
#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;
- void update() override;
+
+private:
+ //! 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:
+ //! Structure representing components of the collider
+ struct ColliderInfo {
+ Transform & transform;
+ Rigidbody & rigidbody;
+ Metadata & metadata;
+ };
+
+ /**
+ * \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 {
+ ColliderInfo self;
+ ColliderInfo other;
+ //! The resolution vector for the collision.
+ vec2 resolution;
+ //! The direction of movement for resolving the collision.
+ Direction resolution_direction = Direction::NONE;
+ CollisionInfo operator-() const;
+ };
+
+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,
+ NONE,
+ };
+
+ /**
+ * \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 handling 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;
+ ColliderInfo info;
+ vec2 resolution;
+ Direction resolution_direction = Direction::NONE;
+ };
+
+ //! Structure of a collider with additional components
+ template <typename ColliderType>
+ struct ColliderInternal {
+ ColliderType & collider;
+ Transform & transform;
+ Rigidbody & rigidbody;
+ };
+ //! Predefined BoxColliderInternal. (System is only made for this type)
+ using BoxColliderInternal = ColliderInternal<BoxCollider>;
+ //! Predefined CircleColliderInternal. (System is only made for this type)
+ using CircleColliderInternal = ColliderInternal<CircleCollider>;
+
+public:
+ //! Updates the collision system by checking for collisions between colliders and handling them.
+ void fixed_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;
+
+private:
+ /**
+ * \brief Converts internal collision data into user-accessible collision information.
+ *
+ * This function processes collision data from two colliding entities and packages it
+ * into a structured format that is accessible for further use,
+ * such as resolving collisions and triggering user-defined collision scripts.
+ *
+ * \param data1 Collision data for the first collider.
+ * \param data2 Collision data for the second collider.
+ */
+ CollisionInfo
+ get_collision_info(const CollisionInternal & data1, const CollisionInternal & data2) const;
+
+ /**
+ * \brief Corrects the collision resolution vector and determines its direction.
+ *
+ * This function adjusts the provided resolution vector based on the
+ * rigidbody's linear velocity to ensure consistent collision correction. If the resolution
+ * vector has only one non-zero component (either x or y), the missing component is computed
+ * based on the rigidbody's velocity. If both components are non-zero, it indicates a corner
+ * collision. The function also identifies the direction of the resolution and returns it.
+ *
+ * \param resolution resolution vector that needs to be corrected
+ * \param rigidbody rigidbody data used to correct resolution
+ * \return A Direction indicating the resolution direction
+ */
+ Direction resolution_correction(vec2 & resolution, const Rigidbody::Data & rigidbody);
+
+ /**
+ * \brief Determines the appropriate collision handler for a given collision event.
+ *
+ * This function identifies the correct collision resolution process based on the body types
+ * of the colliders involved in the collision. It delegates
+ * collision handling to specific handlers and calls collision event scripts
+ * as needed.
+ *
+ * \param info Collision information containing data about both colliders.
+ */
+ void determine_collision_handler(const CollisionInfo & info);
+
+ /**
+ * \brief Calls both collision script
+ *
+ * Calls both collision script to let user add additonal handling or handle full collision.
+ *
+ * \param info Collision information containing data about both colliders.
+ */
+ void call_collision_events(const CollisionInfo & info);
+
+ /**
+ * \brief Handles collisions involving static objects.
+ *
+ * This function resolves collisions between static and dynamic objects by adjusting
+ * the position of the static object and modifying the velocity of the dynamic object
+ * if elasticity is enabled. The position of the static object is corrected
+ * based on the collision resolution, and the dynamic object's velocity is adjusted
+ * accordingly to reflect the collision response.
+ *
+ * The handling includes stopping movement, applying bouncing based on the elasticity
+ * coefficient, and adjusting the position of the dynamic object if needed.
+ *
+ * \param info Collision information containing data about both colliders.
+ */
+ void static_collision_handler(const CollisionInfo & info);
+
+ /**
+ * \brief Handles collisions involving dynamic objects.
+ *
+ * Resolves collisions between two dynamic objects by adjusting their positions and modifying
+ * their velocities based on the collision resolution. If elasticity is enabled,
+ * the velocity of both objects is reversed and scaled by the respective elasticity coefficient.
+ * The positions of the objects are adjusted based on the collision resolution.
+ *
+ * \param info Collision information containing data about both colliders.
+ */
+ void dynamic_collision_handler(const CollisionInfo & info);
+
+private:
+ /**
+ * \brief Checks for collisions between colliders.
+ *
+ * This function checks all active colliders and identifies pairs of colliding objects.
+ * For each identified collision, the appropriate collision data is returned as pairs 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 the settings allow collision
+ *
+ * This function checks if there is any collison layer where each object is located in.
+ * After checking the layers it checks the names and at last the tags.
+ * if in all three sets nothing is found collision can not happen.
+ *
+ * \param this_rigidbody Rigidbody of first object
+ * \param other_rigidbody Rigidbody of second collider
+ * \param this_metadata Rigidbody of first object
+ * \param other_metadata Rigidbody of second object
+ * \return Returns true if there is at least one comparison found.
+ */
+ bool should_collide(
+ const CollisionInternal & self,
+ const CollisionInternal & other
+ ) const; //done
+
+ /**
+ * \brief Checks for collision between two colliders.
+ *
+ * This function determines whether two colliders are colliding based on their types.
+ * It calls the appropriate collision detection function based on the collider pair type and stores the collision resolution data.
+ * If a collision is detected, it returns true, otherwise false.
+ *
+ * \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 detect_collision(
+ CollisionInternal & first_info, CollisionInternal & second_info,
+ const CollisionInternalType & type
+ );
+
+ /**
+ * \brief Detects collisions between two BoxColliders.
+ *
+ * This function checks whether two `BoxCollider` are colliding based on their positions and scaled dimensions.
+ * If a collision is detected, it calculates the overlap along the X and Y axes and returns the resolution vector.
+ * If no collision is detected, it returns a vector with NaN values.
+
+ * \param box1 Information about the first BoxCollider.
+ * \param box2 Information about the second BoxCollider.
+ * \return If colliding, returns the resolution vector; otherwise, returns {NaN, NaN}.
+ */
+ vec2 get_box_box_detection(
+ const BoxColliderInternal & box1, const BoxColliderInternal & box2
+ ) const;
+
+ /**
+ * \brief Check collision for box on circle collider
+ *
+ * This function detects if a collision occurs between a rectangular box and a circular collider.
+ * If a collision is detected, the function calculates the resolution vector to resolve the collision.
+ * If no collision is detected, it returns a vector with NaN values
+ *
+ * \param box1 Information about the BoxCollider.
+ * \param circle2 Information about the circleCollider.
+ * \return If colliding, returns the resolution vector; otherwise, returns {NaN, NaN}.
+ */
+ vec2 get_box_circle_detection(
+ const BoxColliderInternal & box1, const CircleColliderInternal & circle2
+ ) const;
+
+ /**
+ * \brief Check collision for circle on circle collider
+ *
+ * This function detects if a collision occurs between two circular colliders.
+ * If a collision is detected, it calculates the resolution vector to resolve the collision.
+ * If no collision is detected, it returns a vector with NaN values.
+ *
+ * \param circle1 Information about the first circleCollider.
+ * \param circle2 Information about the second circleCollider.
+ * \return If colliding, returns the resolution vector; otherwise, returns {NaN, NaN}.
+ */
+ vec2 get_circle_circle_detection(
+ const CircleColliderInternal & circle1, const CircleColliderInternal & circle2
+ ) 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