From 03dc3774e7c730af3376bbad1375cd6502806c59 Mon Sep 17 00:00:00 2001 From: Klemen Plestenjak Date: Sun, 7 Jan 2024 15:20:39 +0100 Subject: [PATCH] Rework input system --- engine/breeze/ui/ui.c | 9 +- game/input.h | 3 +- game/main.c | 8 +- game/systems/s_input.c | 201 ++++++++++++----------------------------- 4 files changed, 70 insertions(+), 151 deletions(-) diff --git a/engine/breeze/ui/ui.c b/engine/breeze/ui/ui.c index 004fa0a..01f7fea 100644 --- a/engine/breeze/ui/ui.c +++ b/engine/breeze/ui/ui.c @@ -409,7 +409,14 @@ static void updateNodeInteraction(BzUI *ui, BzUINode *node, Vector2 mouse) { hovered = false; clicked = false; } - if (hovered) { + BzUIFlags flags = node->flags; + bool drawsAnything = (flags & BZ_UI_DRAW_BACKGROUND) || + (flags & BZ_UI_DRAW_BOX_SHADOW)|| + (flags & BZ_UI_DRAW_BORDER) || + (flags & BZ_UI_DRAW_TEXT) || + (flags & BZ_UI_DRAW_TEXT_SHADOW) || + (flags & BZ_UI_DRAW_SPRITE); + if (hovered && drawsAnything) { ui->capturedMouse = true; } diff --git a/game/input.h b/game/input.h index abb1889..5115171 100644 --- a/game/input.h +++ b/game/input.h @@ -67,8 +67,9 @@ typedef struct InputState { * 3: UnitSelected */ ecs_query_t *selected; - //ecs_query_t *selectedBuilding; } queries; + bool canUseMouse; + bool canUseKeyboard; } InputState; static InputMapping inputDefaultMapping() { diff --git a/game/main.c b/game/main.c index 13ef15a..c142885 100644 --- a/game/main.c +++ b/game/main.c @@ -300,14 +300,13 @@ void update(float dt, void *userData) { bzUISetCaptureMouse(UI, !io->WantCaptureMouse); bzUISetCaptureKeyboard(UI, !io->WantCaptureKeyboard); + input->canUseMouse = !io->WantCaptureMouse && !bzUICapturedMouse(UI); + input->canUseKeyboard = !io->WantCaptureKeyboard && !bzUICapturedKeyboard(UI); updateInputState(input, game->camera, dt); switch (game->screen) { case SCREEN_GAME: updatePlayerInput(); - if (IsKeyReleased(input->mapping.backBtn)) { - game->screen = SCREEN_PAUSE_MENU; - } break; case SCREEN_PAUSE_MENU: if (IsKeyReleased(input->mapping.backBtn)) { @@ -709,7 +708,8 @@ void imguiRender(float dt, void *userData) { if (igCollapsingHeader_TreeNodeFlags("Selection", 0)) { switch (input->state) { case INPUT_SELECTED_UNITS: - case INPUT_SELECTED_OBJECT: { + case INPUT_SELECTED_OBJECT: + case INPUT_SELECTED_BUILDING: { ecs_defer_begin(ECS); ecs_iter_t it = ecs_query_iter(ECS, input->queries.selected); while (ecs_iter_next(&it)) { diff --git a/game/systems/s_input.c b/game/systems/s_input.c index df60fcb..073004f 100644 --- a/game/systems/s_input.c +++ b/game/systems/s_input.c @@ -16,8 +16,10 @@ bool getEntityBounds(ecs_entity_t entity, Position *outPos, Size *outSize, Recta ecs_entity_t queryEntity(BzSpatialGrid *entityGrid, Vector2 point, ecs_entity_t tag); -bool pickEntity(BzSpatialGrid *entityGrid, Vector2 point, ecs_entity_t tag); -void pickUnits(BzSpatialGrid *entityGrid, Rectangle area); +bool selectEntity(BzSpatialGrid *entityGrid, Vector2 point, ecs_entity_t tag); +void selectUnits(BzSpatialGrid *entityGrid, Rectangle area); + +void addEntityToInspected(ecs_entity_t entity, Game *game); static void iterateSelectedUnits(ecs_query_t *query, void (*fn)(ecs_entity_t entity, Position *pos, Size *size)); static void iterRemovePaths(ecs_entity_t entity, Position *pos, Size *size); @@ -46,42 +48,29 @@ void inputPrimaryAction(Game *game, InputState *input) { end.y = tmp; } input->pickArea = (Rectangle) {start.x, start.y, end.x - start.x, end.y - start.y}; - pickUnits(game->entityGrid, input->pickArea); + selectUnits(game->entityGrid, input->pickArea); } i32 selectedCount = ecs_query_entity_count(input->queries.selected); if (isInputBtnJustDragged(input, primaryBtn) && selectedCount > 0) { resetInputState(input); input->state = INPUT_SELECTED_UNITS; + } + if (IsKeyDown(KEY_LEFT_ALT) && isInputBtnJustUp(input, primaryBtn)) { + ecs_entity_t entity = queryEntity(game->entityGrid, input->mouseDownWorld, ecs_id(GameEntity)); + if (entity) addEntityToInspected(entity, game); } else if (isInputBtnJustUp(input, primaryBtn)) { - if (pickEntity(game->entityGrid, input->mouseDownWorld, ecs_id(Unit))) { - resetInputState(input); - input->state = INPUT_SELECTED_UNITS; - } else if (pickEntity(game->entityGrid, input->mouseDownWorld, Harvestable)) { - resetInputState(input); - input->state = INPUT_SELECTED_OBJECT; - } else if (pickEntity(game->entityGrid, input->mouseDownWorld, Buildable)) { - resetInputState(input); - input->state = INPUT_SELECTED_BUILDING; - } + InputType type = input->state; + if (selectEntity(game->entityGrid, input->mouseDownWorld, ecs_id(Unit))) + type = INPUT_SELECTED_UNITS; + else if (selectEntity(game->entityGrid, input->mouseDownWorld, ecs_id(Harvestable))) + type = INPUT_SELECTED_OBJECT; + else if (selectEntity(game->entityGrid, input->mouseDownWorld, ecs_id(Buildable))) + type = INPUT_SELECTED_BUILDING; selectedCount = ecs_query_entity_count(input->queries.selected); - if (IsKeyDown(KEY_LEFT_ALT) && IsKeyDown(KEY_LEFT_SHIFT)) { - ecs_iter_t it = ecs_query_iter(ECS, input->queries.selected); - while (ecs_iter_next(&it)) { - for (i32 i = 0; i < it.count; i++) { - ecs_entity_t entity = it.entities[i]; - bool alreadyInspecting = false; - for (i32 j = 0; j < bzArraySize(game->debug.inspecting); j++) { - if (game->debug.inspecting[j] == entity) { - alreadyInspecting = true; - break; - } - } - if (!alreadyInspecting) - bzArrayPush(game->debug.inspecting, entity); - } - } + if (selectedCount > 0) { + resetInputState(input); + input->state = type; } - } if (selectedCount == 0) @@ -157,23 +146,36 @@ void inputUnitAction(Game *game, InputState *input) { void updatePlayerInput() { f32 dt = GetFrameTime(); - ImGuiIO *io = igGetIO(); - if (io->WantCaptureMouse || io->WantCaptureKeyboard) - return; Game *game = ecs_singleton_get_mut(ECS, Game); InputState *input = ecs_singleton_get_mut(ECS, InputState); const f32 maxZoom = 4.5f; const f32 minZoom = 0.9f; - float moveSpeed = 100.0f * dt * (1 + maxZoom - game->camera.zoom); - if (IsKeyDown(KEY_W)) game->camera.target.y -= moveSpeed; - if (IsKeyDown(KEY_S)) game->camera.target.y += moveSpeed; - if (IsKeyDown(KEY_A)) game->camera.target.x -= moveSpeed; - if (IsKeyDown(KEY_D)) game->camera.target.x += moveSpeed; + if (input->canUseKeyboard) { + float moveSpeed = 100.0f * dt * (1 + maxZoom - game->camera.zoom); + if (IsKeyDown(KEY_W)) game->camera.target.y -= moveSpeed; + if (IsKeyDown(KEY_S)) game->camera.target.y += moveSpeed; + if (IsKeyDown(KEY_A)) game->camera.target.x -= moveSpeed; + if (IsKeyDown(KEY_D)) game->camera.target.x += moveSpeed; - if (IsKeyDown(KEY_Q)) game->camera.rotation--; - if (IsKeyDown(KEY_E)) game->camera.rotation++; + if (IsKeyDown(KEY_Q)) game->camera.rotation--; + if (IsKeyDown(KEY_E)) game->camera.rotation++; + + if (IsKeyReleased(input->mapping.backBtn)) { + i32 selectedCount = ecs_query_entity_count(input->queries.selected); + if (selectedCount == 0) { + game->screen = SCREEN_PAUSE_MENU; + } else { + ecs_remove_all(ECS, Selected); + resetInputState(input); + } + + } + + } + if (!input->canUseMouse) + return; // https://gamedev.stackexchange.com/questions/9330/zoom-to-cursor-calculation float wheel = GetMouseWheelMove(); @@ -219,12 +221,6 @@ void updatePlayerInput() { BzTile tileX = 0, tileY = 0; bzTileMapPosToTile(map, input->mouseWorld, &tileX, &tileY); - if (IsKeyPressed(input->mapping.backBtn)) { - ecs_remove_all(ECS, Selected); - resetInputState(input); - return; - } - const MouseButton primaryBtn = input->mapping.primaryBtn; const MouseButton secondaryBtn = input->mapping.secondaryBtn; @@ -250,81 +246,6 @@ void updatePlayerInput() { inputPrimaryAction(game, input); if (input->state != INPUT_SELECTED_UNITS) break; inputUnitAction(game, input); - - /* - - i32 selectedCount = ecs_query_entity_count(input->queries.selected); - if (selectedCount > 1 && isInputBtnJustDragged(input, secondaryBtn)) { - // TODO: For click it should just move them - i32 numUnits = selectedCount; - f32 unitSpacing = 3.5f; - bzArrayClear(input->unitPositions); - placeUnits(numUnits, unitSpacing, - input->mouseDownWorld, input->mouseWorld, - map, &input->unitPositions); - - BZ_ASSERT(bzArraySize(input->unitPositions) == numUnits); - i32 unitPosIdx = 0; - - ecs_defer_begin(ECS); - ecs_defer_end(ECS); - - ecs_iter_t it = ecs_query_iter(ECS, input->queries.selected); - ecs_defer_begin(ECS); - while (ecs_iter_next(&it)) { - Position *pos = ecs_field(&it, Position, 1); - for (i32 i = 0; i < it.count; i++) { - ecs_entity_t entity = it.entities[i]; - - Position target = bzArrayGet(input->unitPositions, unitPosIdx); - unitPosIdx++; - - Path path = {NULL, 0}; - pathfindAStar(&(PathfindingDesc) { - .start=pos[i], - .target=target, - .map=map, - .outPath=&path, - .pool=game->pools.pathData, - .alloc=&game->stackAlloc - }); - if (!path.paths) continue; - ecs_set_ptr(ECS, entity, Path, &path); - - } - } - ecs_defer_end(ECS); - } else if (isInputBtnJustDown(input, secondaryBtn)) { - ecs_defer_begin(ECS); - iterateSelectedUnits(input->queries.selected, iterRemovePaths); - ecs_defer_end(ECS); - - ecs_iter_t it = ecs_query_iter(ECS, input->queries.selected); - - ecs_defer_begin(ECS); - while (ecs_iter_next(&it)) { - Position *pos = ecs_field(&it, Position, 1); - for (i32 i = 0; i < it.count; i++) { - ecs_entity_t entity = it.entities[i]; - ecs_remove(ECS, entity, Path); - - Path path = {NULL, 0}; - pathfindAStar(&(PathfindingDesc) { - .start=pos[i], - .target=input->mouseWorld, - .map=map, - .outPath=&path, - .pool=game->pools.pathData, - .alloc=&game->stackAlloc - }); - if (!path.paths) continue; - ecs_set_ptr(ECS, entity, Path, &path); - - } - } - ecs_defer_end(ECS); - } - */ break; } case INPUT_SELECTED_OBJECT: { @@ -345,9 +266,8 @@ void drawPlayerInputUIGround() { const Game *game = ecs_singleton_get_mut(ECS, Game); const InputState *input = ecs_singleton_get_mut(ECS, InputState); - const MouseButton primaryBtn = input->mapping.primaryBtn; + const MouseButton primaryBtn = input->mapping.primaryBtn; - const i32 selectedUnitCount = ecs_count_id(ECS, Selected); switch (input->state) { case INPUT_BUILDING: { const Color placeColor = input->buildingCanPlace ? @@ -362,25 +282,6 @@ void drawPlayerInputUIGround() { input->buildingSize.sizeY * height, placeColor); break; } - case INPUT_SELECTED_UNITS: { - //BZ_ASSERT(selectedUnitCount); - /* - if (selectedUnitCount > 1 && isInputBtnDragged(input, primaryBtn)) { - i32 numUnits = selectedUnitCount; - f32 unitSpacing = 3.5f; - bzArrayClear(input->unitPositions); - placeUnits(numUnits, unitSpacing, input->mouseDownWorld, input->mouseWorld, - map, &input->unitPositions); - - BZ_ASSERT(bzArraySize(input->unitPositions) == numUnits); - bzArrayFor(input->unitPositions, i) { - Position pos = bzArrayGet(input->unitPositions, i); - DrawCircle(pos.x, pos.y, 2.0f, ORANGE); - } - } - */ - break; - } default: break; } ecs_iter_t it = ecs_query_iter(ECS, input->queries.selected); @@ -481,7 +382,7 @@ ecs_entity_t queryEntity(BzSpatialGrid *entityGrid, Vector2 point, ecs_entity_t return closest; } -bool pickEntity(BzSpatialGrid *entityGrid, Vector2 point, ecs_entity_t tag) { +bool selectEntity(BzSpatialGrid *entityGrid, Vector2 point, ecs_entity_t tag) { ecs_remove_all(ECS, Selected); const ecs_entity_t entity = queryEntity(entityGrid, point, tag); if (entity) { @@ -491,7 +392,7 @@ bool pickEntity(BzSpatialGrid *entityGrid, Vector2 point, ecs_entity_t tag) { return false; } -void pickUnits(BzSpatialGrid *entityGrid, Rectangle area) { +void selectUnits(BzSpatialGrid *entityGrid, Rectangle area) { ecs_remove_all(ECS, Selected); BzSpatialGridIter it = bzSpatialGridIter(entityGrid, area.x, area.y, area.width, area.height); while (bzSpatialGridQueryNext(&it)) { @@ -505,7 +406,17 @@ void pickUnits(BzSpatialGrid *entityGrid, Rectangle area) { } } - +void addEntityToInspected(ecs_entity_t entity, Game *game) { + bool alreadyInspecting = false; + for (i32 i = 0; i < bzArraySize(game->debug.inspecting); i++) { + if (game->debug.inspecting[i] == entity) { + alreadyInspecting = true; + break; + } + } + if (!alreadyInspecting) + bzArrayPush(game->debug.inspecting, entity); +} static bool isUnitObstructed(f32 x, f32 y, BzTileMap *map) { return bzTileMapHasCollision(map, x / map->tileWidth, y / map->tileHeight);