Gama C Library
Gama C API Documentation
collision.h
Go to the documentation of this file.
1/**
2 * @file collision.h
3 * @brief Defines collision structures and provides functions for 2D collision detection.
4 *
5 * This file contains the core logic for detecting collisions between different
6 * types of physics bodies (rectangles and circles) and structures to hold
7 * collision information.
8 */
9#pragma once
10
11#include "body.h"
12#include "system.h" // For gmSystem
13#include <math.h>
14
15/**
16 * @brief Structure to store detailed information about a collision between two bodies.
17 */
18typedef struct gm_collision {
19 gmBody *bodies[2]; /**< Pointers to the two bodies involved in the collision. */
20 gmPos normals; /**< The normal vector of the collision, pointing from bodies[0] to bodies[1]. */
21 double penetration; /**< The penetration depth of the collision (how much bodies overlap). */
22 double since; /**< The total time the bodies have been in collision (for continuous collision detection). */
23 gmSystem *sys; /**< Pointer to the physics system managing this collision (can be NULL). */
25
26
27// ---------------------------------------------------------------------------
28// ----------------------------- Collision Detection -------------------------
29// ---------------------------------------------------------------------------
30
31/**
32 * @internal
33 * @brief Checks for collision between two Axis-Aligned Bounding Boxes (AABB).
34 * @param a Pointer to the first rectangular body.
35 * @param b Pointer to the second rectangular body.
36 * @return 1 if the AABBs overlap, 0 otherwise.
37 */
38static inline int gm_aabb_vs_aabb(gmBody *a, gmBody *b) {
39 double a_left = a->position.x - a->width / 2;
40 double a_right = a->position.x + a->width / 2;
41 double a_top = a->position.y + a->height / 2;
42 double a_bottom = a->position.y - a->height / 2;
43
44 double b_left = b->position.x - b->width / 2;
45 double b_right = b->position.x + b->width / 2;
46 double b_top = b->position.y + b->height / 2;
47 double b_bottom = b->position.y - b->height / 2;
48
49 // Check for no overlap and return early
50 if (a_right < b_left || a_left > b_right || a_top < b_bottom ||
51 a_bottom > b_top) {
52 return 0;
53 }
54 return 1;
55}
56
57/**
58 * @internal
59 * @brief Checks for collision between two circles.
60 * @param a Pointer to the first circular body.
61 * @param b Pointer to the second circular body.
62 * @return 1 if the circles overlap, 0 otherwise.
63 */
64static inline int gm_circle_vs_circle(gmBody *a, gmBody *b) {
65 double dx = b->position.x - a->position.x;
66 double dy = b->position.y - a->position.y;
67 double distance_sq = dx * dx + dy * dy;
68 double total_radius = a->radius + b->radius;
69 return distance_sq < (total_radius * total_radius);
70}
71/**
72 * @internal
73 * @brief Checks for collision between a circle and an Axis-Aligned Bounding Box (AABB).
74 * @param circle Pointer to the circular body.
75 * @param rect Pointer to the rectangular body.
76 * @return 1 if the circle and rectangle overlap, 0 otherwise.
77 */
78static inline int gm_circle_vs_aabb(const gmBody *circle, const gmBody *rect) {
79 double half_w = rect->width * 0.5;
80 double half_h = rect->height * 0.5;
81
82 // Clamp circle center to rectangle bounds
83 double closest_x = fmax(rect->position.x - half_w,
84 fmin(circle->position.x, rect->position.x + half_w));
85
86 double closest_y = fmax(rect->position.y - half_h,
87 fmin(circle->position.y, rect->position.y + half_h));
88
89 // Vector from closest point to circle center
90 double dx = circle->position.x - closest_x;
91 double dy = circle->position.y - closest_y;
92
93 // Check collision (<= catches "touching" cases)
94 return (dx * dx + dy * dy) <= (circle->radius * circle->radius);
95}
96
97// Main collision detection dispatcher
98/**
99 * @brief Detects a collision between two physics bodies based on their collider types.
100 *
101 * This function dispatches to specific collision tests (e.g., AABB vs AABB,
102 * Circle vs Circle, Circle vs AABB) based on the `collider_type` of the input bodies.
103 *
104 * @param a Pointer to the first body.
105 * @param b Pointer to the second body.
106 * @return A dynamically allocated `gmCollision` structure if a collision occurs,
107 * otherwise NULL. The caller is responsible for freeing the returned
108 * `gmCollision` object if it's not managed by a `gmSystem`.
109 */
111 int collided = 0;
114 collided = gm_aabb_vs_aabb(a, b);
115 }
118 collided = gm_circle_vs_circle(a, b);
119 }
122 collided = gm_circle_vs_aabb(a, b);
123 }
126 collided = gm_circle_vs_aabb(b, a);
127 }
128 if (!collided)
129 return NULL; // No collision for other combinations
130 gmCollision *collision = malloc(sizeof(gmCollision));
131 collision->bodies[0] = a;
132 collision->bodies[1] = b;
133 collision->normals = gmpos(0, 0); // Initialize to zero
134 collision->penetration = 0; // Initialize to zero
135 collision->since = 0;
136 collision->sys = NULL;
137 return collision;
138}
139
140/**
141 * @brief Checks if a given point (x, y) is contained within a body's collider.
142 *
143 * This function performs a point-in-rectangle test for `GM_COLLIDER_RECT`
144 * and a point-in-circle test for `GM_COLLIDER_CIRCLE`.
145 *
146 * @param body Pointer to the body to check.
147 * @param x The x-coordinate of the point.
148 * @param y The y-coordinate of the point.
149 * @return 1 if the point is inside the body's collider, 0 otherwise.
150 */
151int gm_body_contains(gmBody *body, double x, double y) {
152 double dx = fabs(body->position.x - x);
153 double dy = fabs(body->position.y - y);
154 switch (body->collider_type) {
155 case GM_COLLIDER_RECT:
156 return (dx < body->width * 0.5) && (dy < body->height * 0.5);
158 return (dx * dx) + (dy * dy) < (body->radius * body->radius);
159 default:
160 return 0; // Should not happen with current collider types
161 }
162}
163
164/**
165 * @brief Checks if the mouse cursor is currently within a given rectangular area.
166 * @param x The x-coordinate of the center of the rectangle.
167 * @param y The y-coordinate of the center of the rectangle.
168 * @param w The width of the rectangle.
169 * @param h The height of the rectangle.
170 * @return 1 if the mouse is inside the rectangle, 0 otherwise.
171 */
172int gm_mouse_in_rect(const double x, const double y, const double w,
173 const double h) {
174 return fabs(gm_mouse.position.x - x) < w / 2 &&
175 fabs(gm_mouse.position.y - y) < h / 2;
176}
177/**
178 * @brief Checks if the mouse cursor is currently within a given circular area.
179 * @param x The x-coordinate of the center of the circle.
180 * @param y The y-coordinate of the center of the circle.
181 * @param r The radius of the circle.
182 * @return 1 if the mouse is inside the circle, 0 otherwise.
183 */
184int gm_mouse_in_circle(const double x, const double y, const double r) {
185 return pow(gm_mouse.position.x - x, 2) + pow(gm_mouse.position.y - y, 2) <
186 pow(r, 2);
187}
@ GM_COLLIDER_RECT
Definition body.h:18
@ GM_COLLIDER_CIRCLE
Definition body.h:17
struct gm_collision gmCollision
Structure to store detailed information about a collision between two bodies.
int gm_mouse_in_rect(const double x, const double y, const double w, const double h)
Checks if the mouse cursor is currently within a given rectangular area.
Definition collision.h:172
gmCollision * gm_collision_detect(gmBody *a, gmBody *b)
Detects a collision between two physics bodies based on their collider types.
Definition collision.h:110
int gm_mouse_in_circle(const double x, const double y, const double r)
Checks if the mouse cursor is currently within a given circular area.
Definition collision.h:184
int gm_body_contains(gmBody *body, double x, double y)
Checks if a given point (x, y) is contained within a body's collider.
Definition collision.h:151
void * malloc(size_t size)
Custom implementation of malloc using a static memory pool.
Definition malloc.h:144
double fmin(double a, double b)
Returns the smaller of two double values.
Definition math.h:413
double fmax(double a, double b)
Returns the larger of two double values.
Definition math.h:428
double pow(double base, double exp)
Calculates the base raised to the power of the exponent (base^exp).
Definition math.h:358
double fabs(double x)
Calculates the absolute value of a double.
Definition math.h:369
struct _gmMouse gm_mouse
Definition mouse.h:32
Structure to store detailed information about a collision between two bodies.
Definition collision.h:18
gmPos normals
Definition collision.h:20
double since
Definition collision.h:22
double penetration
Definition collision.h:21
gmBody * bodies[2]
Definition collision.h:19
gmSystem * sys
Definition collision.h:23
Structure representing a physics body with properties for collision and movement.
Definition body.h:25
double width
Definition body.h:35
gmColliderType collider_type
Definition body.h:30
double height
Definition body.h:35
double radius
Definition body.h:35
gmPos position
Definition body.h:31
Represents a 2D position or vector.
Definition position.h:8
double x
Definition position.h:9
double y
Definition position.h:9
Manages physics bodies, their interactions, and collision detection within a simulation.
struct gm_system gmSystem
Structure representing a physics system containing bodies and collision information.