From 76bf6e81e59ef0929944ba6a079b48fd54f49978 Mon Sep 17 00:00:00 2001 From: Sara Date: Sun, 25 Jun 2023 12:41:53 +0200 Subject: [PATCH 1/7] reworked collision_t component into physics_t component --- src/corelib/object.c | 2 +- src/corelib/object.h | 3 +- src/corelib/physics.c | 100 +++++++++++++++++++++--------------------- src/corelib/physics.h | 20 +++++---- 4 files changed, 64 insertions(+), 61 deletions(-) diff --git a/src/corelib/object.c b/src/corelib/object.c index 5872c1e..5664fbc 100644 --- a/src/corelib/object.c +++ b/src/corelib/object.c @@ -4,7 +4,7 @@ object_t object_default() { return (object_t){ .active = 1, .enabled = 1, - .collider = collider_default(), + .physics = physics_default(), .evt_draw = &object_draw_sprite, .evt_update = NULL, .sprite = sprite_default(), diff --git a/src/corelib/object.h b/src/corelib/object.h index 2b8686a..9d26ab9 100644 --- a/src/corelib/object.h +++ b/src/corelib/object.h @@ -5,7 +5,6 @@ #include "physics.h" typedef struct object_t object_t; -typedef struct collider_t collider_t; typedef void(*tick_fn)(struct object_t*); typedef void(*draw_fn)(struct object_t*); @@ -14,7 +13,7 @@ struct object_t { sprite_t sprite; int active; // 1 if this object is in use and should not be overriden. int enabled; // 1 if this object's events should be triggered. - collider_t collider; // the collider to use for this object's physics interaction. + physics_t physics; // the collider to use for this object's physics interaction. uintptr_t timer; // free to use for whatever diff --git a/src/corelib/physics.c b/src/corelib/physics.c index 64df3ef..247d9cb 100644 --- a/src/corelib/physics.c +++ b/src/corelib/physics.c @@ -9,15 +9,17 @@ float fclampf(float x, float min_, float max_) { } -collider_t collider_default() { - return (collider_t) { - .type=COLLIDERTYPE_NONE +physics_t physics_default() { + return (physics_t) { + .type=COLLIDERTYPE_NONE, + .velocity_x = 0.f, + .velocity_y = 0.f }; } void object_broadcast_collision(object_t* this, object_t* other) { - if(this->collider.evt_collision != NULL) { - this->collider.evt_collision(this, other); + if(this->physics.evt_collision != NULL) { + this->physics.evt_collision(this, other); } } short can_collide(const object_t* this) { @@ -40,21 +42,21 @@ int _rect_overlap(float aminx, float aminy, float amaxx, float amaxy, float bmin static inline short _collision_aabb_aabb(const object_t* a, const object_t* b) { - const float aminx = a->collider.aabb.x + a->sprite.x, aminy = a->collider.aabb.y + a->sprite.x; - const float amaxx = aminx + a->collider.aabb.w, amaxy = aminy + a->collider.aabb.h; - const float bminx = b->collider.aabb.x, bminy = b->collider.aabb.y; - const float bmaxx = b->collider.aabb.x + b->collider.aabb.w, bmaxy = b->collider.aabb.y + b->collider.aabb.h; + const float aminx = a->physics.aabb.x + a->sprite.x, aminy = a->physics.aabb.y + a->sprite.x; + const float amaxx = aminx + a->physics.aabb.w, amaxy = aminy + a->physics.aabb.h; + const float bminx = b->physics.aabb.x, bminy = b->physics.aabb.y; + const float bmaxx = b->physics.aabb.x + b->physics.aabb.w, bmaxy = b->physics.aabb.y + b->physics.aabb.h; return _rect_overlap(aminx, aminy, amaxx, amaxy, bminx, bminy, bmaxx, bmaxy); } static inline short _collision_circle_circle(const object_t* a, const object_t* b) { - const float ax = a->sprite.x + a->collider.circle.x, ay = a->sprite.y + a->collider.circle.y, - bx = b->sprite.x + b->collider.circle.x, by = b->sprite.y + b->collider.circle.y; + const float ax = a->sprite.x + a->physics.circle.x, ay = a->sprite.y + a->physics.circle.y, + bx = b->sprite.x + b->physics.circle.x, by = b->sprite.y + b->physics.circle.y; const float dx = fabsf(ax-bx), dy = fabsf(ay-by); const float sqrdist = dx*dx+dy*dy; - const float mindist = a->collider.circle.radius + b->collider.circle.radius; + const float mindist = a->physics.circle.radius + b->physics.circle.radius; const float mindistsqr = mindist*mindist; return sqrdist < mindistsqr; } @@ -62,17 +64,17 @@ short _collision_circle_circle(const object_t* a, const object_t* b) { static inline short _collision_circle_aabb(const object_t* circle, const object_t* aabb) { // generate a point on the edge of the rectangle that is closest to the circle - const float bbminx = aabb->collider.aabb.x + aabb->sprite.x, bbmaxx = bbminx + aabb->collider.aabb.w, - bbminy = aabb->collider.aabb.y + aabb->sprite.y, bbmaxy = bbminy + aabb->collider.aabb.h; - const float cx = circle->sprite.x + circle->collider.circle.x, - cy = circle->sprite.y + circle->collider.circle.y; + const float bbminx = aabb->physics.aabb.x + aabb->sprite.x, bbmaxx = bbminx + aabb->physics.aabb.w, + bbminy = aabb->physics.aabb.y + aabb->sprite.y, bbmaxy = bbminy + aabb->physics.aabb.h; + const float cx = circle->sprite.x + circle->physics.circle.x, + cy = circle->sprite.y + circle->physics.circle.y; const float x = fclampf(cx, bbminx, bbmaxx), y = fclampf(cy, bbminy, bbmaxy); const float dx = fabsf(cx - x), dy = fabsf(cy - y); // calculate the square distance from the centre of the circle to the edge of the aabb const float distsqr = dx*dx+dy*dy; - const float rsqr = circle->collider.circle.radius*circle->collider.circle.radius; + const float rsqr = circle->physics.circle.radius*circle->physics.circle.radius; // return if the square distance is larger than the square of the radius return distsqr < rsqr; @@ -80,13 +82,13 @@ short _collision_circle_aabb(const object_t* circle, const object_t* aabb) { static inline short _collision_check(const object_t* a, const object_t* b) { - if(a->collider.type == COLLIDERTYPE_AABB && b->collider.type == COLLIDERTYPE_AABB) { + if(a->physics.type == COLLIDERTYPE_AABB && b->physics.type == COLLIDERTYPE_AABB) { return _collision_aabb_aabb(a, b); - } else if(a->collider.type == COLLIDERTYPE_CIRCLE && b->collider.type == COLLIDERTYPE_CIRCLE) { + } else if(a->physics.type == COLLIDERTYPE_CIRCLE && b->physics.type == COLLIDERTYPE_CIRCLE) { return _collision_circle_circle(a, b); - } else if(a->collider.type == COLLIDERTYPE_CIRCLE && b->collider.type == COLLIDERTYPE_AABB) { + } else if(a->physics.type == COLLIDERTYPE_CIRCLE && b->physics.type == COLLIDERTYPE_AABB) { return _collision_circle_aabb(a, b); - } else if(a->collider.type == COLLIDERTYPE_AABB && b->collider.type == COLLIDERTYPE_CIRCLE) { + } else if(a->physics.type == COLLIDERTYPE_AABB && b->physics.type == COLLIDERTYPE_CIRCLE) { return _collision_circle_aabb(b, a); } return 0; @@ -95,11 +97,11 @@ short _collision_check(const object_t* a, const object_t* b) { static inline float _solve_circle_aabb(const object_t* circle, const object_t* aabb, float* out_px, float* out_py) { // generate a point on the edge of the rectangle that is closest to the circle - const float bbminx = aabb->collider.aabb.x + aabb->sprite.x, bbmaxx = bbminx + aabb->collider.aabb.w, - bbminy = aabb->collider.aabb.y + aabb->sprite.y, bbmaxy = bbminy + aabb->collider.aabb.h; + const float bbminx = aabb->physics.aabb.x + aabb->sprite.x, bbmaxx = bbminx + aabb->physics.aabb.w, + bbminy = aabb->physics.aabb.y + aabb->sprite.y, bbmaxy = bbminy + aabb->physics.aabb.h; // the centre of the circle in world space - const float cx = circle->sprite.x + circle->collider.circle.x, - cy = circle->sprite.y + circle->collider.circle.y; + const float cx = circle->sprite.x + circle->physics.circle.x, + cy = circle->sprite.y + circle->physics.circle.y; // the point on the rectangle closest to the centre of the circle const float x = fclampf(cx, bbminx, bbmaxx), y = fclampf(cy, bbminy, bbmaxy); @@ -111,7 +113,7 @@ float _solve_circle_aabb(const object_t* circle, const object_t* aabb, float* ou dist_y = fabsf(dif_y); // euclidean distance const float dist = sqrt(dist_x*dist_x + dist_y*dist_y); - const float solve_distance = circle->collider.circle.radius - dist; + const float solve_distance = circle->physics.circle.radius - dist; // distance to solve collision float solve_x, solve_y; normalize(dif_x, dif_y, &solve_x, &solve_y); @@ -122,11 +124,11 @@ float _solve_circle_aabb(const object_t* circle, const object_t* aabb, float* ou static inline float _solve_circle_circle(const object_t* a, const object_t* b, float* out_px, float* out_py) { - const float x1 = a->collider.circle.x + a->sprite.x, y1 = a->collider.circle.y + a->sprite.y; - const float x2 = b->collider.circle.x + b->sprite.x, y2 = b->collider.circle.y + b->sprite.y; + const float x1 = a->physics.circle.x + a->sprite.x, y1 = a->physics.circle.y + a->sprite.y; + const float x2 = b->physics.circle.x + b->sprite.x, y2 = b->physics.circle.y + b->sprite.y; const float dif_x = x1 - x2, dif_y = y1 - y2; const float difference = sqrtf(fabsf(dif_x*dif_x) + fabsf(dif_y*dif_y)); - const float target_difference = a->collider.circle.radius + b->collider.circle.radius; + const float target_difference = a->physics.circle.radius + b->physics.circle.radius; float dir_x, dir_y; normalize(dif_x, dif_y, &dir_x, &dir_y); *out_px = dir_x * target_difference; @@ -136,10 +138,10 @@ float _solve_circle_circle(const object_t* a, const object_t* b, float* out_px, static inline float _solve_aabb_aabb(const object_t* a, const object_t* b, float* out_px, float* out_py) { - float right = (a->collider.aabb.x + a->collider.aabb.w + a->sprite.x) - (b->collider.aabb.x + b->sprite.x); - float left = (a->collider.aabb.x + a->sprite.x) - (b->collider.aabb.x + b->collider.aabb.w + b->sprite.x); - float top = (a->collider.aabb.y + a->sprite.y) - (b->collider.aabb.y + b->collider.aabb.w + b->sprite.y); - float bottom = (a->collider.aabb.y + a->collider.aabb.h) - (b->collider.aabb.y + b->sprite.y); + float right = (a->physics.aabb.x + a->physics.aabb.w + a->sprite.x) - (b->physics.aabb.x + b->sprite.x); + float left = (a->physics.aabb.x + a->sprite.x) - (b->physics.aabb.x + b->physics.aabb.w + b->sprite.x); + float top = (a->physics.aabb.y + a->sprite.y) - (b->physics.aabb.y + b->physics.aabb.w + b->sprite.y); + float bottom = (a->physics.aabb.y + a->physics.aabb.h) - (b->physics.aabb.y + b->sprite.y); float ret = right; *out_px = right; @@ -165,15 +167,15 @@ float _solve_aabb_aabb(const object_t* a, const object_t* b, float* out_px, floa } float get_solve_force(const object_t* a, const object_t* b, float* out_px, float* out_py) { - if(a->collider.type == COLLIDERTYPE_AABB && b->collider.type == COLLIDERTYPE_AABB) { + if(a->physics.type == COLLIDERTYPE_AABB && b->physics.type == COLLIDERTYPE_AABB) { return _solve_aabb_aabb(a, b, out_px, out_py); - } else if(a->collider.type == COLLIDERTYPE_AABB && b->collider.type == COLLIDERTYPE_CIRCLE) { + } else if(a->physics.type == COLLIDERTYPE_AABB && b->physics.type == COLLIDERTYPE_CIRCLE) { float penetration_distance = _solve_circle_aabb(b, a, out_px, out_py); *out_px = -(*out_px); *out_py = -(*out_py); - } else if(a->collider.type == COLLIDERTYPE_CIRCLE && b->collider.type == COLLIDERTYPE_AABB) { + } else if(a->physics.type == COLLIDERTYPE_CIRCLE && b->physics.type == COLLIDERTYPE_AABB) { return _solve_circle_aabb(a, b, out_px, out_py); - } else if(a->collider.type == COLLIDERTYPE_CIRCLE && b->collider.type == COLLIDERTYPE_CIRCLE) { + } else if(a->physics.type == COLLIDERTYPE_CIRCLE && b->physics.type == COLLIDERTYPE_CIRCLE) { return _solve_circle_circle(a, b, out_px, out_py); } } @@ -201,17 +203,21 @@ void _solve_move(object_t* this) { } } -void interpolate_move(object_t* this, const float target_x, const float target_y, const float max_step_size, const int slide) { +void move_and_slide(object_t* this, float delta_time) { + const float max_step_size = this->physics.max_interpolate_step_size; // calculate step delta - float dx = target_x - this->sprite.x, dy = target_y - this->sprite.y; + float dx = this->physics.velocity_x * delta_time, dy = this->physics.velocity_y * delta_time; + const float target_x = this->sprite.x + dx, + target_y = this->sprite.y + dy; if(dx == 0 && dy == 0) return; + // calculate direction x,y float m = sqrtf(dx*dx + dy*dy); - dx /= m; - dy /= m; - dx *= max_step_size; dy *= max_step_size; - int step_count = max_step_size / m; + dx = dx / m * max_step_size; + dy = dy / m * max_step_size; + + const int step_count = max_step_size / m; // ensure this object would ever collide // if it wouldn't collide anyway, just set position @@ -225,6 +231,7 @@ void interpolate_move(object_t* this, const float target_x, const float target_y this->sprite.x = target_x; this->sprite.y = target_y; _solve_move(this); + return; } /* @@ -233,21 +240,14 @@ void interpolate_move(object_t* this, const float target_x, const float target_y */ for(int steps = 0; steps <= step_count && (this->sprite.x != target_x || this->sprite.y != target_y); ++steps) { // move towards target, snap to target if distance is too low - const float old_x = this->sprite.x, old_y = this->sprite.y; - float new_x, new_y; - const float distx = fabsf(this->sprite.x - target_x), disty = fabsf(this->sprite.y - target_y); const float sqdist = distx*distx + disty*disty; if(sqdist > max_step_size*max_step_size) { this->sprite.x += dx; this->sprite.y += dy; - new_x = this->sprite.x; - new_y = this->sprite.y; } else { this->sprite.x = target_x; this->sprite.y = target_y; - new_x = target_x; - new_y = target_y; } _solve_move(this); diff --git a/src/corelib/physics.h b/src/corelib/physics.h index 93e145c..f8313d7 100644 --- a/src/corelib/physics.h +++ b/src/corelib/physics.h @@ -15,25 +15,29 @@ typedef enum collider_type_t { COLLIDERTYPE_MAX, } collider_type_t; -typedef struct collider_t { +typedef struct circle_t { + float x, y; + float radius; +} circle_t; + +typedef struct physics_t { collider_type_t type; collided_fn evt_collision; + float velocity_x, velocity_y; + float max_interpolate_step_size; union { - struct { - float x, y; - float radius; - } circle; + circle_t circle; SDL_FRect aabb; }; -} collider_t; +} physics_t; -collider_t collider_default(); +physics_t physics_default(); void object_broadcast_evt_collision(object_t* this, object_t* other); void physics_update(); -void interpolate_move(object_t* object, float target_x, float target_y, float max_step_size, int slide); +void move_and_slide(object_t* this, float delta_time); extern short can_collide(const object_t* this); extern float get_solve_force(const object_t* this, const object_t* other, float* solve_x, float* solve_y); -- 2.34.1 From 7a2cb3cd5ca1e165e946fa5af648c0595971f949 Mon Sep 17 00:00:00 2001 From: Sara Date: Sun, 25 Jun 2023 18:12:38 +0200 Subject: [PATCH 2/7] added solver field to physics_t, exposed solve_collision_slide to make it work --- src/corelib/physics.c | 11 +++++++---- src/corelib/physics.h | 4 ++++ 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/corelib/physics.c b/src/corelib/physics.c index 247d9cb..46fa8d0 100644 --- a/src/corelib/physics.c +++ b/src/corelib/physics.c @@ -13,7 +13,8 @@ physics_t physics_default() { return (physics_t) { .type=COLLIDERTYPE_NONE, .velocity_x = 0.f, - .velocity_y = 0.f + .velocity_y = 0.f, + .solver = &solve_collision_slide }; } @@ -180,12 +181,14 @@ float get_solve_force(const object_t* a, const object_t* b, float* out_px, float } } -static inline -void _solve_collision_slide(object_t* this, object_t* other) { +void solve_collision_slide(object_t* left, object_t* right) { float dx, dy; const float d = get_solve_force(this, other, &dx, &dy); this->sprite.x += dx; this->sprite.y += dy; + const float d = get_solve_force(left, right, &dx, &dy); + left->sprite.x += dx; + right->sprite.y += dy; } static inline @@ -198,7 +201,7 @@ void _solve_move(object_t* this) { if(can_collide(other) && this != other && _collision_check(other, this)) { object_broadcast_collision(other, this); object_broadcast_collision(this, other); - _solve_collision_slide(this, other); + this->physics.solver(this, other); } } } diff --git a/src/corelib/physics.h b/src/corelib/physics.h index f8313d7..2b71a2c 100644 --- a/src/corelib/physics.h +++ b/src/corelib/physics.h @@ -6,6 +6,8 @@ typedef struct object_t object_t; typedef void(*collided_fn)(object_t*, struct object_t*); +typedef void(*collided_fn)(object_t*, object_t*); +typedef void(*solver_fn)(object_t* left, object_t* right); typedef enum collider_type_t { COLLIDERTYPE_MIN, @@ -23,6 +25,7 @@ typedef struct circle_t { typedef struct physics_t { collider_type_t type; collided_fn evt_collision; + solver_fn solver; float velocity_x, velocity_y; float max_interpolate_step_size; union { @@ -40,6 +43,7 @@ void physics_update(); void move_and_slide(object_t* this, float delta_time); extern short can_collide(const object_t* this); +extern void solve_collision_slide(object_t* left, object_t* right); extern float get_solve_force(const object_t* this, const object_t* other, float* solve_x, float* solve_y); #endif /* _physics_h */ -- 2.34.1 From ead22d114c0f60d2276eaa3aa34bb03f063e942a Mon Sep 17 00:00:00 2001 From: Sara Date: Sun, 25 Jun 2023 18:13:12 +0200 Subject: [PATCH 3/7] added explicit extern specifiers to physics functions lacking them --- src/corelib/physics.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/corelib/physics.h b/src/corelib/physics.h index 2b71a2c..6ea5630 100644 --- a/src/corelib/physics.h +++ b/src/corelib/physics.h @@ -5,7 +5,6 @@ typedef struct object_t object_t; -typedef void(*collided_fn)(object_t*, struct object_t*); typedef void(*collided_fn)(object_t*, object_t*); typedef void(*solver_fn)(object_t* left, object_t* right); @@ -34,15 +33,16 @@ typedef struct physics_t { }; } physics_t; -physics_t physics_default(); +extern physics_t physics_default(); -void object_broadcast_evt_collision(object_t* this, object_t* other); +extern void object_broadcast_evt_collision(object_t* this, object_t* other); -void physics_update(); +extern void physics_update(); void move_and_slide(object_t* this, float delta_time); extern short can_collide(const object_t* this); + extern void solve_collision_slide(object_t* left, object_t* right); extern float get_solve_force(const object_t* this, const object_t* other, float* solve_x, float* solve_y); -- 2.34.1 From 812e7eab20e687e0cf1264d05bb94297aec90ed2 Mon Sep 17 00:00:00 2001 From: Sara Date: Sun, 25 Jun 2023 18:13:28 +0200 Subject: [PATCH 4/7] renamed move_and_slide to physics_move --- src/corelib/physics.c | 2 +- src/corelib/physics.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/corelib/physics.c b/src/corelib/physics.c index 46fa8d0..817d802 100644 --- a/src/corelib/physics.c +++ b/src/corelib/physics.c @@ -206,7 +206,7 @@ void _solve_move(object_t* this) { } } -void move_and_slide(object_t* this, float delta_time) { +void physics_move(object_t* this, float delta_time) { const float max_step_size = this->physics.max_interpolate_step_size; // calculate step delta float dx = this->physics.velocity_x * delta_time, dy = this->physics.velocity_y * delta_time; diff --git a/src/corelib/physics.h b/src/corelib/physics.h index 6ea5630..5a00e40 100644 --- a/src/corelib/physics.h +++ b/src/corelib/physics.h @@ -39,7 +39,7 @@ extern void object_broadcast_evt_collision(object_t* this, object_t* other); extern void physics_update(); -void move_and_slide(object_t* this, float delta_time); +extern void physics_move(object_t* this, float delta_time); extern short can_collide(const object_t* this); -- 2.34.1 From 9a732ad82f4f3471b625bee8113d283c73f9a0e8 Mon Sep 17 00:00:00 2001 From: Sara Date: Sun, 25 Jun 2023 18:13:48 +0200 Subject: [PATCH 5/7] simplified solve_collision_slide --- src/corelib/physics.c | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/corelib/physics.c b/src/corelib/physics.c index 817d802..f289606 100644 --- a/src/corelib/physics.c +++ b/src/corelib/physics.c @@ -183,9 +183,6 @@ float get_solve_force(const object_t* a, const object_t* b, float* out_px, float void solve_collision_slide(object_t* left, object_t* right) { float dx, dy; - const float d = get_solve_force(this, other, &dx, &dy); - this->sprite.x += dx; - this->sprite.y += dy; const float d = get_solve_force(left, right, &dx, &dy); left->sprite.x += dx; right->sprite.y += dy; -- 2.34.1 From 20ca626acfe4ba6fd614d7e6b25381aea25d645a Mon Sep 17 00:00:00 2001 From: Sara Date: Sun, 25 Jun 2023 18:16:17 +0200 Subject: [PATCH 6/7] solve_collision_slide no longer modifies rhs argument --- src/corelib/physics.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/physics.c b/src/corelib/physics.c index f289606..001348c 100644 --- a/src/corelib/physics.c +++ b/src/corelib/physics.c @@ -185,7 +185,7 @@ void solve_collision_slide(object_t* left, object_t* right) { float dx, dy; const float d = get_solve_force(left, right, &dx, &dy); left->sprite.x += dx; - right->sprite.y += dy; + left->sprite.y += dy; } static inline -- 2.34.1 From 484db1961ab7b75e7fcf062fa0ac0497b7ebf8bb Mon Sep 17 00:00:00 2001 From: Sara Date: Mon, 26 Jun 2023 17:24:57 +0200 Subject: [PATCH 7/7] reformatting some lines in CMakeLists --- CMakeLists.txt | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 330f641..4d9b887 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -17,14 +17,17 @@ find_package(SDL2) find_package(SDL2_image) find_package(SDL2_ttf) -file(GLOB_RECURSE +file( + GLOB_RECURSE SOURCE_C "${CMAKE_SOURCE_DIR}/src/**.c") -file(GLOB_RECURSE +file( + GLOB_RECURSE SOURCE_CPP "${CMAKE_SOURCE_DIR}/src/**.c*") -add_executable(${PROJECT} +add_executable( + ${PROJECT} ${SOURCE_C} ${SOURCE_CPP}) -- 2.34.1