Implement key recording for rebind

Changelog:
- Update engine to record last key released
- Update option scene to get the last key pressed for binding
    - Does not actually change the keybind yet
main
En Yi 2025-08-22 21:23:54 +08:00
parent 5c3428da56
commit 16de3bb70e
4 changed files with 72 additions and 11 deletions

View File

@ -17,6 +17,7 @@ void init_engine(GameEngine_t* engine, Vector2 starting_win_size)
engine->intended_window_size = starting_win_size; engine->intended_window_size = starting_win_size;
InitWindow(starting_win_size.x, starting_win_size.y, "raylib"); InitWindow(starting_win_size.x, starting_win_size.y, "raylib");
engine->base_canvas = LoadRenderTexture(starting_win_size.x, starting_win_size.y); engine->base_canvas = LoadRenderTexture(starting_win_size.x, starting_win_size.y);
engine->last_input_key = KEY_NULL;
} }
void deinit_engine(GameEngine_t* engine) 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) void process_inputs(GameEngine_t* engine, Scene_t* scene)
{ {
engine->last_input_key = KEY_NULL;
Vector2 raw_mouse_pos = GetMousePosition(); Vector2 raw_mouse_pos = GetMousePosition();
scene->mouse_pos = raw_mouse_pos; 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); unsigned int sz = sc_queue_size(&engine->key_buffer);
// Process any existing pressed key // Process any existing pressed key
for (size_t i = 0; i < sz; i++) for (size_t i = 0; i < sz; i++)
{ {
int button = sc_queue_del_first(&engine->key_buffer); int button = sc_queue_del_first(&engine->key_buffer);
ActionType_t action = sc_map_get_64(&scene->action_map, button); bool pressed = !IsKeyReleased(button);
if (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); sc_queue_add_last(&engine->key_buffer, button);
} }
} }
@ -75,8 +86,10 @@ void process_inputs(GameEngine_t* engine, Scene_t* scene)
int button = GetKeyPressed(); int button = GetKeyPressed();
if (button == 0) break; if (button == 0) break;
ActionType_t action = sc_map_get_64(&scene->action_map, button); ActionType_t action = sc_map_get_64(&scene->action_map, button);
if (!sc_map_found(&scene->action_map)) continue; if (sc_map_found(&scene->action_map))
{
do_action(scene, action, true); do_action(scene, action, true);
}
sc_queue_add_last(&engine->key_buffer, button); sc_queue_add_last(&engine->key_buffer, button);
} }

View File

@ -40,6 +40,9 @@ typedef struct GameEngine {
// an absolute reference // an absolute reference
Vector2 intended_window_size; Vector2 intended_window_size;
RenderTexture2D base_canvas; RenderTexture2D base_canvas;
// ad-hoc addition. Next version should be a configurable key buffer
int last_input_key;
} GameEngine_t; } GameEngine_t;
#define SCENE_ACTIVE_BIT (1 << 0) // Systems Active #define SCENE_ACTIVE_BIT (1 << 0) // Systems Active

View File

@ -91,11 +91,55 @@ static void options_scene_render_func(Scene_t* scene)
y_offset += 12; y_offset += 12;
line++; line++;
if (data->mode == OPTIONS_KEYBIND_MODE)
{
y_offset += 36;
DrawText("Press a Key...", 32, y_offset, 12, WHITE);
}
EndTextureMode(); 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) 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); printf("Sel: %u\n", sel);
if (sel == 0) if (sel == 0)
{ {
@ -116,9 +160,8 @@ static void exec_component_function(Scene_t* scene, uint16_t sel)
} }
else else
{ {
// Keybind options // Keybind options, but need to wait one frame
// TODO: This should change the scene mode data->mode = OPTIONS_KEYBIND_READY_MODE;
// Engine need to record last key released
} }
} }
@ -173,7 +216,7 @@ static void options_do_action(Scene_t* scene, ActionType_t action, bool pressed)
} }
} }
break; break;
case OPTIONS_KEYBIND_MODE: default:
break; break;
} }
} }
@ -219,6 +262,7 @@ void init_options_scene(OptionScene_t* scene)
// The number of actions that can be key-binds is constant. // The number of actions that can be key-binds is constant.
// So can just init once. // 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_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); sc_map_put_64(&scene->scene.action_map, get_keybind_or_default(scene->scene.engine, ACTION_UP, KEY_UP), ACTION_UP);

View File

@ -137,6 +137,7 @@ typedef struct LevelSelectScene {
typedef enum OptionSceneMode { typedef enum OptionSceneMode {
OPTIONS_NORMAL_MODE, OPTIONS_NORMAL_MODE,
OPTIONS_KEYBIND_READY_MODE,
OPTIONS_KEYBIND_MODE, OPTIONS_KEYBIND_MODE,
}OptionSceneMode_t; }OptionSceneMode_t;