Gama C Library
Gama C API Documentation
Loading...
Searching...
No Matches
body.h
Go to the documentation of this file.
1#pragma once
2
3#define gnothing NULL
4
5#include "gapi.h"
6#include <stdint.h>
7
8/**
9 * @brief Enum to define the type of collider for a physics body.
10 */
11typedef enum {
12 GM_COLLIDER_CIRCLE, /**< Circular collider */
13 GM_COLLIDER_RECT /**< Rectangular collider */
15
16/**
17 * @brief Structure representing a physics body with properties for collision and movement.
18 */
19typedef struct {
20 uint8_t is_active; /**< Whether the body is active in the physics simulation */
21 uint8_t is_static; /**< Whether the body is static (immovable) */
22
23 gmColliderType collider_type; /**< Type of collider (rectangle or circle) */
24 gmPos position; /**< Current position of the body */
25 gmPos velocity; /**< Current velocity of the body */
26 gmPos acceleration; /**< Current acceleration of the body */
27
28 double width, height, radius; /**< Dimensions of the body (width/height for rectangles, radius for circles) */
29 double mass; /**< Mass of the body */
30 double restitution; /**< Bounciness of the body (0.0 = no bounce, 1.0+ = bounce) */
31 double friction; /**< Friction coefficient (not currently used in the code) */
32} gmBody;
33
34/**
35 * @brief Creates a new physics body with specified properties.
36 * @param mass The mass of the body.
37 * @param x The x-coordinate of the body's position.
38 * @param y The y-coordinate of the body's position.
39 * @param w The width of the body.
40 * @param h The height of the body.
41 * @param c The type of collider for the body.
42 * @return A new gmBody instance.
43 */
44gmBody gm_body_create(double mass, double x, double y, double w, double h,
46 gmBody body = {
47 .is_active = 1,
48 .is_static = 0,
49 .collider_type = c,
50 .position = {.x = x, .y = y},
51 .velocity = {.x = 0, .y = 0},
52 .acceleration = {.x = 0, .y = 0},
53 .width = w,
54 .height = h,
55 .radius = w < h ? w : h,
56 .mass = mass,
57 .restitution = 1,
58 };
59 return body;
60}
61
62/**
63 * @brief Limits the maximum speed of a body.
64 * @param body Pointer to the body to modify.
65 * @param max_speed The maximum allowed speed.
66 */
67void gm_max_speed(gmBody *body, double max_speed) {
68 double current_speed = gm_pos_magniture(body->velocity);
69 if (current_speed > max_speed) {
70 double factor = max_speed / current_speed;
71 body->velocity.x *= factor;
72 body->velocity.y *= factor;
73 }
74}
75
76/**
77 * @brief Sets the minimum speed of a body.
78 * @param body Pointer to the body to modify.
79 * @param min_speed The minimum allowed speed.
80 */
81void gm_min_speed(gmBody *body, double min_speed) {
82 double current_speed = gm_pos_magniture(body->velocity);
83 if (current_speed < min_speed) {
84 // Avoid division by zero if body is not moving.
85 if (current_speed == 0)
86 return;
87
88 double factor = min_speed / current_speed;
89 body->velocity.x *= factor;
90 body->velocity.y *= factor;
91 }
92}
93
94/**
95 * @brief Sets the speed of a body while preserving its direction.
96 * @param body Pointer to the body to modify.
97 * @param speed The speed to set.
98 */
99void gm_speed(gmBody *body, double speed) {
100 double current_speed = gm_pos_magniture(body->velocity);
101 if (current_speed == speed)
102 return;
103
104 if (current_speed == 0) {
105 // If speed is 0, we have no direction. Assume movement along X axis.
106 body->velocity.x = speed;
107 body->velocity.y = 0;
108 } else {
109 double factor = speed / current_speed;
110 body->velocity.x *= factor;
111 body->velocity.y *= factor;
112 }
113}
114
115/**
116 * @brief Limits the maximum speed of a body using an animation function.
117 * @param body Pointer to the body to modify.
118 * @param max_speed The maximum allowed speed.
119 * @param animator Function pointer to animate the velocity change.
120 * @param dt Delta time for animation.
121 * @param t Time parameter for animation.
122 */
123void gm_max_speed_anim(gmBody *body, double max_speed,
124 void animator(double *value, double target, double dt,
125 double t),
126 double dt, double t) {
127 double current_speed = gm_pos_magniture(body->velocity);
128 if (current_speed > max_speed) {
129 double factor = max_speed / current_speed;
130 double x_target = body->velocity.x * factor;
131 double y_target = body->velocity.y * factor;
132 animator(&body->velocity.x, x_target, dt, t);
133 animator(&body->velocity.y, y_target, dt, t);
134 }
135}
136
137/**
138 * @brief Sets the minimum speed of a body using an animation function.
139 * @param body Pointer to the body to modify.
140 * @param min_speed The minimum allowed speed.
141 * @param animator Function pointer to animate the velocity change.
142 * @param dt Delta time for animation.
143 * @param t Time parameter for animation.
144 */
145void gm_min_speed_anim(gmBody *body, double min_speed,
146 void animator(double *value, double target, double dt,
147 double t),
148 double dt, double t) {
149 double current_speed = gm_pos_magniture(body->velocity);
150 if (current_speed < min_speed) {
151 // Avoid division by zero if body is not moving.
152 if (current_speed == 0)
153 return;
154 double factor = min_speed / current_speed;
155 double x_target = body->velocity.x * factor;
156 double y_target = body->velocity.y * factor;
157 animator(&body->velocity.x, x_target, dt, t);
158 animator(&body->velocity.y, y_target, dt, t);
159 }
160}
161
162/**
163 * @brief Sets the speed of a body using an animation function.
164 * @param body Pointer to the body to modify.
165 * @param speed The speed to set.
166 * @param animator Function pointer to animate the velocity change.
167 * @param dt Delta time for animation.
168 * @param t Time parameter for animation.
169 */
170void gm_speed_anim(gmBody *body, double speed,
171 void animator(double *value, double target, double dt,
172 double t),
173 double dt, double t) {
174 double current_speed = gm_pos_magniture(body->velocity);
175 if (current_speed != speed) {
176 double x_target, y_target;
177 if (current_speed == 0) {
178 // If speed is 0, we have no direction. Assume movement along X axis.
179 x_target = speed;
180 y_target = 0;
181 } else {
182 double factor = speed / current_speed;
183 x_target = body->velocity.x * factor;
184 y_target = body->velocity.y * factor;
185 }
186 animator(&body->velocity.x, x_target, dt, t);
187 animator(&body->velocity.y, y_target, dt, t);
188 }
189}
190
191/**
192 * @brief Creates a rectangular physics body.
193 * @param m The mass of the body.
194 * @param x The x-coordinate of the body's position.
195 * @param y The y-coordinate of the body's position.
196 * @param w The width of the body.
197 * @param h The height of the body.
198 * @return A new rectangular gmBody instance.
199 */
200gmBody gm_rectangle_body(double m, double x, double y, double w, double h) {
201 return gm_body_create(m, x, y, w, h, GM_COLLIDER_RECT);
202}
203
204/**
205 * @brief Creates a circular physics body.
206 * @param m The mass of the body.
207 * @param x The x-coordinate of the body's position.
208 * @param y The y-coordinate of the body's position.
209 * @param r The radius of the body.
210 * @return A new circular gmBody instance.
211 */
212gmBody gm_circle_body(double m, double x, double y, double r) {
213 return gm_body_create(m, x, y, r, r, GM_COLLIDER_CIRCLE);
214}
215
216/**
217 * @brief Checks if a point is contained within a body's collider.
218 * @param body Pointer to the body to check.
219 * @param x The x-coordinate of the point.
220 * @param y The y-coordinate of the point.
221 * @return 1 if the point is inside the body, 0 otherwise.
222 */
223int gm_body_contains(gmBody *body, double x, double y);
224
225/**
226 * @brief Checks if a body is currently being hovered over by the mouse.
227 * @param body Pointer to the body to check.
228 * @return 1 if the body is being hovered over, 0 otherwise.
229 */
230static inline int gm_hovered(gmBody *body) {
231 return gm_body_contains(body, gm_mouse.position.x, gm_mouse.position.y);
232}
233
234/**
235 * @brief Checks if a body is currently being clicked by the mouse.
236 * @param body Pointer to the body to check.
237 * @return 1 if the body is being clicked, 0 otherwise.
238 */
239static inline int gm_clicked(gmBody *body) {
240 return gm_mouse.pressed && gm_hovered(body);
241}
242
243/**
244 * @brief Constrains a body within specified boundaries by clipping its position.
245 * @param body Pointer to the body to constrain.
246 * @param bx The beginning x-coordinate of the boundary (0 to ignore).
247 * @param ex The ending x-coordinate of the boundary (0 to ignore).
248 * @param by The beginning y-coordinate of the boundary (0 to ignore).
249 * @param ey The ending y-coordinate of the boundary (0 to ignore).
250 * @return A bitmask indicating which boundaries were exceeded (0b1000=left, 0b0100=right, 0b0010=bottom, 0b0001=top).
251 */
252static inline uint8_t gm_body_bound_clip(gmBody *body, double bx, double ex,
253 double by, double ey) {
254
255 int8_t exited = 0;
256 if (bx != 0 || ex != 0) {
257 if (body->position.x < bx) {
258 body->position.x = bx;
259 exited |= 0b1000;
260 } else if (body->position.x > ex) {
261 body->position.x = ex;
262 exited |= 0b0100;
263 }
264 }
265 if (by != 0 || ey != 0) {
266 if (body->position.y < by) {
267 body->position.y = by;
268 exited |= 0b0010;
269 } else if (body->position.y > ey) {
270 body->position.y = ey;
271 exited |= 0b0001;
272 }
273 }
274 return exited;
275}
276
277/**
278 * @brief Wraps a body around specified boundaries (like a torus).
279 * @param body Pointer to the body to wrap.
280 * @param bx The beginning x-coordinate of the boundary (0 to ignore).
281 * @param ex The ending x-coordinate of the boundary (0 to ignore).
282 * @param by The beginning y-coordinate of the boundary (0 to ignore).
283 * @param ey The ending y-coordinate of the boundary (0 to ignore).
284 * @return A bitmask indicating which boundaries were exceeded.
285 */
286static inline int8_t gm_body_bound_reflect(gmBody *body, double bx, double ex,
287 double by, double ey) {
288 int8_t exited = 0;
289 if (body->position.x < bx) {
290 body->position.x = ex;
291 exited |= 0b1000;
292 } else if (body->position.x > ex) {
293 body->position.x = bx;
294 exited |= 0b0100;
295 }
296 if (body->position.y < by) {
297 body->position.y = ey;
298 exited |= 0b0010;
299 } else if (body->position.y > ey) {
300 body->position.y = by;
301 exited |= 0b0001;
302 }
303 return exited;
304}
305
306/**
307 * @brief Bounces a body when it exceeds specified boundaries.
308 * @param body Pointer to the body to bounce.
309 * @param bx The beginning x-coordinate of the boundary (0 to ignore).
310 * @param ex The ending x-coordinate of the boundary (0 to ignore).
311 * @param by The beginning y-coordinate of the boundary (0 to ignore).
312 * @param ey The ending y-coordinate of the boundary (0 to ignore).
313 * @param restitution The bounciness factor to apply when bouncing.
314 * @return A bitmask indicating which boundaries were exceeded.
315 */
316static inline int8_t gm_body_bound_bounce(gmBody *body, double bx, double ex,
317 double by, double ey,
318 double restitution) {
319 int8_t exited = 0;
320 if (body->position.x < bx && body->velocity.x < 0) {
321 body->velocity.x = fabs(body->velocity.x) * restitution;
322 exited |= 0b1000;
323 } else if (body->position.x > ex && body->velocity.x > 0) {
324 body->velocity.x = -fabs(body->velocity.x) * restitution;
325 exited |= 0b0100;
326 }
327 if (body->position.y < by && body->velocity.y < 0) {
328 body->velocity.y = fabs(body->velocity.y) * restitution;
329 exited |= 0b0010;
330 } else if (body->position.y > ey && body->velocity.y > 0) {
331 body->velocity.y = -fabs(body->velocity.y) * restitution;
332 exited |= 0b0001;
333 }
334 return exited;
335}
void gm_speed_anim(gmBody *body, double speed, void animator(double *value, double target, double dt, double t), double dt, double t)
Sets the speed of a body using an animation function.
Definition body.h:170
void gm_max_speed(gmBody *body, double max_speed)
Limits the maximum speed of a body.
Definition body.h:67
gmBody gm_rectangle_body(double m, double x, double y, double w, double h)
Creates a rectangular physics body.
Definition body.h:200
void gm_speed(gmBody *body, double speed)
Sets the speed of a body while preserving its direction.
Definition body.h:99
gmBody gm_body_create(double mass, double x, double y, double w, double h, gmColliderType c)
Creates a new physics body with specified properties.
Definition body.h:44
void gm_min_speed(gmBody *body, double min_speed)
Sets the minimum speed of a body.
Definition body.h:81
gmColliderType
Enum to define the type of collider for a physics body.
Definition body.h:11
@ GM_COLLIDER_RECT
Definition body.h:13
@ GM_COLLIDER_CIRCLE
Definition body.h:12
gmBody gm_circle_body(double m, double x, double y, double r)
Creates a circular physics body.
Definition body.h:212
int gm_body_contains(gmBody *body, double x, double y)
Checks if a point is contained within a body's collider.
Definition collision.h:89
void gm_min_speed_anim(gmBody *body, double min_speed, void animator(double *value, double target, double dt, double t), double dt, double t)
Sets the minimum speed of a body using an animation function.
Definition body.h:145
void gm_max_speed_anim(gmBody *body, double max_speed, void animator(double *value, double target, double dt, double t), double dt, double t)
Limits the maximum speed of a body using an animation function.
Definition body.h:123
struct _gmMouse gm_mouse
Definition gapi.h:19
Structure representing a physics body with properties for collision and movement.
Definition body.h:19
double width
Definition body.h:28
gmPos acceleration
Definition body.h:26
gmColliderType collider_type
Definition body.h:23
double height
Definition body.h:28
double friction
Definition body.h:31
double restitution
Definition body.h:30
uint8_t is_active
Definition body.h:20
double radius
Definition body.h:28
double mass
Definition body.h:29
gmPos velocity
Definition body.h:25
gmPos position
Definition body.h:24
uint8_t is_static
Definition body.h:21
Definition position.h:4
double x
Definition position.h:5
double y
Definition position.h:5