diff --git a/engine/engine.c b/engine/engine.c index e22d56b..ae581a5 100644 --- a/engine/engine.c +++ b/engine/engine.c @@ -48,6 +48,18 @@ int get_keybind_or_default(GameEngine_t* engine, ActionType_t action, int defaul return key; } +void remap_scene_keys(GameEngine_t* engine) +{ + // Assume all scene to be init'd + for(size_t i = 0; i < engine->max_scenes; ++i) + { + if (engine->scenes[i]->action_remap_function != NULL) + { + engine->scenes[i]->action_remap_function(engine->scenes[i]); + } + } +} + void process_inputs(GameEngine_t* engine, Scene_t* scene) { engine->last_input_key = KEY_NULL; @@ -121,6 +133,17 @@ void process_inputs(GameEngine_t* engine, Scene_t* scene) } } +Scene_t* change_scene_ext(GameEngine_t* engine, unsigned int idx, bool reset) +{ + + Scene_t * scene = change_active_scene(engine, idx); + if (reset && scene->reset_function != NULL) + { + scene->reset_function(scene); + } + return scene; +} + Scene_t* change_scene(GameEngine_t* engine, unsigned int idx) { // Backwards compat @@ -201,6 +224,7 @@ void init_scene(Scene_t* scene, action_func_t action_func, uint32_t subsystem_in scene->bg_colour = WHITE; scene->action_function = action_func; + scene->reset_function = NULL; scene->state = SCENE_COMPLETE_ACTIVE; scene->time_scale = 1.0f; } @@ -448,6 +472,8 @@ void remove_child_scene(GameEngine_t* engine, unsigned int idx) Scene_t* change_active_scene(GameEngine_t* engine, unsigned int idx) { + assert(idx < engine->max_scenes); + engine->scenes[engine->curr_scene]->state = 0; engine->curr_scene = idx; engine->scenes[engine->curr_scene]->state = SCENE_COMPLETE_ACTIVE; diff --git a/engine/engine.h b/engine/engine.h index 63d5e49..059a4b0 100644 --- a/engine/engine.h +++ b/engine/engine.h @@ -31,7 +31,10 @@ typedef struct GameEngine { SFXList_t sfx_list; // Maintain own queue to handle key presses Scene_t* focused_scene; // The one scene to receive key inputs - struct sc_map_64 keybinds; // Global action -> key mapping + + // Global action->key map. Does not hold previous key + struct sc_map_64 keybinds; + struct sc_queue_32 key_buffer; struct sc_queue_ptr scene_stack; struct sc_heap scenes_render_order; @@ -70,9 +73,12 @@ struct Scene { EntityManager_t ent_manager; Scene_t* parent_scene; struct sc_map_64 action_map; // key -> actions + struct sc_array_systems systems; SceneRenderLayers_t layers; Color bg_colour; + system_func_t reset_function; + system_func_t action_remap_function; action_func_t action_function; float delta_time; float time_scale; @@ -91,14 +97,22 @@ void process_inputs(GameEngine_t* engine, Scene_t* scene); // Register a key bind. If already exists, will override. // Does not support multi key to an action +// Register keybind should be done before scene inits. This lets the engine +// know what are the available keybinds for the game runtime. +// void register_keybind(GameEngine_t* engine, int key, ActionType_t action); int get_keybind_or_default(GameEngine_t* engine, ActionType_t action, int default_key); +// If a key bind gets changed, this must be called to update the +// key -> action mapping for all scene +void remap_scene_keys(GameEngine_t* engine); + void process_active_scene_inputs(GameEngine_t* engine); void update_curr_scene(GameEngine_t* engine); void render_curr_scene(GameEngine_t* engine); Scene_t* change_scene(GameEngine_t* engine, unsigned int idx); +Scene_t* change_scene_ext(GameEngine_t* engine, unsigned int idx, bool reset); Scene_t* change_active_scene(GameEngine_t* engine, unsigned int idx); void change_focused_scene(GameEngine_t* engine, unsigned int idx); bool load_sfx(GameEngine_t* engine, const char* snd_name, uint32_t tag_idx); diff --git a/scenes/game_scene.c b/scenes/game_scene.c index 1cd84b4..d9f51e2 100644 --- a/scenes/game_scene.c +++ b/scenes/game_scene.c @@ -518,6 +518,20 @@ static void at_level_complete(Scene_t* scene) } } +static void game_action_remap_func(Scene_t* scene) +{ + sc_map_clear_64(&scene->action_map); + sc_map_put_64(&scene->action_map, get_keybind_or_default(scene->engine, ACTION_UP, KEY_UP), ACTION_UP); + sc_map_put_64(&scene->action_map, get_keybind_or_default(scene->engine, ACTION_DOWN, KEY_DOWN), ACTION_DOWN); + sc_map_put_64(&scene->action_map, get_keybind_or_default(scene->engine, ACTION_LEFT, KEY_LEFT), ACTION_LEFT); + sc_map_put_64(&scene->action_map, get_keybind_or_default(scene->engine, ACTION_RIGHT, KEY_RIGHT), ACTION_RIGHT); + sc_map_put_64(&scene->action_map, get_keybind_or_default(scene->engine, ACTION_JUMP, KEY_ENTER), ACTION_JUMP); + sc_map_put_64(&scene->action_map, get_keybind_or_default(scene->engine, ACTION_EXIT, KEY_Q), ACTION_EXIT); + sc_map_put_64(&scene->action_map, get_keybind_or_default(scene->engine, ACTION_LOOKAHEAD, KEY_Z), ACTION_LOOKAHEAD); + + sc_map_put_64(&scene->action_map, KEY_R, ACTION_RESTART); +} + void init_game_scene(LevelScene_t* scene) { init_scene(&scene->scene, &level_do_action, ENABLE_ENTITY_MANAGEMENT_SYSTEM | ENABLE_PARTICLE_SYSTEM); @@ -526,6 +540,7 @@ void init_game_scene(LevelScene_t* scene) init_entity_tag_map(&scene->scene.ent_manager, LEVEL_END_TAG, 16); init_entity_tag_map(&scene->scene.ent_manager, DYNMEM_ENT_TAG, 16); + scene->scene.action_remap_function = &game_action_remap_func; scene->data.tilemap.tiles = all_tiles; scene->data.tilemap.render_nodes = all_tile_rendernodes; init_level_scene_data( @@ -600,15 +615,7 @@ void init_game_scene(LevelScene_t* scene) // This avoid graphical glitch, not essential //sc_array_add(&scene->scene.systems, &update_tilemap_system); - 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_DOWN, KEY_DOWN), ACTION_DOWN); - sc_map_put_64(&scene->scene.action_map, get_keybind_or_default(scene->scene.engine, ACTION_LEFT, KEY_LEFT), ACTION_LEFT); - sc_map_put_64(&scene->scene.action_map, get_keybind_or_default(scene->scene.engine, ACTION_RIGHT, KEY_RIGHT), ACTION_RIGHT); - sc_map_put_64(&scene->scene.action_map, get_keybind_or_default(scene->scene.engine, ACTION_JUMP, KEY_ENTER), ACTION_JUMP); - sc_map_put_64(&scene->scene.action_map, get_keybind_or_default(scene->scene.engine, ACTION_EXIT, KEY_Q), ACTION_EXIT); - sc_map_put_64(&scene->scene.action_map, get_keybind_or_default(scene->scene.engine, ACTION_LOOKAHEAD, KEY_Z), ACTION_LOOKAHEAD); - - sc_map_put_64(&scene->scene.action_map, KEY_R, ACTION_RESTART); + game_action_remap_func(&scene->scene); } void free_game_scene(LevelScene_t* scene) diff --git a/scenes/level_select_scene.c b/scenes/level_select_scene.c index 2883c3e..b3cb11a 100644 --- a/scenes/level_select_scene.c +++ b/scenes/level_select_scene.c @@ -245,6 +245,18 @@ static void level_select_do_action(Scene_t* scene, ActionType_t action, bool pre } } +static void level_select_action_remap_func(Scene_t* scene) +{ + sc_map_clear_64(&scene->action_map); + sc_map_put_64(&scene->action_map, get_keybind_or_default(scene->engine, ACTION_UP, KEY_UP), ACTION_UP); + sc_map_put_64(&scene->action_map, get_keybind_or_default(scene->engine, ACTION_DOWN, KEY_DOWN), ACTION_DOWN); + sc_map_put_64(&scene->action_map, get_keybind_or_default(scene->engine, ACTION_JUMP, KEY_ENTER), ACTION_CONFIRM); + sc_map_put_64(&scene->action_map, get_keybind_or_default(scene->engine, ACTION_EXIT, KEY_Q), ACTION_EXIT); + + sc_map_put_64(&scene->action_map, KEY_BACKSPACE, ACTION_EXIT); + sc_map_put_64(&scene->action_map, KEY_ENTER, ACTION_CONFIRM); +} + #define FONT_SIZE 22 #define TEXT_PADDING 3 #define SCROLL_TOTAL_HEIGHT 800 @@ -253,6 +265,7 @@ void init_level_select_scene(LevelSelectScene_t* scene) init_scene(&scene->scene, &level_select_do_action, 0); scene->data.preview = LoadRenderTexture(LEVEL_PREVIEW_SIZE, LEVEL_PREVIEW_SIZE); scene->data.update_preview = true; + scene->scene.action_remap_function = level_select_action_remap_func; add_scene_layer( &scene->scene, scene->scene.engine->intended_window_size.x, scene->scene.engine->intended_window_size.y, @@ -298,13 +311,7 @@ void init_level_select_scene(LevelSelectScene_t* scene) sc_array_add(&scene->scene.systems, &level_preview_render_func); sc_array_add(&scene->scene.systems, &level_select_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_DOWN, KEY_DOWN), ACTION_DOWN); - sc_map_put_64(&scene->scene.action_map, get_keybind_or_default(scene->scene.engine, ACTION_JUMP, KEY_ENTER), ACTION_CONFIRM); - sc_map_put_64(&scene->scene.action_map, get_keybind_or_default(scene->scene.engine, ACTION_EXIT, KEY_Q), ACTION_EXIT); - - sc_map_put_64(&scene->scene.action_map, KEY_BACKSPACE, ACTION_EXIT); - sc_map_put_64(&scene->scene.action_map, KEY_ENTER, ACTION_CONFIRM); + level_select_action_remap_func(&scene->scene); } void free_level_select_scene(LevelSelectScene_t* scene) { diff --git a/scenes/menu_scene.c b/scenes/menu_scene.c index 69ef803..5834ad1 100644 --- a/scenes/menu_scene.c +++ b/scenes/menu_scene.c @@ -56,7 +56,7 @@ static void exec_component_function(Scene_t* scene, int sel) change_scene(scene->engine, LEVEL_SELECT_SCENE); break; case 1: - change_scene(scene->engine, OPTIONS_SCENE); + change_scene_ext(scene->engine, OPTIONS_SCENE, true); break; case 2: scene->state = 0; @@ -162,9 +162,24 @@ static void gui_loop(Scene_t* scene) } } +static void menu_action_remap_func(Scene_t* scene) +{ + sc_map_clear_64(&scene->action_map); + + + sc_map_put_64(&scene->action_map, get_keybind_or_default(scene->engine, ACTION_UP, KEY_UP), ACTION_UP); + sc_map_put_64(&scene->action_map, get_keybind_or_default(scene->engine, ACTION_DOWN, KEY_DOWN), ACTION_DOWN); + sc_map_put_64(&scene->action_map, get_keybind_or_default(scene->engine, ACTION_LEFT, KEY_LEFT), ACTION_LEFT); + sc_map_put_64(&scene->action_map, get_keybind_or_default(scene->engine, ACTION_RIGHT, KEY_RIGHT), ACTION_RIGHT); + sc_map_put_64(&scene->action_map, get_keybind_or_default(scene->engine, ACTION_JUMP, KEY_ENTER), ACTION_CONFIRM); + // Guarantee a enter key for selection + sc_map_put_64(&scene->action_map, KEY_ENTER, ACTION_CONFIRM); +} + void init_menu_scene(MenuScene_t* scene) { init_scene(&scene->scene, &menu_do_action, 0); + scene->scene.action_remap_function = &menu_action_remap_func; sc_array_add(&scene->scene.systems, &gui_loop); sc_array_add(&scene->scene.systems, &menu_scene_render_func); @@ -205,14 +220,7 @@ void init_menu_scene(MenuScene_t* scene) } ); - - 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_DOWN, KEY_DOWN), ACTION_DOWN); - sc_map_put_64(&scene->scene.action_map, get_keybind_or_default(scene->scene.engine, ACTION_LEFT, KEY_LEFT), ACTION_LEFT); - sc_map_put_64(&scene->scene.action_map, get_keybind_or_default(scene->scene.engine, ACTION_RIGHT, KEY_RIGHT), ACTION_RIGHT); - sc_map_put_64(&scene->scene.action_map, get_keybind_or_default(scene->scene.engine, ACTION_JUMP, KEY_ENTER), ACTION_CONFIRM); - // Guarantee a enter key for selection - sc_map_put_64(&scene->scene.action_map, KEY_ENTER, ACTION_CONFIRM); + menu_action_remap_func(&scene->scene); } void free_menu_scene(MenuScene_t* scene) diff --git a/scenes/options_scene.c b/scenes/options_scene.c index 74cc4b3..d126095 100644 --- a/scenes/options_scene.c +++ b/scenes/options_scene.c @@ -69,7 +69,7 @@ static void options_scene_render_func(Scene_t* scene) { DrawText(">>", 0, y_offset, 12, WHITE); } - sprintf(buffer, "%s : %s %d", keybind_info.action_name, keybind_info.key_name, keybind_info.key); + sprintf(buffer, "%s : %s", keybind_info.action_name, keybind_info.key_name); DrawText(buffer, 32, y_offset, 12, WHITE); y_offset += 12; line++; @@ -132,8 +132,17 @@ static void wait_for_keymap_input(Scene_t* scene) printf("Key inputted: %d\n", scene->engine->last_input_key); + ActionType_t selected_action = data->keybinds_info.elems[data->curr_selection - 1].action; + + int last_key = sc_map_get_64(&scene->engine->keybinds, selected_action); + assert(sc_map_found(&scene->engine->keybinds)); + + // Register immediately only for this scene + sc_map_del_64(&scene->action_map, last_key); + sc_map_put_64(&scene->action_map, scene->engine->last_input_key, selected_action); 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; } @@ -153,8 +162,25 @@ static void exec_component_function(Scene_t* scene, uint16_t sel) { // Either OK or Cancel // Both will return to menu scene + // OK does nothing since the keybinds are already modified sel -= n_binds; - // TODO: add check to save keybinds + if (sel == 0) + { + printf("Keybind ready\n"); + // OK will propagate to the engine + KeyBindInfo_t info; + sc_array_foreach(&data->keybinds_info, info) + { + register_keybind(scene->engine, info.key, info.action); + } + remap_scene_keys(scene->engine); + } + else + { + // Need to reset action map, otherwise will preserve over scene change + scene->action_remap_function(scene); + } + change_scene(scene->engine, MAIN_MENU_SCENE); } @@ -221,10 +247,50 @@ static void options_do_action(Scene_t* scene, ActionType_t action, bool pressed) } } +static void reset_options_scene(Scene_t* scene) +{ + OptionSceneData_t* data = &(CONTAINER_OF(scene, OptionScene_t, scene)->data); + sc_array_clear(&data->keybinds_info); + { + int key; + ActionType_t action; + sc_map_foreach(&scene->engine->keybinds, action, key) + { + KeyBindInfo_t keybind = { + .action_name = get_action_name(action), + .key_name = ExtGetKeyName(key), + .action = action, + .original_key = key, + .key = key, + }; + sc_array_add(&data->keybinds_info, keybind); + } + } + data->curr_selection = 0; + data->mode = OPTIONS_NORMAL_MODE; +} + +static void options_action_remap_func(Scene_t* scene) +{ + sc_map_clear_64(&scene->action_map); + sc_map_put_64(&scene->action_map, get_keybind_or_default(scene->engine, ACTION_UP, KEY_UP), ACTION_UP); + sc_map_put_64(&scene->action_map, get_keybind_or_default(scene->engine, ACTION_DOWN, KEY_DOWN), ACTION_DOWN); + sc_map_put_64(&scene->action_map, get_keybind_or_default(scene->engine, ACTION_LEFT, KEY_LEFT), ACTION_LEFT); + sc_map_put_64(&scene->action_map, get_keybind_or_default(scene->engine, ACTION_RIGHT, KEY_RIGHT), ACTION_RIGHT); + sc_map_put_64(&scene->action_map, get_keybind_or_default(scene->engine, ACTION_JUMP, KEY_ENTER), ACTION_CONFIRM); + sc_map_put_64(&scene->action_map, get_keybind_or_default(scene->engine, ACTION_EXIT, KEY_Q), ACTION_EXIT); + + sc_map_put_64(&scene->action_map, KEY_ENTER, ACTION_CONFIRM); + sc_map_put_64(&scene->action_map, KEY_BACKSPACE, ACTION_EXIT); +} + void init_options_scene(OptionScene_t* scene) { init_scene(&scene->scene, &options_do_action, 0); scene->scene.bg_colour = BLACK; + scene->scene.reset_function = &reset_options_scene; + scene->scene.action_remap_function = &options_action_remap_func; + add_scene_layer( &scene->scene, scene->scene.engine->intended_window_size.x, scene->scene.engine->intended_window_size.y, @@ -244,36 +310,10 @@ void init_options_scene(OptionScene_t* scene) sc_array_init(&scene->data.keybinds_info); - { - int key; - ActionType_t action; - sc_map_foreach(&scene->scene.engine->keybinds, action, key) - { - KeyBindInfo_t keybind = { - .action_name = get_action_name(action), - .key_name = ExtGetKeyName(key), - .action = action, - .key = key, - }; - sc_array_add(&scene->data.keybinds_info, keybind); - } - } - - // 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); - sc_map_put_64(&scene->scene.action_map, get_keybind_or_default(scene->scene.engine, ACTION_DOWN, KEY_DOWN), ACTION_DOWN); - sc_map_put_64(&scene->scene.action_map, get_keybind_or_default(scene->scene.engine, ACTION_LEFT, KEY_LEFT), ACTION_LEFT); - sc_map_put_64(&scene->scene.action_map, get_keybind_or_default(scene->scene.engine, ACTION_RIGHT, KEY_RIGHT), ACTION_RIGHT); - sc_map_put_64(&scene->scene.action_map, get_keybind_or_default(scene->scene.engine, ACTION_JUMP, KEY_ENTER), ACTION_CONFIRM); - sc_map_put_64(&scene->scene.action_map, get_keybind_or_default(scene->scene.engine, ACTION_EXIT, KEY_Q), ACTION_EXIT); - - sc_map_put_64(&scene->scene.action_map, KEY_ENTER, ACTION_CONFIRM); - sc_map_put_64(&scene->scene.action_map, KEY_BACKSPACE, ACTION_EXIT); + options_action_remap_func(&scene->scene); } void free_options_scene(OptionScene_t* scene) diff --git a/scenes/scene_impl.h b/scenes/scene_impl.h index 93a1c30..0615f8e 100644 --- a/scenes/scene_impl.h +++ b/scenes/scene_impl.h @@ -146,6 +146,7 @@ typedef struct KeyBindInfo { const char* key_name; int action; int key; + int original_key; }KeyBindInfo_t; sc_array_def(KeyBindInfo_t, keybinds);