From b41086790286984795dd9f4d16d8de1ecd2b8105 Mon Sep 17 00:00:00 2001 From: Klemen Plestenjak Date: Thu, 7 Dec 2023 19:24:29 +0100 Subject: [PATCH] Add cursor support --- game/input.h | 14 +++++-- game/main.c | 4 +- game/systems.h | 9 ++++- game/systems_input.c | 89 ++++++++++++++++++++++++++------------------ 4 files changed, 75 insertions(+), 41 deletions(-) diff --git a/game/input.h b/game/input.h index 4f2314a..6d63a4b 100644 --- a/game/input.h +++ b/game/input.h @@ -17,7 +17,7 @@ typedef enum InputType { #define MOUSE_BUTTON_COUNT (MOUSE_BUTTON_BACK + 1) -#define CLICK_LIMIT 0.2f +#define CLICK_LIMIT 0.12f #define BUTTON_COUNT (MOUSE_BUTTON_BACK + 1) typedef struct InputMapping { @@ -41,6 +41,11 @@ typedef struct InputState { Vector2 mouse; Vector2 mouseWorld; f32 mouseDownElapsed[BUTTON_COUNT]; + enum { + CURSOR_NONE, + CURSOR_COLLECT_WOOD, + } cursor; + // INPUT_BUILDING int building; bool buildingCanPlace; @@ -49,6 +54,11 @@ typedef struct InputState { // SELECTED_UNITS Rectangle pickArea; + + // SELECTED_OBJECT + // SELECTED_BUILDING + + // Other struct { /* Selected units * 1: Position @@ -58,8 +68,6 @@ typedef struct InputState { ecs_query_t *selected; //ecs_query_t *selectedBuilding; } queries; - // SELECTED_OBJECT - // SELECTED_BUILDING } InputState; static InputMapping inputDefaultMapping() { diff --git a/game/main.c b/game/main.c index 52dbb19..da57b0f 100644 --- a/game/main.c +++ b/game/main.c @@ -224,7 +224,7 @@ void render(float dt, void *userData) { bzTileMapDraw(&game->map); - drawPlayerInputUI(); + drawPlayerInputUIGround(); ecs_progress(ECS, dt); ecs_enable(ECS, renderDebugPathSystem, game->debugDraw.path); @@ -234,6 +234,8 @@ void render(float dt, void *userData) { if (game->debugDraw.spatialGrid) bzSpatialGridDrawDebugGrid(game->entityGrid); + drawPlayerInputUI(); + EndMode2D(); } diff --git a/game/systems.h b/game/systems.h index d74c26c..7208686 100644 --- a/game/systems.h +++ b/game/systems.h @@ -114,7 +114,14 @@ void renderDebugPath(ecs_iter_t *it); void updatePlayerInput(); /* - * Task: + * Task (rendering above ground): + * 0: Game (singleton) + * 0: InputState (singleton) + */ +void drawPlayerInputUIGround(); + +/* + * Task (rendering on top): * 0: Game (singleton) * 0: InputState (singleton) */ diff --git a/game/systems_input.c b/game/systems_input.c index 614056c..077b25d 100644 --- a/game/systems_input.c +++ b/game/systems_input.c @@ -20,6 +20,12 @@ static void iterRemovePaths(ecs_entity_t entity, Position *pos, Size *size); void placeUnits(i32 numUnits, f32 unitSpacing, Vector2 start, Vector2 end, BzTileMap *map, Vector2 **outPlaces); +void resetInputState(InputState *input) { + input->cursor = CURSOR_NONE; + input->state = INPUT_NONE; + input->building = 0; +} + void inputPrimaryAction(Game *game, InputState *input) { const MouseButton primaryBtn = input->mapping.primaryBtn; if (isInputBtnDragged(input, primaryBtn)) { @@ -40,22 +46,26 @@ void inputPrimaryAction(Game *game, InputState *input) { } i32 selectedCount = ecs_query_entity_count(input->queries.selected); if (isInputBtnJustDragged(input, primaryBtn) && selectedCount > 0) { + resetInputState(input); input->state = INPUT_SELECTED_UNITS; } else if (isInputBtnJustUp(input, primaryBtn)) { if (pickEntity(game->entityGrid, input->mouseDownWorld, 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; } selectedCount = ecs_query_entity_count(input->queries.selected); } if (selectedCount == 0) - input->state = INPUT_NONE; + resetInputState(input); } -void inputUnitAction(Game *game, const InputState *input) { +void inputUnitAction(Game *game, InputState *input) { ecs_query_t *query = input->queries.selected; BzTileMap *map = &game->map; const i32 numUnits = ecs_query_entity_count(query); @@ -63,6 +73,14 @@ void inputUnitAction(Game *game, const InputState *input) { const MouseButton actionBtn = input->mapping.secondaryBtn; + input->cursor = CURSOR_NONE; + if (queryEntity(game->entityGrid, input->mouseWorld, Harvestable)) { + input->cursor = CURSOR_COLLECT_WOOD; + if (isInputBtnJustUp(input, actionBtn)) { + bzLogInfo("Chop wood!"); + } + } + if (isInputBtnJustDown(input, actionBtn)) { // Note: We mustn't use ecs ecs_remove_all since this will also // remove ongoing paths that are not part of this query. @@ -120,8 +138,7 @@ void updatePlayerInput() { if (IsKeyPressed(input->mapping.backBtn)) { ecs_remove_all(ECS, Selected); - input->state = INPUT_NONE; - input->building = 0; + resetInputState(input); return; } @@ -241,29 +258,21 @@ void updatePlayerInput() { } } -void drawPlayerInputUI() { - Game *game = ecs_singleton_get_mut(ECS, Game); - InputState *input = ecs_singleton_get_mut(ECS, InputState); - BzTileMap *map = &game->map; +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 secondaryBtn = input->mapping.secondaryBtn; - i32 selectedUnitCount = ecs_count_id(ECS, Selected); + const i32 selectedUnitCount = ecs_count_id(ECS, Selected); switch (input->state) { - case INPUT_NONE: - if (isInputBtnDragged(input, primaryBtn)) { - Rectangle area = input->pickArea; - DrawRectangleLines(area.x, area.y, area.width, area.height, RED); - } - break; case INPUT_BUILDING: { - Color placeColor = input->buildingCanPlace ? + const Color placeColor = input->buildingCanPlace ? (Color) {0, 255, 0, 200} : (Color) {255, 0, 0, 200}; - BzTile width = game->map.tileWidth; - BzTile height = game->map.tileHeight; + const BzTile width = game->map.tileWidth; + const BzTile height = game->map.tileHeight; DrawRectangleLines(input->buildingPos.x * width, input->buildingPos.y * height, input->buildingSize.sizeX * width, @@ -287,25 +296,9 @@ void drawPlayerInputUI() { } } */ - Rectangle area = {input->mouseWorld.x, input->mouseWorld.y, 1, 1}; - DrawCircle(area.x, area.y, 4.0f, BLUE); - - BzSpatialGridIter it = bzSpatialGridIter(game->entityGrid, area.x, area.y, area.width, area.height); - while (bzSpatialGridQueryNext(&it)) { - ecs_entity_t entity = 0; - - BzSpatialGrid *grid = game->entityGrid; - Vector2 point = input->mouseWorld; - - - if ((entity = queryEntity(grid, point, Harvestable))) { - DrawText("Collect resources", point.x, point.y, 10.0f, RED); - } - - } - break; } + default: break; } ecs_iter_t it = ecs_query_iter(ECS, input->queries.selected); rlSetLineWidth(2.0f); @@ -323,6 +316,30 @@ void drawPlayerInputUI() { } +void drawPlayerInputUI() { + const Game *game = ecs_singleton_get_mut(ECS, Game); + const InputState *input = ecs_singleton_get_mut(ECS, InputState); + + const MouseButton primaryBtn = input->mapping.primaryBtn; + + if (isInputBtnDragged(input, primaryBtn)) { + const Rectangle area = input->pickArea; + DrawRectangleLines(area.x, area.y, area.width, area.height, RED); + } + + switch (input->cursor) { + case CURSOR_COLLECT_WOOD: { + const Vector2 point = input->mouseWorld; + DrawCircle(point.x, point.y, 2.0f, RED); + DrawText("Collect wood", point.x, point.y, 10.0f, RED); + break; + } + default: break; + } + +} + + Rectangle calculateEntityBounds(Position pos, Size size) { return (Rectangle) { pos.x - size.x * 0.5f,