From 5ff0fbb26ffbe8ee00c8b6515306af1c3f6670ae Mon Sep 17 00:00:00 2001 From: Klemen Plestenjak Date: Thu, 23 Nov 2023 12:21:25 +0100 Subject: [PATCH] Add feedback UI for selecting and placing units --- game/game_state.h | 1 + game/main.c | 113 ++----------------------------------------- game/systems.h | 13 ++++- game/systems_input.c | 80 ++++++++++++++++++++++++++---- 4 files changed, 86 insertions(+), 121 deletions(-) diff --git a/game/game_state.h b/game/game_state.h index 04dc92c..db6db05 100644 --- a/game/game_state.h +++ b/game/game_state.h @@ -31,6 +31,7 @@ typedef struct InputState { TileSize buildingSize; // SELECTED_UNITS ecs_entity_t *entities; + Position *unitPositions; // SELECTED_OBJECT // SELECTED_BUILDING } InputState; diff --git a/game/main.c b/game/main.c index f0cce67..7e3eaa2 100644 --- a/game/main.c +++ b/game/main.c @@ -72,6 +72,7 @@ bool init(void *userData) { input->CLICK_LIMIT = 0.2f; input->entities = bzArrayCreate(ecs_entity_t, 16); + input->unitPositions = bzArrayCreate(Position, 16); // init pools @@ -177,6 +178,7 @@ void deinit(void *userData) { ECS = NULL; bzArrayDestroy(inputCopy.entities); + bzArrayDestroy(inputCopy.unitPositions); bzObjectPoolDestroy(gameCopy.pools.pathData); bzSpatialGridDestroy(gameCopy.entityGrid); } @@ -202,116 +204,7 @@ void render(float dt, void *userData) { bzTileMapDraw(&game->map); - Vector2 worldPos = GetScreenToWorld2D(GetMousePosition(), game->camera); - switch (input->state) { - case INPUT_NONE: - if (IsMouseButtonDown(input->LMB) && input->mouseDownElapsed > input->CLICK_LIMIT) { - Vector2 start = input->mouseDownWorld; - Vector2 end = worldPos; - if (start.x > end.x) { - f32 tmp = start.x; - start.x = end.x; - end.x = tmp; - } - if (start.y > end.y) { - f32 tmp = start.y; - start.y = end.y; - end.y = tmp; - } - Rectangle area = {start.x, start.y, end.x - start.x, end.y - start.y}; - DrawRectangleLines(area.x, area.y, area.width, area.height, RED); - } - break; - case INPUT_BUILDING: { - Color placeColor = input->buildingCanPlace ? - (Color) {0, 255, 0, 200} : - (Color) {255, 0, 0, 200}; - - BzTile width = game->map.tileWidth; - BzTile height = game->map.tileHeight; - DrawRectangleLines(input->buildingPos.x * width, - input->buildingPos.y * height, - input->buildingSize.sizeX * width, - input->buildingSize.sizeY * height, placeColor); - break; - } - case INPUT_SELECTED_UNITS: - break; - case INPUT_SELECTED_OBJECT: - break; - case INPUT_SELECTED_BUILDING: - break; - } - -#if 0 - Vector2 worldPos = GetScreenToWorld2D(GetMousePosition(), game->camera); - int tileX = (int) worldPos.x / 16; - int tileY = (int) worldPos.y / 16; - - i32 numUnits = 240; - static Vector2 *units = NULL; - if (!units) units = bzArrayCreate(Vector2, 3); - if (IsMouseButtonDown(MOUSE_BUTTON_LEFT) && game->input.mouseDownElapsed > 0.1) { - Vector2 start = game->input.mouseDownWorld; - Vector2 end = worldPos; - //bzArrayClear(units); - placeUnits(numUnits, 3.5f, start, end, &game->map, &units); - if (start.x > end.x) { - f32 tmp = start.x; - start.x = end.x; - end.x = tmp; - } - if (start.y > end.y) { - f32 tmp = start.y; - start.y = end.y; - end.y = tmp; - } - Vector2 size = Vector2Subtract(end, start); - - DrawRectangleLines(start.x, start.y, size.x, size.y, RED); - - BzSpatialGridIter it = bzSpatialGridIter(game->entityGrid, start.x, start.y, size.x, size.y); - i32 count = 0; - while (bzSpatialGridQueryNext(&it)) { - ecs_entity_t *e = it.data; - count++; - } - bzLogInfo("%d", count); - - //bzArrayClear(units); - //placeUnits(numUnits, 3.5f, start, end, &game->map, &units); - - - } - - - static PathNode *heap = NULL; - if (!heap) - heap = bzHeapCreate(PathNode, game->map.width * game->map.height); - if (!ecs_has(ECS, game->entity, Path) && IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) { - Path path = {}; - clock_t begin = clock(); - const Position *start = ecs_get(ECS, game->entity, Position); - findPath(&(PathfindingDesc) { - .start=(TilePosition) { - (int) (start->x / game->map.tileWidth), - (int) (start->y / game->map.tileHeight) - }, - .target=(TilePosition) {tileX, tileY}, - .map=&game->map, - .openSet=heap, - .outPath=&path, - .pool=game->pools.pathData - }); - if (path.paths) { - ecs_set_ptr(ECS, game->entity, Path, &path); - } - clock_t end = clock(); - double timeSpent = (double) (end - begin) / CLOCKS_PER_SEC; - timeSpent *= 1000; - bzLogInfo("A* took: %.3fms", timeSpent); - } -#endif + drawPlayerInputUI(NULL); ecs_progress(ECS, dt); ecs_enable(ECS, renderDebugPathSystem, game->debugDraw.path); diff --git a/game/systems.h b/game/systems.h index 0c90ff6..dc6fb51 100644 --- a/game/systems.h +++ b/game/systems.h @@ -73,7 +73,7 @@ void renderDebugPath(ecs_iter_t *it); /********************************** - * Entity Systems + * Input systems **********************************/ /* @@ -83,4 +83,15 @@ void renderDebugPath(ecs_iter_t *it); */ void updatePlayerInput(ecs_iter_t *it); +/* + * Task: + * 0: Game (singleton) + * 0: InputState (singleton) + */ +void drawPlayerInputUI(ecs_iter_t *it); + +/********************************** + * UI systems + **********************************/ + #endif //PIXELDEFENSE_SYSTEMS_H diff --git a/game/systems_input.c b/game/systems_input.c index 8d1ff2c..8ddaec8 100644 --- a/game/systems_input.c +++ b/game/systems_input.c @@ -5,6 +5,7 @@ #include #include +bool getEntityBounds(ecs_entity_t entity, Position *outPos, Size *outSize, Rectangle *outBounds); void pickEntity(BzSpatialGrid *entityGrid, Vector2 point, ecs_entity_t **outEntities); void pickEntities(BzSpatialGrid *entityGrid, Rectangle area, ecs_entity_t **outEntities); @@ -116,14 +117,14 @@ void updatePlayerInput(ecs_iter_t *it) { // TODO: For click it should just move them i32 numUnits = bzArraySize(input->entities); f32 unitSpacing = 3.5f; - Vector2 *unitPositions = bzArrayCreate(Position, numUnits); + bzArrayClear(input->unitPositions); placeUnits(numUnits, unitSpacing, input->mouseDownWorld, worldPos, - map, &unitPositions); + map, &input->unitPositions); - BZ_ASSERT(bzArraySize(unitPositions) == numUnits); + BZ_ASSERT(bzArraySize(input->unitPositions) == numUnits); - bzArrayFor(unitPositions, i) { - Position target = bzArrayGet(unitPositions, i); + bzArrayFor(input->unitPositions, i) { + Position target = bzArrayGet(input->unitPositions, i); ecs_entity_t entity = bzArrayGet(input->entities, i); const Position *start = ecs_get(ECS, entity, Position); @@ -139,9 +140,6 @@ void updatePlayerInput(ecs_iter_t *it) { ecs_set_ptr(ECS, entity, Path, &path); input->state = INPUT_NONE; } - - bzArrayDestroy(unitPositions); - } else if (wasInputClicked(input)) { bzArrayFor(input->entities, i) { ecs_entity_t entity = bzArrayGet(input->entities, i); @@ -170,8 +168,70 @@ void updatePlayerInput(ecs_iter_t *it) { } } -static bool getEntityBounds(ecs_entity_t entity, Position *outPos, Size *outSize, - Rectangle *outBounds) { +void drawPlayerInputUI(ecs_iter_t *it) { + Game *game = ecs_singleton_get_mut(ECS, Game); + InputState *input = ecs_singleton_get_mut(ECS, InputState); + Vector2 worldPos = GetScreenToWorld2D(GetMousePosition(), game->camera); + + switch (input->state) { + case INPUT_NONE: + if (IsMouseButtonDown(input->LMB) && input->mouseDownElapsed > input->CLICK_LIMIT) { + Vector2 start = input->mouseDownWorld; + Vector2 end = worldPos; + if (start.x > end.x) { + f32 tmp = start.x; + start.x = end.x; + end.x = tmp; + } + if (start.y > end.y) { + f32 tmp = start.y; + start.y = end.y; + end.y = tmp; + } + Rectangle area = {start.x, start.y, end.x - start.x, end.y - start.y}; + DrawRectangleLines(area.x, area.y, area.width, area.height, RED); + } + break; + case INPUT_BUILDING: { + Color placeColor = input->buildingCanPlace ? + (Color) {0, 255, 0, 200} : + (Color) {255, 0, 0, 200}; + + BzTile width = game->map.tileWidth; + BzTile height = game->map.tileHeight; + DrawRectangleLines(input->buildingPos.x * width, + input->buildingPos.y * height, + input->buildingSize.sizeX * width, + input->buildingSize.sizeY * height, placeColor); + break; + } + case INPUT_SELECTED_UNITS: { + bzArrayFor(input->entities, i) { + ecs_entity_t entity = bzArrayGet(input->entities, i); + Position pos = {0}; + if (!getEntityBounds(entity, &pos, NULL, NULL)) + continue; + DrawCircleLines(pos.x, pos.y, 4.5f, GREEN); + } + + + + break; + } + case INPUT_SELECTED_OBJECT: + break; + case INPUT_SELECTED_BUILDING: + break; + } + bzArrayFor(input->unitPositions, i) { + Position pos = bzArrayGet(input->unitPositions, i); + DrawCircle(pos.x, pos.y, 2.0f, ORANGE); + } + + +} + +bool getEntityBounds(ecs_entity_t entity, Position *outPos, Size *outSize, Rectangle *outBounds) { if (!ecs_is_alive(ECS, entity)) return false; const Position *pos = ecs_get(ECS, entity, Position);