From 3a99dafcd4a1a0183ed1673911f354c521b0dbc5 Mon Sep 17 00:00:00 2001 From: En Yi Date: Sun, 11 Dec 2022 14:32:26 +0800 Subject: [PATCH] Implement key controls to scene Changelog: - Add double buffer to handle key presses and release - Add more actions - Update action mapping of level scene - Implement action function for level scene - Remove action queue for Scene struct. This is handled by raylib and the game engine - Update scene struct with action function field --- actions.h | 5 ++++- scene.c | 10 ++++----- scene.h | 8 ++++--- scene_impl.c | 36 +++++++++++++++++++++++++++++++- scene_test.c | 59 +++++++++++++++++++++++++++++++++++++++++++++++----- 5 files changed, 102 insertions(+), 16 deletions(-) diff --git a/actions.h b/actions.h index 6045445..6668700 100644 --- a/actions.h +++ b/actions.h @@ -2,6 +2,9 @@ #define __ACTIONS_H typedef enum ActionType { - ACTION_UP + ACTION_UP, + ACTION_DOWN, + ACTION_LEFT, + ACTION_RIGHT, }ActionType_t; #endif // __ACTIONS_H diff --git a/scene.c b/scene.c index a33b65c..f7ee934 100644 --- a/scene.c +++ b/scene.c @@ -1,14 +1,14 @@ #include "scene.h" -void init_scene(Scene_t *scene, SceneType_t scene_type, system_func_t render_func) +void init_scene(Scene_t *scene, SceneType_t scene_type, system_func_t render_func, action_func_t action_func) { sc_map_init_64(&scene->action_map, 32, 0); - sc_queue_init(&scene->action_queue); sc_array_init(&scene->systems); init_entity_manager(&scene->ent_manager); scene->scene_type = scene_type; scene->render_function = render_func; + scene->action_function = action_func; scene->paused = false; scene->has_ended = false; } @@ -16,7 +16,6 @@ void init_scene(Scene_t *scene, SceneType_t scene_type, system_func_t render_fun void free_scene(Scene_t *scene) { sc_map_term_64(&scene->action_map); - sc_queue_term(&scene->action_queue); sc_array_term(&scene->systems); free_entity_manager(&scene->ent_manager); } @@ -35,8 +34,7 @@ inline void render_scene(Scene_t *scene) scene->render_function(scene); } -inline void queue_action(Scene_t *scene, ActionType_t action) +inline void do_action(Scene_t *scene, ActionType_t action, bool pressed) { - sc_queue_add_last(&scene->action_queue, action); + scene->action_function(scene, action, pressed); } - diff --git a/scene.h b/scene.h index c4bb914..cafe45d 100644 --- a/scene.h +++ b/scene.h @@ -10,14 +10,15 @@ typedef enum SceneType typedef struct Scene Scene_t; typedef void(*system_func_t)(Scene_t *); +typedef void(*action_func_t)(Scene_t *, ActionType_t, bool); sc_array_def(system_func_t, systems); struct Scene { struct sc_map_64 action_map; // key -> actions - struct sc_queue_64 action_queue; struct sc_array_systems systems; system_func_t render_function; + action_func_t action_function; EntityManager_t ent_manager; SceneType_t scene_type; void * scene_data; @@ -25,11 +26,12 @@ struct Scene bool has_ended; }; +// Inline functions, for convenience extern void update_scene(Scene_t *scene); extern void render_scene(Scene_t *scene); -extern void queue_action(Scene_t *scene, ActionType_t action); +extern void do_action(Scene_t *scene, ActionType_t action, bool pressed); -void init_scene(Scene_t *scene, SceneType_t scene_type, system_func_t render_func); +void init_scene(Scene_t *scene, SceneType_t scene_type, system_func_t render_func, action_func_t action_func); void free_scene(Scene_t *scene); #endif // __SCENE_H diff --git a/scene_impl.c b/scene_impl.c index 3c4f659..ae57a8f 100644 --- a/scene_impl.c +++ b/scene_impl.c @@ -58,16 +58,50 @@ static void screen_bounce_system(Scene_t *scene) } +void level_do_action(Scene_t *scene, ActionType_t action, bool pressed) +{ + LevelSceneData_t *data = (LevelSceneData_t *)scene->scene_data; + CTransform_t *p_ctransform = get_component(&scene->ent_manager, data->player, CTRANSFORM_COMP_T); + Vector2 dir = {0, 0}; + if (pressed) + { + switch(action) + { + case ACTION_UP: + dir.y -= 1; + break; + case ACTION_DOWN: + dir.y += 1; + break; + case ACTION_LEFT: + dir.x -= 1; + break; + case ACTION_RIGHT: + dir.x += 1; + break; + } + } + p_ctransform->accel.x = dir.x * 500; + p_ctransform->accel.y = dir.y * 500; + +} + void init_level_scene(LevelScene_t *scene) { - init_scene(&scene->scene, LEVEL_SCENE, &level_scene_render_func); + init_scene(&scene->scene, LEVEL_SCENE, &level_scene_render_func, &level_do_action); scene->scene.scene_data = &scene->data; scene->data.player = NULL; // insert level scene systems sc_array_add(&scene->scene.systems, &movement_update_system); sc_array_add(&scene->scene.systems, &screen_bounce_system); + + sc_map_put_64(&scene->scene.action_map, KEY_UP, ACTION_UP); + sc_map_put_64(&scene->scene.action_map, KEY_DOWN, ACTION_DOWN); + sc_map_put_64(&scene->scene.action_map, KEY_LEFT, ACTION_LEFT); + sc_map_put_64(&scene->scene.action_map, KEY_RIGHT, ACTION_RIGHT); } + void free_level_scene(LevelScene_t *scene) { free_scene(&scene->scene); diff --git a/scene_test.c b/scene_test.c index 569630b..28ad45e 100644 --- a/scene_test.c +++ b/scene_test.c @@ -3,28 +3,75 @@ #include #include +// Use double buffer to handle key presses +// Can do single buffer, but need careful handling +unsigned int curr_keybuf = 0; +unsigned int next_keybuf = 1; +struct sc_queue_32 key_buffer[2]; + int main(void) { + sc_queue_init(key_buffer); + sc_queue_init(key_buffer + 1); InitWindow(320, 240, "raylib"); - SetTargetFPS(60); // Set our game to run at 60 frames-per-second + SetTargetFPS(60); init_memory_pools(); LevelScene_t scene; init_level_scene(&scene); Entity_t *p_ent = add_entity(&scene.scene.ent_manager, PLAYER_ENT_TAG); + scene.data.player = p_ent; + CBBox_t *p_bbox = add_component(&scene.scene.ent_manager, p_ent, CBBOX_COMP_T); p_bbox->size.x = 30; p_bbox->size.y = 30; - CTransform_t * p_ctran = (CTransform_t *)add_component(&scene.scene.ent_manager, p_ent, CTRANSFORM_COMP_T); - p_ctran->accel.x = 200; - p_ctran->accel.y = 100; + add_component(&scene.scene.ent_manager, p_ent, CTRANSFORM_COMP_T); update_entity_manager(&scene.scene.ent_manager); for (size_t step = 0; step < 6000; step++) { + + // This entire key processing relies on the assumption that a pressed key will + // appear in the polling of raylib + + // Process any existing pressed key + while (!sc_queue_empty(key_buffer + curr_keybuf)) + { + int button = sc_queue_del_first(key_buffer + curr_keybuf); + ActionType_t action = sc_map_get_64(&scene.scene.action_map, button); + if (IsKeyReleased(button)) + { + do_action(&scene.scene, action, false); + } + else + { + do_action(&scene.scene, action, true); + sc_queue_add_last(key_buffer + next_keybuf, button); + } + } + + // Detect new key presses + while(true) + { + int button = GetKeyPressed(); + printf("Button pressed: %d\n", button); + if (button == 0) break; + ActionType_t action = sc_map_get_64(&scene.scene.action_map, button); + if (!sc_map_found(&scene.scene.action_map)) continue; + printf("Action mapped: %d\n", action); + do_action(&scene.scene, action, true); + sc_queue_add_last(key_buffer + next_keybuf, button); + } + + // Swap keystroke buffer; + { + unsigned int tmp = curr_keybuf; + curr_keybuf = next_keybuf; + next_keybuf = tmp; + } + printf("Step %lu\n", step); update_scene(&scene.scene); // This is needed to advance time delta BeginDrawing(); - // TODO: Call the current scene Render function render_scene(&scene.scene); ClearBackground(RAYWHITE); EndDrawing(); @@ -32,4 +79,6 @@ int main(void) } CloseWindow(); free_level_scene(&scene); + sc_queue_term(key_buffer); + sc_queue_term(key_buffer + 1); }