From 81e242532bd3d24a5f818954f9e012456c6a2ec6 Mon Sep 17 00:00:00 2001 From: Sara Date: Sun, 18 Jun 2023 14:08:55 +0200 Subject: [PATCH 01/22] added argument to interpolate_move, removed return value from interpolate_move --- src/corelib/world.c | 8 ++++---- src/corelib/world.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/corelib/world.c b/src/corelib/world.c index 85fbed4..8a063e9 100644 --- a/src/corelib/world.c +++ b/src/corelib/world.c @@ -166,7 +166,7 @@ void update_collision() { } } -object_t* interpolate_move(object_t* object, float target_x, float target_y, float max_step_size) { +void interpolate_move(object_t* object, float target_x, float target_y, float max_step_size, int slide) { // calculate step delta float dx = target_x - object->sprite.x, dy = target_y - object->sprite.y; // calculate direction x,y @@ -179,7 +179,7 @@ object_t* interpolate_move(object_t* object, float target_x, float target_y, flo if(!_can_collide(object)) { object->sprite.x = target_x; object->sprite.y = target_y; - return NULL; + return; } /* @@ -208,11 +208,11 @@ object_t* interpolate_move(object_t* object, float target_x, float target_y, flo object_broadcast_collision(object, other); object->sprite.x = old_x; object->sprite.y = old_y; - return other; + return; } } } // no collision, return nothing - return NULL; + return; } diff --git a/src/corelib/world.h b/src/corelib/world.h index 2c57f31..27de091 100644 --- a/src/corelib/world.h +++ b/src/corelib/world.h @@ -62,6 +62,6 @@ void draw_objects(); void update_collision(); -object_t* interpolate_move(object_t* object, float target_x, float target_y, float max_step_size); +void interpolate_move(object_t* object, float target_x, float target_y, float max_step_size, int slide); #endif /* _world_h */ -- 2.34.1 From 0a8aac2325e0256cd31557eba268fa29e76d1c73 Mon Sep 17 00:00:00 2001 From: Sara Date: Sun, 18 Jun 2023 14:18:37 +0200 Subject: [PATCH 02/22] implemented slide --- src/corelib/world.c | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/src/corelib/world.c b/src/corelib/world.c index 8a063e9..57c64f1 100644 --- a/src/corelib/world.c +++ b/src/corelib/world.c @@ -189,13 +189,14 @@ void interpolate_move(object_t* object, float target_x, float target_y, float ma while(object->sprite.x != target_x || object->sprite.y != target_y) { // move towards target, snap to target if distance is too low const float old_x = object->sprite.x, old_y = object->sprite.y; + float new_x, new_y; const float distx = fabsf(object->sprite.x - target_x), disty = fabsf(object->sprite.y - target_y); if(distx < fabsf(dx) && disty < fabsf(dy)) { - object->sprite.x += dx; - object->sprite.y += dy; + new_x = object->sprite.x += dx; + new_y = object->sprite.y += dy; } else { - object->sprite.x = target_x; - object->sprite.y = target_y; + new_x = object->sprite.x = target_x; + new_y = object->sprite.y = target_y; } // loop over all objects and check collision if applicable @@ -206,9 +207,20 @@ void interpolate_move(object_t* object, float target_x, float target_y, float ma if(_can_collide(other) && object != other && _collision_check(other, object)) { object_broadcast_collision(other, object); object_broadcast_collision(object, other); - object->sprite.x = old_x; - object->sprite.y = old_y; - return; + if(slide) { + object->sprite.x = old_x; + if(_collision_check(other, object)) { + object->sprite.x = new_x; + } + object->sprite.y = old_y; + if(_collision_check(other, object)) { + object->sprite.y = new_y; + } + } else { + object->sprite.x = old_x; + object->sprite.y = old_y; + return; + } } } } -- 2.34.1 From dff8e8304dec4a60ebd388ddc5810b5afab036db Mon Sep 17 00:00:00 2001 From: Sara Date: Sun, 18 Jun 2023 14:24:38 +0200 Subject: [PATCH 03/22] iteration count for interpolate_move now based on number of steps required to fullfill move in theory --- src/corelib/world.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/corelib/world.c b/src/corelib/world.c index 57c64f1..4545b1e 100644 --- a/src/corelib/world.c +++ b/src/corelib/world.c @@ -173,6 +173,7 @@ void interpolate_move(object_t* object, float target_x, float target_y, float ma 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; // ensure this object would ever collide // if it wouldn't collide anyway, just set position @@ -186,7 +187,7 @@ void interpolate_move(object_t* object, float target_x, float target_y, float ma * 1. move towards target * 2. check collision with every other object */ - while(object->sprite.x != target_x || object->sprite.y != target_y) { + for(int steps = 0; steps < step_count; ++steps) { // move towards target, snap to target if distance is too low const float old_x = object->sprite.x, old_y = object->sprite.y; float new_x, new_y; -- 2.34.1 From ea3beddfec7ea1cabcd13ff1cb8348f03e829530 Mon Sep 17 00:00:00 2001 From: Sara Date: Sun, 18 Jun 2023 14:27:24 +0200 Subject: [PATCH 04/22] inverted correction collision_check --- src/corelib/world.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/corelib/world.c b/src/corelib/world.c index 4545b1e..fc15d77 100644 --- a/src/corelib/world.c +++ b/src/corelib/world.c @@ -210,11 +210,11 @@ void interpolate_move(object_t* object, float target_x, float target_y, float ma object_broadcast_collision(object, other); if(slide) { object->sprite.x = old_x; - if(_collision_check(other, object)) { + if(!_collision_check(other, object)) { object->sprite.x = new_x; } object->sprite.y = old_y; - if(_collision_check(other, object)) { + if(!_collision_check(other, object)) { object->sprite.y = new_y; } } else { -- 2.34.1 From fa2a9117321b6e6c1d6c04caeb82da088679fea5 Mon Sep 17 00:00:00 2001 From: Sara Date: Sun, 18 Jun 2023 14:39:04 +0200 Subject: [PATCH 05/22] added corelib/math/vec.h single header vector math library --- src/corelib/math/vec.h | 43 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 src/corelib/math/vec.h diff --git a/src/corelib/math/vec.h b/src/corelib/math/vec.h new file mode 100644 index 0000000..07aef07 --- /dev/null +++ b/src/corelib/math/vec.h @@ -0,0 +1,43 @@ +#ifndef _vec_math_h +#define _vec_math_h + +#include "math.h" + +static inline +void clamp_magnitude(float* xx, float* yy, float max_magnitude) { + float x = *xx, y = *yy; + const float m = sqrtf(x*x + y*y); + if(m > max_magnitude) { + x /= m; y /= m; + x *= max_magnitude; y *= max_magnitude; + } + *xx = x; *yy = y; +} + +static inline +void normalize(float* xx, float* yy) { + float x = *xx, y = *yy; + if(x != 0 && y != 0) { + const float m = sqrtf(x*x + y*y); + x /= m; y /= m; + *xx = x; *yy = y; + } +} + +static inline +int move_towards(float* out_x, float* out_y, float x, float y, float tx, float ty, float max_delta) { + const float diff_x = tx - x, diff_y = ty - y; + const float m = sqrtf(diff_x*diff_x + diff_y*diff_y); + const float dir_x = diff_x / m * max_delta, dir_y = diff_y / m * max_delta; + if(dir_x < diff_x && dir_y < diff_y) { + *out_x = x + dir_x; + *out_y = y + dir_y; + return 0; + } else { + *out_x = tx; + *out_y = ty; + return 1; + } +} + +#endif /* _vec_math_h */ -- 2.34.1 From 1df623e6695d7447bb312b7a67c6e6093ed30006 Mon Sep 17 00:00:00 2001 From: Sara Date: Sun, 18 Jun 2023 16:09:43 +0200 Subject: [PATCH 06/22] move_towards now compares absolutes of diff and dir to check if the destination will be reached --- src/corelib/math/vec.h | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/corelib/math/vec.h b/src/corelib/math/vec.h index 07aef07..a98452f 100644 --- a/src/corelib/math/vec.h +++ b/src/corelib/math/vec.h @@ -26,10 +26,12 @@ void normalize(float* xx, float* yy) { static inline int move_towards(float* out_x, float* out_y, float x, float y, float tx, float ty, float max_delta) { - const float diff_x = tx - x, diff_y = ty - y; + const float diff_x = tx - x, + diff_y = ty - y; const float m = sqrtf(diff_x*diff_x + diff_y*diff_y); - const float dir_x = diff_x / m * max_delta, dir_y = diff_y / m * max_delta; - if(dir_x < diff_x && dir_y < diff_y) { + const float dir_x = diff_x / m * max_delta, + dir_y = diff_y / m * max_delta; + if(fabsf(dir_x) < fabsf(diff_x) && fabsf(dir_y) < fabsf(diff_y)) { *out_x = x + dir_x; *out_y = y + dir_y; return 0; -- 2.34.1 From 494dbfedb3d79907208176edbf152ff618192d15 Mon Sep 17 00:00:00 2001 From: Sara Date: Sun, 18 Jun 2023 16:14:30 +0200 Subject: [PATCH 07/22] clamp_magnitude no longer outputs input x,y regardless of checks --- src/corelib/math/vec.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/corelib/math/vec.h b/src/corelib/math/vec.h index a98452f..601e6c4 100644 --- a/src/corelib/math/vec.h +++ b/src/corelib/math/vec.h @@ -10,8 +10,9 @@ void clamp_magnitude(float* xx, float* yy, float max_magnitude) { if(m > max_magnitude) { x /= m; y /= m; x *= max_magnitude; y *= max_magnitude; + } else { + *xx = x; *yy = y; } - *xx = x; *yy = y; } static inline -- 2.34.1 From 6f78731d8fc0b5b7e2539fa902421eeab241f764 Mon Sep 17 00:00:00 2001 From: Sara Date: Sun, 18 Jun 2023 16:33:39 +0200 Subject: [PATCH 08/22] normalize will now normalize if either x or y is non-zero previously 100,0 would return 100,0 instead of 1,0 --- src/corelib/math/vec.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/corelib/math/vec.h b/src/corelib/math/vec.h index 601e6c4..9a62b93 100644 --- a/src/corelib/math/vec.h +++ b/src/corelib/math/vec.h @@ -18,7 +18,7 @@ void clamp_magnitude(float* xx, float* yy, float max_magnitude) { static inline void normalize(float* xx, float* yy) { float x = *xx, y = *yy; - if(x != 0 && y != 0) { + if(x != 0 || y != 0) { const float m = sqrtf(x*x + y*y); x /= m; y /= m; *xx = x; *yy = y; -- 2.34.1 From fcb9645dbe17e8c5cf08769b73be56107541c95c Mon Sep 17 00:00:00 2001 From: Sara Date: Sun, 18 Jun 2023 16:34:28 +0200 Subject: [PATCH 09/22] added NORMALIZE #define macro avoids pointers and the accompanying dereference operations of normalize(...) --- src/corelib/math/vec.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/corelib/math/vec.h b/src/corelib/math/vec.h index 9a62b93..1129da3 100644 --- a/src/corelib/math/vec.h +++ b/src/corelib/math/vec.h @@ -25,6 +25,14 @@ void normalize(float* xx, float* yy) { } } +#define NORMALIZE(_xx, _yy) \ +if(_xx != 0 || _yy != 0) { \ + const float m = sqrtf(_xx*_xx + _yy*_yy); \ + _xx /= m; _yy /= m; \ +} else { \ + _xx = 0; _yy = 0; \ +} + static inline int move_towards(float* out_x, float* out_y, float x, float y, float tx, float ty, float max_delta) { const float diff_x = tx - x, -- 2.34.1 From d69b92a46414bde0c9ea3a20778c033befb3028f Mon Sep 17 00:00:00 2001 From: Sara Date: Sun, 18 Jun 2023 17:59:50 +0200 Subject: [PATCH 10/22] delta_time is now calculating by converting timespec to seconds --- src/engine.c | 22 +++++++++++++++++++--- src/engine.h | 2 ++ 2 files changed, 21 insertions(+), 3 deletions(-) diff --git a/src/engine.c b/src/engine.c index 8d61289..3c146a2 100644 --- a/src/engine.c +++ b/src/engine.c @@ -5,11 +5,27 @@ #include "corelib/input.h" #include "time.h" -static float _delta_time = 0; +static double _delta_time = 0; +static double _min_frame_interval = 0; static struct timespec start_last_frame; +#define CURRENT_TIME(__out) { struct timespect ts; timespec_get(&ts, TIME_UTC); __out = ts.tv_sec + tv.nsec * 1E-09; } + +inline static +double timespec_to_sec(struct timespec spec) { + return spec.tv_sec + spec.tv_nsec; +} + inline float delta_time() { - return _delta_time; + return (float)_delta_time; +} + +void set_frame_interval(double frame_interval) { + _min_frame_interval = frame_interval; +} + +void set_frame_rate_limit(int fps) { + _min_frame_interval = 1.0/(double)fps; } static inline @@ -58,7 +74,7 @@ int _engine_run() { struct timespec next_time; while(g_context.running) { timespec_get(&next_time, TIME_UTC); - _delta_time = (next_time.tv_nsec - start_last_frame.tv_nsec) * 1E-9; + _delta_time = timespec_to_sec(next_time) - timespec_to_sec(start_last_frame); if(next_time.tv_nsec < start_last_frame.tv_nsec) _delta_time = 0; start_last_frame = next_time; _handle_events(); diff --git a/src/engine.h b/src/engine.h index 87bf672..8667836 100644 --- a/src/engine.h +++ b/src/engine.h @@ -6,6 +6,8 @@ extern "C" { #endif extern float delta_time(); +extern void set_frame_interval(double frame_interval); +extern void set_frame_rate_limit(int fps); /* TO BE DEFINED IN GAME */ -- 2.34.1 From 56679110e303e78ed20e0466460121177cbea34c Mon Sep 17 00:00:00 2001 From: Sara Date: Sun, 18 Jun 2023 18:02:22 +0200 Subject: [PATCH 11/22] added frame limiting --- src/engine.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/engine.c b/src/engine.c index 3c146a2..6e460dd 100644 --- a/src/engine.c +++ b/src/engine.c @@ -86,6 +86,11 @@ int _engine_run() { update_objects(); // update world objects draw_objects(); // draw world objects swap_buffer(); + + while(_delta_time < _min_frame_interval) { + timespec_get(&next_time, TIME_UTC); + _delta_time = timespec_to_sec(next_time) - timespec_to_sec(start_last_frame); + } } return 0; } -- 2.34.1 From a49ac0db93bcc3fe554b7a625e4275c38788a533 Mon Sep 17 00:00:00 2001 From: Sara Date: Sun, 18 Jun 2023 18:04:49 +0200 Subject: [PATCH 12/22] timespec_to_sec now first multiplies tv_nsec by 1E-09 to convert to seconds --- src/engine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine.c b/src/engine.c index 6e460dd..a8ab0a2 100644 --- a/src/engine.c +++ b/src/engine.c @@ -13,7 +13,7 @@ static struct timespec start_last_frame; inline static double timespec_to_sec(struct timespec spec) { - return spec.tv_sec + spec.tv_nsec; + return spec.tv_sec + spec.tv_nsec * 1E-09f; } inline float delta_time() { -- 2.34.1 From b30df338ace2512c0ecb7f16075d775cf27f25e4 Mon Sep 17 00:00:00 2001 From: Sara Date: Sun, 18 Jun 2023 19:04:22 +0200 Subject: [PATCH 13/22] no longer zeroing _delta_time if nanosecond element of difference between last and next time is negative --- src/engine.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/engine.c b/src/engine.c index a8ab0a2..515ab9c 100644 --- a/src/engine.c +++ b/src/engine.c @@ -75,7 +75,6 @@ int _engine_run() { while(g_context.running) { timespec_get(&next_time, TIME_UTC); _delta_time = timespec_to_sec(next_time) - timespec_to_sec(start_last_frame); - if(next_time.tv_nsec < start_last_frame.tv_nsec) _delta_time = 0; start_last_frame = next_time; _handle_events(); update_input(); -- 2.34.1 From a93d09c96cf3e72e4962d004a4a416f5e2e15a10 Mon Sep 17 00:00:00 2001 From: Sara Date: Sun, 18 Jun 2023 22:14:16 +0200 Subject: [PATCH 14/22] reworked most input listener types to use OS events instead of checking state on update this allows for them to be more reliable with low framerates --- src/corelib/input.c | 93 +++++++++++++++++++++++---------------------- 1 file changed, 47 insertions(+), 46 deletions(-) diff --git a/src/corelib/input.c b/src/corelib/input.c index d4b5bf7..571de49 100644 --- a/src/corelib/input.c +++ b/src/corelib/input.c @@ -70,21 +70,6 @@ void input_init() { g_key_states = SDL_GetKeyboardState(NULL); } -static inline -void _process_axis_listener(input_listener_t* listener) { - int val = 0; - if(g_key_states[listener->axis.negative]) { - val = -1; - } - if(g_key_states[listener->axis.positive]) { - val += 1; - } - if(val != listener->axis.last) { - listener->axis.last = val; - listener->axis.delegate(val); - } -} - static inline void _process_mouse_listener(input_listener_t* listener, float dx, float dy) { if(dx != 0.0 && dy != 0.0) { @@ -92,23 +77,6 @@ void _process_mouse_listener(input_listener_t* listener, float dx, float dy) { } } -static inline -void _process_button_listener(input_listener_t* listener) { - uint32_t state = SDL_GetMouseState(NULL, NULL); - int is_down = (state & (listener->button.button)) != 0; - if(is_down != listener->button.last) { - listener->button.delegate(is_down); - } - listener->button.last = is_down; -} - -static inline -void _process_scroll_listener(input_listener_t* listener) { - if(_scroll_delta != 0) { - listener->scroll.delegate(_scroll_delta); - } -} - void update_input() { float dx, dy; int px, py; @@ -118,19 +86,8 @@ void update_input() { dx = (float)(px - _last_mouse_x)/width; dy = (float)(py - _last_mouse_y)/width; for(input_listener_t* listener = g_key_listeners; listener != g_key_listeners_endptr; ++listener) { - switch(listener->type) { - case INPUT_LISTENER_AXIS: - _process_axis_listener(listener); - break; - case INPUT_LISTENER_MOUSE: + if(listener->type == INPUT_LISTENER_MOUSE) { _process_mouse_listener(listener, dx, dy); - break; - case INPUT_LISTENER_SCROLL: - _process_scroll_listener(listener); - break; - case INPUT_LISTENER_BUTTON: - _process_button_listener(listener); - break; } } @@ -140,13 +97,57 @@ void update_input() { _scroll_delta = 0; } +static inline +void _handle_key_event(const SDL_Event event) { + for(input_listener_t* listener = g_key_listeners; listener < g_key_listeners_endptr; ++listener) { + if(listener->type == INPUT_LISTENER_AXIS) { + if(listener->axis.positive == event.key.keysym.scancode + || listener->axis.negative == event.key.keysym.scancode) { + const SDL_Scancode scode = event.key.keysym.scancode; + const int value = (event.type == SDL_KEYDOWN ? 1 : -1) * (scode == listener->axis.negative ? -1 : 1); + listener->axis.last += value; + listener->axis.delegate(listener->axis.last); + } + } + } +} + +static inline +void _handle_scroll_event(const SDL_Event event) { + _scroll_delta = event.wheel.y; + for(input_listener_t* listener = g_key_listeners; listener < g_key_listeners_endptr; ++listener) { + if(listener->type == INPUT_LISTENER_SCROLL) { + listener->scroll.delegate(_scroll_delta); + } + } +} + +static inline +void _handle_mousebutton_event(const SDL_Event event) { + for(input_listener_t* listener = g_key_listeners; listener < g_key_listeners_endptr; ++listener) { + if(listener->type == INPUT_LISTENER_BUTTON + || listener->button.button == event.button.button) { + listener->button.last = event.button.state == SDL_PRESSED; + listener->button.delegate(listener->button.last); + } + } +} + void input_notify_event(SDL_Event event) { switch(event.type) { default: return; + case SDL_KEYUP: + case SDL_KEYDOWN: + _handle_key_event(event); + return; case SDL_MOUSEWHEEL: - _scroll_delta = event.wheel.y; - break; + _handle_scroll_event(event); + return; + case SDL_MOUSEBUTTONUP: + case SDL_MOUSEBUTTONDOWN: + _handle_mousebutton_event(event); + return; } } -- 2.34.1 From 14b8b2f380e14a673295c49f5711b59d22a8977a Mon Sep 17 00:00:00 2001 From: Sara Date: Sun, 18 Jun 2023 22:17:06 +0200 Subject: [PATCH 15/22] delta time is now updated before evaluating minimum delta time/ --- src/engine.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/engine.c b/src/engine.c index 515ab9c..110dc9d 100644 --- a/src/engine.c +++ b/src/engine.c @@ -85,11 +85,10 @@ int _engine_run() { update_objects(); // update world objects draw_objects(); // draw world objects swap_buffer(); - - while(_delta_time < _min_frame_interval) { + do { timespec_get(&next_time, TIME_UTC); _delta_time = timespec_to_sec(next_time) - timespec_to_sec(start_last_frame); - } + } while(_delta_time < _min_frame_interval); } return 0; } -- 2.34.1 From fc1f3499e325e4c53cc7fac623bd3f78d8724bf3 Mon Sep 17 00:00:00 2001 From: Sara Date: Sun, 18 Jun 2023 22:17:25 +0200 Subject: [PATCH 16/22] input events are now still pumped during frame downtime --- src/engine.c | 1 + 1 file changed, 1 insertion(+) diff --git a/src/engine.c b/src/engine.c index 110dc9d..8b63ab2 100644 --- a/src/engine.c +++ b/src/engine.c @@ -88,6 +88,7 @@ int _engine_run() { do { timespec_get(&next_time, TIME_UTC); _delta_time = timespec_to_sec(next_time) - timespec_to_sec(start_last_frame); + SDL_PumpEvents(); } while(_delta_time < _min_frame_interval); } return 0; -- 2.34.1 From cfcd31cee8093e1d315b626c13c12a8e410e36a1 Mon Sep 17 00:00:00 2001 From: Sara Date: Sun, 18 Jun 2023 22:17:38 +0200 Subject: [PATCH 17/22] more explicit typing and casting in timespec_to_sec --- src/engine.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine.c b/src/engine.c index 8b63ab2..8a5d514 100644 --- a/src/engine.c +++ b/src/engine.c @@ -13,7 +13,7 @@ static struct timespec start_last_frame; inline static double timespec_to_sec(struct timespec spec) { - return spec.tv_sec + spec.tv_nsec * 1E-09f; + return (double)spec.tv_sec + (double)spec.tv_nsec * 1E-09; } inline float delta_time() { -- 2.34.1 From fab7338891394c08f30eeb1cedc268ebed1478b2 Mon Sep 17 00:00:00 2001 From: Sara Date: Sun, 18 Jun 2023 22:22:16 +0200 Subject: [PATCH 18/22] axis now keeps a history for both keys --- src/corelib/input.c | 16 +++++++++------- src/corelib/input.h | 2 +- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/corelib/input.c b/src/corelib/input.c index 571de49..df5c666 100644 --- a/src/corelib/input.c +++ b/src/corelib/input.c @@ -23,7 +23,8 @@ void add_key_listener(SDL_Scancode negative, SDL_Scancode positive, g_key_listeners_endptr->axis.delegate = delegate; g_key_listeners_endptr->axis.positive = positive; g_key_listeners_endptr->axis.negative = negative; - g_key_listeners_endptr->axis.last = 0; + g_key_listeners_endptr->axis.last_positive = + g_key_listeners_endptr->axis.last_negative = 0; ++g_key_listeners_endptr; } @@ -101,13 +102,14 @@ static inline void _handle_key_event(const SDL_Event event) { for(input_listener_t* listener = g_key_listeners; listener < g_key_listeners_endptr; ++listener) { if(listener->type == INPUT_LISTENER_AXIS) { - if(listener->axis.positive == event.key.keysym.scancode - || listener->axis.negative == event.key.keysym.scancode) { - const SDL_Scancode scode = event.key.keysym.scancode; - const int value = (event.type == SDL_KEYDOWN ? 1 : -1) * (scode == listener->axis.negative ? -1 : 1); - listener->axis.last += value; - listener->axis.delegate(listener->axis.last); + const SDL_Scancode scode = event.key.keysym.scancode; + if(listener->axis.positive == scode) { + listener->axis.last_positive = event.key.state == SDL_PRESSED; } + if(listener->axis.negative == scode) { + listener->axis.last_negative = event.key.state == SDL_PRESSED; + } + listener->axis.delegate(listener->axis.last_positive - listener->axis.last_negative); } } } diff --git a/src/corelib/input.h b/src/corelib/input.h index 85d3cc8..9be54d6 100644 --- a/src/corelib/input.h +++ b/src/corelib/input.h @@ -25,7 +25,7 @@ typedef struct input_listener_t { struct { input_axis_delegate_t delegate; SDL_Scancode positive, negative; - int last; + int last_positive, last_negative; } axis; struct { input_mouse_delegate_t delegate; -- 2.34.1 From 3df374b3b9cfd47f5a973288e4de27c5348a3fd2 Mon Sep 17 00:00:00 2001 From: Sara Date: Sun, 18 Jun 2023 22:45:06 +0200 Subject: [PATCH 19/22] interpolate move will now immediately stop if destination is reached --- src/corelib/world.c | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/corelib/world.c b/src/corelib/world.c index fc15d77..5ed847b 100644 --- a/src/corelib/world.c +++ b/src/corelib/world.c @@ -171,7 +171,10 @@ void interpolate_move(object_t* object, float target_x, float target_y, float ma float dx = target_x - object->sprite.x, dy = target_y - object->sprite.y; // calculate direction x,y float m = sqrtf(dx*dx + dy*dy); - dx /= m; dy /= m; + if(dx != 0) + dx /= m; + if(dy != 0) + dy /= m; dx *= max_step_size; dy *= max_step_size; int step_count = max_step_size / m; @@ -187,7 +190,7 @@ void interpolate_move(object_t* object, float target_x, float target_y, float ma * 1. move towards target * 2. check collision with every other object */ - for(int steps = 0; steps < step_count; ++steps) { + for(int steps = 0; steps < step_count && (object->sprite.x != target_x || object->sprite.y != target_y); ++steps) { // move towards target, snap to target if distance is too low const float old_x = object->sprite.x, old_y = object->sprite.y; float new_x, new_y; -- 2.34.1 From daa53c6ef0537d884b529f117fe66998657d34f8 Mon Sep 17 00:00:00 2001 From: Sara Date: Sat, 24 Jun 2023 20:32:31 +0200 Subject: [PATCH 20/22] movetowards now also works in cases where x == 0 && y != 0 || x != 0 && y == 0 --- src/corelib/math/vec.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/corelib/math/vec.h b/src/corelib/math/vec.h index 1129da3..082c589 100644 --- a/src/corelib/math/vec.h +++ b/src/corelib/math/vec.h @@ -16,11 +16,11 @@ void clamp_magnitude(float* xx, float* yy, float max_magnitude) { } static inline -void normalize(float* xx, float* yy) { - float x = *xx, y = *yy; +void normalize(float x, float y, float* xx, float* yy) { if(x != 0 || y != 0) { const float m = sqrtf(x*x + y*y); - x /= m; y /= m; + *xx = x / m; *yy = y / m; + } else { *xx = x; *yy = y; } } @@ -40,7 +40,7 @@ int move_towards(float* out_x, float* out_y, float x, float y, float tx, float t const float m = sqrtf(diff_x*diff_x + diff_y*diff_y); const float dir_x = diff_x / m * max_delta, dir_y = diff_y / m * max_delta; - if(fabsf(dir_x) < fabsf(diff_x) && fabsf(dir_y) < fabsf(diff_y)) { + if(fabsf(dir_x) < fabsf(diff_x) || fabsf(dir_y) < fabsf(diff_y)) { *out_x = x + dir_x; *out_y = y + dir_y; return 0; -- 2.34.1 From 4271ee8f8d1d090fbc12f39d6919c7d761041245 Mon Sep 17 00:00:00 2001 From: Sara Date: Sat, 24 Jun 2023 20:32:54 +0200 Subject: [PATCH 21/22] fully implemented slide collision for any combination of aabb and circle colliders --- src/corelib/world.c | 143 +++++++++++++++++++++++++++++++++++++++----- 1 file changed, 128 insertions(+), 15 deletions(-) diff --git a/src/corelib/world.c b/src/corelib/world.c index 5ed847b..1a33db3 100644 --- a/src/corelib/world.c +++ b/src/corelib/world.c @@ -1,4 +1,5 @@ #include "world.h" +#include "math/vec.h" object_t g_objects[WORLD_NUM_OBJECTS]; @@ -106,6 +107,93 @@ float fclampf(float x, float min_, float max_) { return fminf(max_, fmaxf(min_, x)); } +static inline +float _circle_aabb_overlap(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; + // 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; + // the point on the rectangle closest to the centre of the circle + const float x = fclampf(cx, bbminx, bbmaxx), + y = fclampf(cy, bbminy, bbmaxy); + // the relative position of the point on the rectangle + const float dif_x = cx - x, + dif_y = cy - y; + // absolute difference for use in calculating euclidean distance + const float dist_x = fabsf(dif_x), + 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; + // distance to solve collision + float solve_x, solve_y; + normalize(dif_x, dif_y, &solve_x, &solve_y); + *out_px = solve_x * solve_distance; + *out_py = solve_y * solve_distance; + return solve_distance; +} + +static inline +float _circle_circle_overlap(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 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; + float dir_x, dir_y; + normalize(dif_x, dif_y, &dir_x, &dir_y); + *out_px = dir_x * target_difference; + *out_py = dir_y * target_difference; + return target_difference; +} + +static inline +float _aabb_aabb_overlap(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 ret = right; + *out_px = right; + *out_py = 0.f; + if(fabsf(left) < fabsf(ret)) { + *out_px = left; + *out_py = 0.f; + ret = left; + } + if(fabsf(top) < fabsf(ret)) { + *out_px = 0.f; + *out_py = top; + ret = top; + } + + if(fabsf(bottom) < fabsf(ret)) { + *out_px = 0.f; + *out_py = bottom; + return bottom; + } + + return ret; +} + +static inline +float _get_overlap(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) { + return _aabb_aabb_overlap(a, b, out_px, out_py); + } else if(a->collider.type == COLLIDERTYPE_AABB && b->collider.type == COLLIDERTYPE_CIRCLE) { + float penetration_distance = _circle_aabb_overlap(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) { + return _circle_aabb_overlap(a, b, out_px, out_py); + } else if(a->collider.type == COLLIDERTYPE_CIRCLE && b->collider.type == COLLIDERTYPE_CIRCLE) { + return _circle_circle_overlap(a, b, out_px, out_py); + } +} + 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 @@ -166,9 +254,40 @@ void update_collision() { } } -void interpolate_move(object_t* object, float target_x, float target_y, float max_step_size, int slide) { +static inline +void _slide_collision(object_t* this, object_t* other, float old_x, float old_y, float new_x, float new_y) { + float dx, dy; + const float d = _get_overlap(this, other, &dx, &dy); + this->sprite.x += dx; + this->sprite.y += dy; + printf("collision solving step: %f %f, distance: %f\n", dx, dy, d); + printf("collision solved, resulting position: %f, %f\n", this->sprite.x, this->sprite.y); + + return; + this->sprite.x = old_x; + this->sprite.y = new_y; + if(!_collision_check(other, this)) { + return; + } + + this->sprite.x = new_x; + this->sprite.y = old_y; + if(!_collision_check(other, this)) { + return; + } + + this->sprite.x = old_x; + this->sprite.y = old_y; + if(!_collision_check(other, this)) { + return; + } +} + +void interpolate_move(object_t* object, const float target_x, const float target_y, const float max_step_size, const int slide) { // calculate step delta float dx = target_x - object->sprite.x, dy = target_y - object->sprite.y; + if(dx == 0 && dy == 0) + return; // calculate direction x,y float m = sqrtf(dx*dx + dy*dy); if(dx != 0) @@ -194,10 +313,14 @@ void interpolate_move(object_t* object, float target_x, float target_y, float ma // move towards target, snap to target if distance is too low const float old_x = object->sprite.x, old_y = object->sprite.y; float new_x, new_y; + const float distx = fabsf(object->sprite.x - target_x), disty = fabsf(object->sprite.y - target_y); - if(distx < fabsf(dx) && disty < fabsf(dy)) { - new_x = object->sprite.x += dx; - new_y = object->sprite.y += dy; + const float sqdist = distx*distx + disty*disty; + if(sqdist > max_step_size) { + object->sprite.x += dx; + object->sprite.y += dy; + new_x = object->sprite.x; + new_y = object->sprite.y; } else { new_x = object->sprite.x = target_x; new_y = object->sprite.y = target_y; @@ -212,14 +335,7 @@ void interpolate_move(object_t* object, float target_x, float target_y, float ma object_broadcast_collision(other, object); object_broadcast_collision(object, other); if(slide) { - object->sprite.x = old_x; - if(!_collision_check(other, object)) { - object->sprite.x = new_x; - } - object->sprite.y = old_y; - if(!_collision_check(other, object)) { - object->sprite.y = new_y; - } + _slide_collision(object, other, old_x, old_y, new_x, new_y); } else { object->sprite.x = old_x; object->sprite.y = old_y; @@ -228,7 +344,4 @@ void interpolate_move(object_t* object, float target_x, float target_y, float ma } } } - - // no collision, return nothing - return; } -- 2.34.1 From 43fa322409fb158ce9288cd5f0db0cfb1a0f24d4 Mon Sep 17 00:00:00 2001 From: Sara Date: Sat, 24 Jun 2023 20:34:35 +0200 Subject: [PATCH 22/22] removed debug prints from _slide_collision solver --- src/corelib/world.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/corelib/world.c b/src/corelib/world.c index 1a33db3..a46e6bc 100644 --- a/src/corelib/world.c +++ b/src/corelib/world.c @@ -260,8 +260,6 @@ void _slide_collision(object_t* this, object_t* other, float old_x, float old_y, const float d = _get_overlap(this, other, &dx, &dy); this->sprite.x += dx; this->sprite.y += dy; - printf("collision solving step: %f %f, distance: %f\n", dx, dy, d); - printf("collision solved, resulting position: %f, %f\n", this->sprite.x, this->sprite.y); return; this->sprite.x = old_x; -- 2.34.1