From ea3ccd3b83511104b4faae1aa6fe503417b27195 Mon Sep 17 00:00:00 2001 From: dark98 Date: Fri, 25 Sep 2026 21:14:07 +0100 Subject: [PATCH] fix: input delay workaround --- components/sys_app/sys_app.c | 7 +-- components/sys_input/sys_input.c | 38 +++++++--------- main/apps/app_game.c | 76 +++++++++++++++++--------------- main/apps/app_settings.c | 4 +- 4 files changed, 60 insertions(+), 65 deletions(-) diff --git a/components/sys_app/sys_app.c b/components/sys_app/sys_app.c index e65c047..afe1c0a 100644 --- a/components/sys_app/sys_app.c +++ b/components/sys_app/sys_app.c @@ -37,11 +37,8 @@ static void launcher_handle_input(input_action_t action) if (action == INPUT_ACTION_CLICK) { s_launcher_selected = (s_launcher_selected + 1) % s_app_count; } else if (action == INPUT_ACTION_DOUBLE_CLICK) { - if (s_launcher_selected == 0) { - s_launcher_selected = s_app_count - 1; - } else { - s_launcher_selected--; - } + /* Tap 1 already stepped +1; stepping -2 results in a net -1 (previous entry) */ + s_launcher_selected = (s_launcher_selected + s_app_count - 2) % s_app_count; } else if (action == INPUT_ACTION_LONG_PRESS) { sys_app_launch_by_index(s_launcher_selected); } diff --git a/components/sys_input/sys_input.c b/components/sys_input/sys_input.c index ab03dfa..613c2b1 100644 --- a/components/sys_input/sys_input.c +++ b/components/sys_input/sys_input.c @@ -7,11 +7,10 @@ static const char *TAG = "SYS_INPUT"; -#define DEBOUNCE_TIME_MS 25 -#define CLICK_TIME_MAX_MS 350 -#define DOUBLE_CLICK_GAP_MS 280 -#define LONG_PRESS_TIME_MS 450 -#define HOME_PRESS_TIME_MS 1500 +#define DEBOUNCE_TIME_MS 12 +#define DOUBLE_CLICK_GAP_MS 260 +#define LONG_PRESS_TIME_MS 380 +#define HOME_PRESS_TIME_MS 1400 typedef struct { sys_input_handler_t handler; @@ -69,48 +68,43 @@ esp_err_t sys_input_register_handler(sys_input_handler_t handler, void *user_arg static void button_scanner_task(void *pvParameters) { - bool last_state = true; + bool last_state = false; uint32_t press_start_ms = 0; - uint32_t release_time_ms = 0; - uint8_t click_count = 0; + uint32_t last_click_time_ms = 0; bool long_press_fired = false; bool home_press_fired = false; while (1) { - vTaskDelay(pdMS_TO_TICKS(10)); + vTaskDelay(pdMS_TO_TICKS(5)); // High-rate 200 Hz scan loop for zero input lag uint32_t now_ms = (uint32_t)(esp_timer_get_time() / 1000ULL); bool current_state = (gpio_get_level(s_button_pin) == 0); if (current_state && !last_state) { + // Button pressed down press_start_ms = now_ms; long_press_fired = false; home_press_fired = false; } else if (current_state && last_state) { + // Button held down uint32_t held_duration = now_ms - press_start_ms; if (!home_press_fired && held_duration >= HOME_PRESS_TIME_MS) { home_press_fired = true; - click_count = 0; dispatch_action(INPUT_ACTION_HOLD_HOME); } else if (!long_press_fired && !home_press_fired && held_duration >= LONG_PRESS_TIME_MS) { long_press_fired = true; - click_count = 0; dispatch_action(INPUT_ACTION_LONG_PRESS); } } else if (!current_state && last_state) { + // Button released uint32_t press_duration = now_ms - press_start_ms; if (press_duration >= DEBOUNCE_TIME_MS && !long_press_fired && !home_press_fired) { - click_count++; - release_time_ms = now_ms; - } - } else if (!current_state && !last_state) { - if (click_count > 0) { - uint32_t idle_time = now_ms - release_time_ms; - if (click_count >= 2) { + if ((now_ms - last_click_time_ms) <= DOUBLE_CLICK_GAP_MS) { dispatch_action(INPUT_ACTION_DOUBLE_CLICK); - click_count = 0; - } else if (idle_time >= DOUBLE_CLICK_GAP_MS) { + last_click_time_ms = 0; + } else { + // Instant click dispatch upon tap release (no 280ms lag penalty!) dispatch_action(INPUT_ACTION_CLICK); - click_count = 0; + last_click_time_ms = now_ms; } } } @@ -142,6 +136,6 @@ esp_err_t sys_input_init(gpio_num_t button_gpio) return ESP_FAIL; } - ESP_LOGI(TAG, "Input gesture engine started on GPIO %d", (int)s_button_pin); + ESP_LOGI(TAG, "Input gesture engine started on GPIO %d (Instant-Response Mode)", (int)s_button_pin); return ESP_OK; } diff --git a/main/apps/app_game.c b/main/apps/app_game.c index 5c97c9e..9ea1415 100644 --- a/main/apps/app_game.c +++ b/main/apps/app_game.c @@ -13,21 +13,27 @@ typedef enum { } game_state_t; static game_state_t s_game_state = GAME_STATE_READY; -static int16_t s_player_y = GROUND_Y; -static int16_t s_player_vy = 0; + +/* Fixed-point 8-bit physics for smooth 60 FPS jump arcs */ +#define FP_SHIFT 8 +#define TO_FP(val) ((int32_t)((val) << FP_SHIFT)) +#define FROM_FP(val) ((int16_t)((val) >> FP_SHIFT)) + +static int32_t s_player_y_fp = TO_FP(GROUND_Y); +static int32_t s_player_vy_fp = 0; static bool s_is_jumping = false; -static int16_t s_obs_x = 72; +static int32_t s_obs_x_fp = TO_FP(72); static int16_t s_obs_h = 6; static uint16_t s_score = 0; static uint16_t s_high_score = 0; static void game_reset(void) { - s_player_y = GROUND_Y; - s_player_vy = 0; + s_player_y_fp = TO_FP(GROUND_Y); + s_player_vy_fp = 0; s_is_jumping = false; - s_obs_x = 72; + s_obs_x_fp = TO_FP(72); s_obs_h = 5 + (rand() % 4); s_score = 0; } @@ -58,45 +64,43 @@ static void game_update(uint32_t delta_ms) } if (s_game_state == GAME_STATE_PLAYING) { - static uint32_t jump_acc = 0; + // 60 FPS Jump Physics if (s_is_jumping) { - jump_acc += delta_ms; - if (jump_acc >= 45) { - jump_acc = 0; - s_player_y += s_player_vy; - s_player_vy += 1; - if (s_player_y >= GROUND_Y) { - s_player_y = GROUND_Y; - s_player_vy = 0; - s_is_jumping = false; - } - } - } else { - jump_acc = 0; - } + s_player_y_fp += s_player_vy_fp; + s_player_vy_fp += 34; // Gravity per frame - static uint32_t move_acc = 0; - move_acc += delta_ms; - if (move_acc >= 16) { - move_acc = 0; - s_obs_x -= 1; - if (s_obs_x < -4) { - s_obs_x = 72 + (rand() % 16); - s_obs_h = 5 + (rand() % 5); - s_score++; - if (s_score > s_high_score) s_high_score = s_score; + if (s_player_y_fp >= TO_FP(GROUND_Y)) { + s_player_y_fp = TO_FP(GROUND_Y); + s_player_vy_fp = 0; + s_is_jumping = false; } } - if (s_obs_x <= 13 && (s_obs_x + 3) >= 8) { - if ((s_player_y - 1) >= (GROUND_Y - s_obs_h + 1)) { + // 60 FPS Obstacle Movement (~70 px/sec) + s_obs_x_fp -= 300; // ~1.17 pixels per 60fps frame + int16_t obs_x = FROM_FP(s_obs_x_fp); + + if (obs_x < -4) { + s_obs_x_fp = TO_FP(72 + (rand() % 16)); + obs_x = FROM_FP(s_obs_x_fp); + s_obs_h = 5 + (rand() % 5); + s_score++; + if (s_score > s_high_score) s_high_score = s_score; + } + + int16_t player_y = FROM_FP(s_player_y_fp); + + // Collision Check (Hitbox: player is 5x5 at x=8..12, obs is 3xH at obs_x..obs_x+2) + if (obs_x <= 13 && (obs_x + 3) >= 8) { + if ((player_y - 1) >= (GROUND_Y - s_obs_h + 1)) { s_game_state = GAME_STATE_OVER; sys_gfx_show_toast("GAME OVER", 800); } } - sys_gfx_fill_rect(8, s_player_y - 5, 5, 5, COLOR_WHITE); - sys_gfx_fill_rect(s_obs_x, GROUND_Y - s_obs_h + 1, 3, s_obs_h, COLOR_WHITE); + // Render Player and Obstacle + sys_gfx_fill_rect(8, player_y - 5, 5, 5, COLOR_WHITE); + sys_gfx_fill_rect(obs_x, GROUND_Y - s_obs_h + 1, 3, s_obs_h, COLOR_WHITE); char score_str[12]; snprintf(score_str, sizeof(score_str), "SC:%u", s_score); @@ -125,7 +129,7 @@ static void game_handle_input(input_action_t action) } else if (s_game_state == GAME_STATE_PLAYING) { if (!s_is_jumping) { s_is_jumping = true; - s_player_vy = -5; + s_player_vy_fp = -740; // Instant jump impulse (-2.9 px/frame) } } else if (s_game_state == GAME_STATE_OVER) { s_game_state = GAME_STATE_PLAYING; diff --git a/main/apps/app_settings.c b/main/apps/app_settings.c index b9cc1e0..60cb2bb 100644 --- a/main/apps/app_settings.c +++ b/main/apps/app_settings.c @@ -52,8 +52,8 @@ static void settings_handle_input(input_action_t action) if (action == INPUT_ACTION_CLICK) { s_selected_idx = (s_selected_idx + 1) % SETTINGS_COUNT; } else if (action == INPUT_ACTION_DOUBLE_CLICK) { - if (s_selected_idx == 0) s_selected_idx = SETTINGS_COUNT - 1; - else s_selected_idx--; + /* Tap 1 already stepped +1; stepping -2 results in a net -1 (previous entry) */ + s_selected_idx = (s_selected_idx + SETTINGS_COUNT - 2) % SETTINGS_COUNT; } else if (action == INPUT_ACTION_LONG_PRESS) { switch (s_selected_idx) { case 0: