diff --git a/engine/engine.c b/engine/engine.c index 51e3868..e22d56b 100644 --- a/engine/engine.c +++ b/engine/engine.c @@ -17,6 +17,7 @@ void init_engine(GameEngine_t* engine, Vector2 starting_win_size) engine->intended_window_size = starting_win_size; InitWindow(starting_win_size.x, starting_win_size.y, "raylib"); engine->base_canvas = LoadRenderTexture(starting_win_size.x, starting_win_size.y); + engine->last_input_key = KEY_NULL; } void deinit_engine(GameEngine_t* engine) @@ -49,22 +50,32 @@ int get_keybind_or_default(GameEngine_t* engine, ActionType_t action, int defaul void process_inputs(GameEngine_t* engine, Scene_t* scene) { + engine->last_input_key = KEY_NULL; Vector2 raw_mouse_pos = GetMousePosition(); scene->mouse_pos = raw_mouse_pos; + // For flexibility, key that are not mapped to an action are still recorded + // pay a little performance to do two checks. + unsigned int sz = sc_queue_size(&engine->key_buffer); // Process any existing pressed key for (size_t i = 0; i < sz; i++) { int button = sc_queue_del_first(&engine->key_buffer); - ActionType_t action = sc_map_get_64(&scene->action_map, button); - if (IsKeyReleased(button)) + bool pressed = !IsKeyReleased(button); + if (!pressed) { - do_action(scene, action, false); + engine->last_input_key = button; } - else + + ActionType_t action = sc_map_get_64(&scene->action_map, button); + if (sc_map_found(&scene->action_map)) + { + do_action(scene, action, pressed); + } + + if (pressed) { - do_action(scene, action, true); sc_queue_add_last(&engine->key_buffer, button); } } @@ -75,8 +86,10 @@ void process_inputs(GameEngine_t* engine, Scene_t* scene) int button = GetKeyPressed(); if (button == 0) break; ActionType_t action = sc_map_get_64(&scene->action_map, button); - if (!sc_map_found(&scene->action_map)) continue; - do_action(scene, action, true); + if (sc_map_found(&scene->action_map)) + { + do_action(scene, action, true); + } sc_queue_add_last(&engine->key_buffer, button); } diff --git a/engine/engine.h b/engine/engine.h index fd5327d..63d5e49 100644 --- a/engine/engine.h +++ b/engine/engine.h @@ -40,6 +40,9 @@ typedef struct GameEngine { // an absolute reference Vector2 intended_window_size; RenderTexture2D base_canvas; + + // ad-hoc addition. Next version should be a configurable key buffer + int last_input_key; } GameEngine_t; #define SCENE_ACTIVE_BIT (1 << 0) // Systems Active diff --git a/scenes/options_scene.c b/scenes/options_scene.c index 14ad728..74cc4b3 100644 --- a/scenes/options_scene.c +++ b/scenes/options_scene.c @@ -90,12 +90,56 @@ static void options_scene_render_func(Scene_t* scene) DrawText("Cancel", 32, y_offset, 12, WHITE); y_offset += 12; line++; + + if (data->mode == OPTIONS_KEYBIND_MODE) + { + y_offset += 36; + DrawText("Press a Key...", 32, y_offset, 12, WHITE); + } EndTextureMode(); } +static void wait_for_keymap_input(Scene_t* scene) +{ + /** + * Due to engine design limitation, I canot remove + * the system when placed into the array + * So, this will have to run as part of the loop + * Even though it is only used in a particular mode + * It's a small performance penalty for unfortunate design + */ + + OptionSceneData_t* data = &(CONTAINER_OF(scene, OptionScene_t, scene)->data); + if (data->mode == OPTIONS_NORMAL_MODE) + { + return; + } + + if (data->mode == OPTIONS_KEYBIND_READY_MODE) + { + // Keys are processed before system Update + // Need to skip the current frame to get the next key + // This state is to do just that. + data->mode = OPTIONS_KEYBIND_MODE; + return; + } + + if (scene->engine->last_input_key == KEY_NULL) + { + return; + } + + printf("Key inputted: %d\n", scene->engine->last_input_key); + + data->keybinds_info.elems[data->curr_selection - 1].key = scene->engine->last_input_key; + data->keybinds_info.elems[data->curr_selection - 1].key_name = ExtGetKeyName(scene->engine->last_input_key); + data->mode = OPTIONS_NORMAL_MODE; +} + static void exec_component_function(Scene_t* scene, uint16_t sel) { + OptionSceneData_t* data = &(CONTAINER_OF(scene, OptionScene_t, scene)->data); printf("Sel: %u\n", sel); if (sel == 0) { @@ -116,9 +160,8 @@ static void exec_component_function(Scene_t* scene, uint16_t sel) } else { - // Keybind options - // TODO: This should change the scene mode - // Engine need to record last key released + // Keybind options, but need to wait one frame + data->mode = OPTIONS_KEYBIND_READY_MODE; } } @@ -173,7 +216,7 @@ static void options_do_action(Scene_t* scene, ActionType_t action, bool pressed) } } break; - case OPTIONS_KEYBIND_MODE: + default: break; } } @@ -219,6 +262,7 @@ void init_options_scene(OptionScene_t* scene) // The number of actions that can be key-binds is constant. // So can just init once. + sc_array_add(&scene->scene.systems, &wait_for_keymap_input); sc_array_add(&scene->scene.systems, &options_scene_render_func); sc_map_put_64(&scene->scene.action_map, get_keybind_or_default(scene->scene.engine, ACTION_UP, KEY_UP), ACTION_UP); diff --git a/scenes/scene_impl.h b/scenes/scene_impl.h index 5ad5ac2..93a1c30 100644 --- a/scenes/scene_impl.h +++ b/scenes/scene_impl.h @@ -137,6 +137,7 @@ typedef struct LevelSelectScene { typedef enum OptionSceneMode { OPTIONS_NORMAL_MODE, + OPTIONS_KEYBIND_READY_MODE, OPTIONS_KEYBIND_MODE, }OptionSceneMode_t;