fix: input delay workaround
This commit is contained in:
@@ -37,11 +37,8 @@ static void launcher_handle_input(input_action_t action)
|
|||||||
if (action == INPUT_ACTION_CLICK) {
|
if (action == INPUT_ACTION_CLICK) {
|
||||||
s_launcher_selected = (s_launcher_selected + 1) % s_app_count;
|
s_launcher_selected = (s_launcher_selected + 1) % s_app_count;
|
||||||
} else if (action == INPUT_ACTION_DOUBLE_CLICK) {
|
} else if (action == INPUT_ACTION_DOUBLE_CLICK) {
|
||||||
if (s_launcher_selected == 0) {
|
/* Tap 1 already stepped +1; stepping -2 results in a net -1 (previous entry) */
|
||||||
s_launcher_selected = s_app_count - 1;
|
s_launcher_selected = (s_launcher_selected + s_app_count - 2) % s_app_count;
|
||||||
} else {
|
|
||||||
s_launcher_selected--;
|
|
||||||
}
|
|
||||||
} else if (action == INPUT_ACTION_LONG_PRESS) {
|
} else if (action == INPUT_ACTION_LONG_PRESS) {
|
||||||
sys_app_launch_by_index(s_launcher_selected);
|
sys_app_launch_by_index(s_launcher_selected);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,11 +7,10 @@
|
|||||||
|
|
||||||
static const char *TAG = "SYS_INPUT";
|
static const char *TAG = "SYS_INPUT";
|
||||||
|
|
||||||
#define DEBOUNCE_TIME_MS 25
|
#define DEBOUNCE_TIME_MS 12
|
||||||
#define CLICK_TIME_MAX_MS 350
|
#define DOUBLE_CLICK_GAP_MS 260
|
||||||
#define DOUBLE_CLICK_GAP_MS 280
|
#define LONG_PRESS_TIME_MS 380
|
||||||
#define LONG_PRESS_TIME_MS 450
|
#define HOME_PRESS_TIME_MS 1400
|
||||||
#define HOME_PRESS_TIME_MS 1500
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
sys_input_handler_t handler;
|
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)
|
static void button_scanner_task(void *pvParameters)
|
||||||
{
|
{
|
||||||
bool last_state = true;
|
bool last_state = false;
|
||||||
uint32_t press_start_ms = 0;
|
uint32_t press_start_ms = 0;
|
||||||
uint32_t release_time_ms = 0;
|
uint32_t last_click_time_ms = 0;
|
||||||
uint8_t click_count = 0;
|
|
||||||
bool long_press_fired = false;
|
bool long_press_fired = false;
|
||||||
bool home_press_fired = false;
|
bool home_press_fired = false;
|
||||||
|
|
||||||
while (1) {
|
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);
|
uint32_t now_ms = (uint32_t)(esp_timer_get_time() / 1000ULL);
|
||||||
bool current_state = (gpio_get_level(s_button_pin) == 0);
|
bool current_state = (gpio_get_level(s_button_pin) == 0);
|
||||||
|
|
||||||
if (current_state && !last_state) {
|
if (current_state && !last_state) {
|
||||||
|
// Button pressed down
|
||||||
press_start_ms = now_ms;
|
press_start_ms = now_ms;
|
||||||
long_press_fired = false;
|
long_press_fired = false;
|
||||||
home_press_fired = false;
|
home_press_fired = false;
|
||||||
} else if (current_state && last_state) {
|
} else if (current_state && last_state) {
|
||||||
|
// Button held down
|
||||||
uint32_t held_duration = now_ms - press_start_ms;
|
uint32_t held_duration = now_ms - press_start_ms;
|
||||||
if (!home_press_fired && held_duration >= HOME_PRESS_TIME_MS) {
|
if (!home_press_fired && held_duration >= HOME_PRESS_TIME_MS) {
|
||||||
home_press_fired = true;
|
home_press_fired = true;
|
||||||
click_count = 0;
|
|
||||||
dispatch_action(INPUT_ACTION_HOLD_HOME);
|
dispatch_action(INPUT_ACTION_HOLD_HOME);
|
||||||
} else if (!long_press_fired && !home_press_fired && held_duration >= LONG_PRESS_TIME_MS) {
|
} else if (!long_press_fired && !home_press_fired && held_duration >= LONG_PRESS_TIME_MS) {
|
||||||
long_press_fired = true;
|
long_press_fired = true;
|
||||||
click_count = 0;
|
|
||||||
dispatch_action(INPUT_ACTION_LONG_PRESS);
|
dispatch_action(INPUT_ACTION_LONG_PRESS);
|
||||||
}
|
}
|
||||||
} else if (!current_state && last_state) {
|
} else if (!current_state && last_state) {
|
||||||
|
// Button released
|
||||||
uint32_t press_duration = now_ms - press_start_ms;
|
uint32_t press_duration = now_ms - press_start_ms;
|
||||||
if (press_duration >= DEBOUNCE_TIME_MS && !long_press_fired && !home_press_fired) {
|
if (press_duration >= DEBOUNCE_TIME_MS && !long_press_fired && !home_press_fired) {
|
||||||
click_count++;
|
if ((now_ms - last_click_time_ms) <= DOUBLE_CLICK_GAP_MS) {
|
||||||
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) {
|
|
||||||
dispatch_action(INPUT_ACTION_DOUBLE_CLICK);
|
dispatch_action(INPUT_ACTION_DOUBLE_CLICK);
|
||||||
click_count = 0;
|
last_click_time_ms = 0;
|
||||||
} else if (idle_time >= DOUBLE_CLICK_GAP_MS) {
|
} else {
|
||||||
|
// Instant click dispatch upon tap release (no 280ms lag penalty!)
|
||||||
dispatch_action(INPUT_ACTION_CLICK);
|
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;
|
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;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|||||||
+40
-36
@@ -13,21 +13,27 @@ typedef enum {
|
|||||||
} game_state_t;
|
} game_state_t;
|
||||||
|
|
||||||
static game_state_t s_game_state = GAME_STATE_READY;
|
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 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 int16_t s_obs_h = 6;
|
||||||
static uint16_t s_score = 0;
|
static uint16_t s_score = 0;
|
||||||
static uint16_t s_high_score = 0;
|
static uint16_t s_high_score = 0;
|
||||||
|
|
||||||
static void game_reset(void)
|
static void game_reset(void)
|
||||||
{
|
{
|
||||||
s_player_y = GROUND_Y;
|
s_player_y_fp = TO_FP(GROUND_Y);
|
||||||
s_player_vy = 0;
|
s_player_vy_fp = 0;
|
||||||
s_is_jumping = false;
|
s_is_jumping = false;
|
||||||
s_obs_x = 72;
|
s_obs_x_fp = TO_FP(72);
|
||||||
s_obs_h = 5 + (rand() % 4);
|
s_obs_h = 5 + (rand() % 4);
|
||||||
s_score = 0;
|
s_score = 0;
|
||||||
}
|
}
|
||||||
@@ -58,45 +64,43 @@ static void game_update(uint32_t delta_ms)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (s_game_state == GAME_STATE_PLAYING) {
|
if (s_game_state == GAME_STATE_PLAYING) {
|
||||||
static uint32_t jump_acc = 0;
|
// 60 FPS Jump Physics
|
||||||
if (s_is_jumping) {
|
if (s_is_jumping) {
|
||||||
jump_acc += delta_ms;
|
s_player_y_fp += s_player_vy_fp;
|
||||||
if (jump_acc >= 45) {
|
s_player_vy_fp += 34; // Gravity per frame
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
static uint32_t move_acc = 0;
|
if (s_player_y_fp >= TO_FP(GROUND_Y)) {
|
||||||
move_acc += delta_ms;
|
s_player_y_fp = TO_FP(GROUND_Y);
|
||||||
if (move_acc >= 16) {
|
s_player_vy_fp = 0;
|
||||||
move_acc = 0;
|
s_is_jumping = false;
|
||||||
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_obs_x <= 13 && (s_obs_x + 3) >= 8) {
|
// 60 FPS Obstacle Movement (~70 px/sec)
|
||||||
if ((s_player_y - 1) >= (GROUND_Y - s_obs_h + 1)) {
|
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;
|
s_game_state = GAME_STATE_OVER;
|
||||||
sys_gfx_show_toast("GAME OVER", 800);
|
sys_gfx_show_toast("GAME OVER", 800);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sys_gfx_fill_rect(8, s_player_y - 5, 5, 5, COLOR_WHITE);
|
// Render Player and Obstacle
|
||||||
sys_gfx_fill_rect(s_obs_x, GROUND_Y - s_obs_h + 1, 3, s_obs_h, COLOR_WHITE);
|
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];
|
char score_str[12];
|
||||||
snprintf(score_str, sizeof(score_str), "SC:%u", s_score);
|
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) {
|
} else if (s_game_state == GAME_STATE_PLAYING) {
|
||||||
if (!s_is_jumping) {
|
if (!s_is_jumping) {
|
||||||
s_is_jumping = true;
|
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) {
|
} else if (s_game_state == GAME_STATE_OVER) {
|
||||||
s_game_state = GAME_STATE_PLAYING;
|
s_game_state = GAME_STATE_PLAYING;
|
||||||
|
|||||||
@@ -52,8 +52,8 @@ static void settings_handle_input(input_action_t action)
|
|||||||
if (action == INPUT_ACTION_CLICK) {
|
if (action == INPUT_ACTION_CLICK) {
|
||||||
s_selected_idx = (s_selected_idx + 1) % SETTINGS_COUNT;
|
s_selected_idx = (s_selected_idx + 1) % SETTINGS_COUNT;
|
||||||
} else if (action == INPUT_ACTION_DOUBLE_CLICK) {
|
} else if (action == INPUT_ACTION_DOUBLE_CLICK) {
|
||||||
if (s_selected_idx == 0) s_selected_idx = SETTINGS_COUNT - 1;
|
/* Tap 1 already stepped +1; stepping -2 results in a net -1 (previous entry) */
|
||||||
else s_selected_idx--;
|
s_selected_idx = (s_selected_idx + SETTINGS_COUNT - 2) % SETTINGS_COUNT;
|
||||||
} else if (action == INPUT_ACTION_LONG_PRESS) {
|
} else if (action == INPUT_ACTION_LONG_PRESS) {
|
||||||
switch (s_selected_idx) {
|
switch (s_selected_idx) {
|
||||||
case 0:
|
case 0:
|
||||||
|
|||||||
Reference in New Issue
Block a user