diff --git a/game/components.c b/game/components.c index 9f27490..de2e78a 100644 --- a/game/components.c +++ b/game/components.c @@ -4,6 +4,8 @@ ECS_TAG_DECLARE(TextureTerrain); ECS_TAG_DECLARE(TextureBuildings); ECS_TAG_DECLARE(TextureEntities); +ECS_TAG_DECLARE(UnitSelected); + ECS_COMPONENT_DECLARE(Resource); ECS_COMPONENT_DECLARE(TilePosition); @@ -29,6 +31,8 @@ void initComponentIDs(ecs_world_t *ecs) { ECS_TAG_DEFINE(ecs, TextureBuildings); ECS_TAG_DEFINE(ecs, TextureEntities); + ECS_TAG_DEFINE(ecs, UnitSelected); + ECS_COMPONENT_DEFINE(ecs, Resource); ECS_COMPONENT_DEFINE(ecs, TilePosition); diff --git a/game/components.h b/game/components.h index 61364b0..561edb0 100644 --- a/game/components.h +++ b/game/components.h @@ -10,6 +10,8 @@ extern ECS_TAG_DECLARE(TextureTerrain); extern ECS_TAG_DECLARE(TextureBuildings); extern ECS_TAG_DECLARE(TextureEntities); +extern ECS_TAG_DECLARE(UnitSelected); + typedef enum ResourceType { RES_IRON, RES_WOOD, diff --git a/game/game_state.h b/game/game_state.h index db6db05..6eef5ed 100644 --- a/game/game_state.h +++ b/game/game_state.h @@ -30,7 +30,12 @@ typedef struct InputState { TilePosition buildingPos; TileSize buildingSize; // SELECTED_UNITS - ecs_entity_t *entities; + /* + * 1: Position + * 2: Size + * 3: UnitSelected + */ + ecs_query_t *unitSelectedQuery; Position *unitPositions; // SELECTED_OBJECT // SELECTED_BUILDING diff --git a/game/main.c b/game/main.c index 47363f1..b9c4787 100644 --- a/game/main.c +++ b/game/main.c @@ -71,7 +71,11 @@ bool init(void *userData) { input->ESC = KEY_ESCAPE; input->CLICK_LIMIT = 0.2f; - input->entities = bzArrayCreate(ecs_entity_t, 16); + input->unitSelectedQuery = ecs_query(ECS, { + .filter.terms = { + { ecs_id(Position) }, { ecs_id(Size) }, { ecs_id(UnitSelected) } + } + }); input->unitPositions = bzArrayCreate(Position, 16); @@ -178,7 +182,6 @@ void deinit(void *userData) { ecs_fini(ECS); ECS = NULL; - bzArrayDestroy(inputCopy.entities); bzArrayDestroy(inputCopy.unitPositions); bzObjectPoolDestroy(gameCopy.pools.pathData); bzSpatialGridDestroy(gameCopy.entityGrid); @@ -249,8 +252,11 @@ void imguiRender(float dt, void *userData) { switch (input->state) { case INPUT_SELECTED_UNITS: igText("Selected units:"); - for (i32 i = 0; i < bzArraySize(input->entities); i++) { - igText("\t%llu", bzArrayGet(input->entities, i)); + ecs_iter_t it = ecs_query_iter(ECS, input->unitSelectedQuery); + while (ecs_iter_next(&it)) { + for (i32 i = 0; i < it.count; i++) { + igText("\t%llu", it.entities[i]); + } } break; case INPUT_SELECTED_OBJECT: diff --git a/game/systems.h b/game/systems.h index 25be265..029c102 100644 --- a/game/systems.h +++ b/game/systems.h @@ -82,14 +82,14 @@ void renderDebugPath(ecs_iter_t *it); * 0: Game (singleton) * 0: InputState (singleton) */ -void updatePlayerInput(ecs_iter_t *it); +void updatePlayerInput(); /* * Task: * 0: Game (singleton) * 0: InputState (singleton) */ -void drawPlayerInputUI(ecs_iter_t *it); +void drawPlayerInputUI(); /********************************** * UI systems diff --git a/game/systems_input.c b/game/systems_input.c index 9e0fea7..bce22fb 100644 --- a/game/systems_input.c +++ b/game/systems_input.c @@ -5,14 +5,13 @@ #include #include +Rectangle calculateEntityBounds(Position pos, Size size); 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); +void pickEntity(BzSpatialGrid *entityGrid, Vector2 point); +void pickEntities(BzSpatialGrid *entityGrid, Rectangle area); void placeUnits(i32 numUnits, f32 unitSpacing, Vector2 start, Vector2 end, BzTileMap *map, Vector2 **outPlaces); -void drawSelectionCircles(ecs_entity_t **selected); - static bool isInputDragged(InputState *input) { return IsMouseButtonDown(input->LMB && input->mouseDownElapsed > input->CLICK_LIMIT); } @@ -23,7 +22,7 @@ static bool wasInputClicked(InputState *input) { return IsMouseButtonReleased(input->LMB); } -void updatePlayerInput(ecs_iter_t *it) { +void updatePlayerInput() { f32 dt = GetFrameTime(); ImGuiIO *io = igGetIO(); if (io->WantCaptureMouse || io->WantCaptureKeyboard) @@ -54,10 +53,11 @@ void updatePlayerInput(ecs_iter_t *it) { Vector2 worldPos = GetScreenToWorld2D(GetMousePosition(), game->camera); BzTile tileX = 0, tileY = 0; bzTileMapPosToTile(map, worldPos, &tileX, &tileY); + i32 selectedUnitCount = ecs_count_id(ECS, UnitSelected); switch (input->state) { case INPUT_NONE: if (wasInputDragged(input)) { - if (bzArraySize(input->entities) > 0) { + if (selectedUnitCount > 0) { input->state = INPUT_SELECTED_UNITS; break; } @@ -66,7 +66,7 @@ void updatePlayerInput(ecs_iter_t *it) { // Click // 1. Entity - if (bzArraySize(input->entities) > 0) { + if (selectedUnitCount > 0) { input->state = INPUT_SELECTED_UNITS; break; } @@ -97,54 +97,67 @@ void updatePlayerInput(ecs_iter_t *it) { break; case INPUT_SELECTED_UNITS: if (IsKeyPressed(input->ESC) || IsMouseButtonPressed(input->RMB)) { - bzArrayClear(input->entities); + ecs_remove_all(ECS, UnitSelected); input->state = INPUT_NONE; break; } - if (bzArraySize(input->entities) > 1 && wasInputDragged(input)) { + if (selectedUnitCount > 1 && wasInputDragged(input)) { // TODO: For click it should just move them - i32 numUnits = bzArraySize(input->entities); + i32 numUnits = selectedUnitCount; f32 unitSpacing = 3.5f; bzArrayClear(input->unitPositions); placeUnits(numUnits, unitSpacing, input->mouseDownWorld, worldPos, map, &input->unitPositions); BZ_ASSERT(bzArraySize(input->unitPositions) == numUnits); + i32 unitPosIdx = 0; - bzArrayFor(input->unitPositions, i) { - Position target = bzArrayGet(input->unitPositions, i); - ecs_entity_t entity = bzArrayGet(input->entities, i); + ecs_iter_t it = ecs_query_iter(ECS, input->unitSelectedQuery); - const Position *start = ecs_get(ECS, entity, Position); - Path path = {NULL, 0}; - pathfindAStar(&(PathfindingDesc) { - .start=*start, - .target=target, - .map=map, - .outPath=&path, - .pool=game->pools.pathData - }); - if (!path.paths) continue; - ecs_set_ptr(ECS, entity, Path, &path); + 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); + + 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 + }); + if (!path.paths) continue; + ecs_set_ptr(ECS, entity, Path, &path); + + } } } else if (wasInputClicked(input)) { - bzArrayFor(input->entities, i) { - ecs_entity_t entity = bzArrayGet(input->entities, i); - ecs_remove(ECS, entity, Path); + ecs_iter_t it = ecs_query_iter(ECS, input->unitSelectedQuery); - const Position *start = ecs_get(ECS, entity, Position); - Path path = {NULL, 0}; - pathfindAStar(&(PathfindingDesc) { - .start=*start, - .target=worldPos, - .map=map, - .outPath=&path, - .pool=game->pools.pathData - }); - if (!path.paths) continue; - ecs_set_ptr(ECS, entity, Path, &path); + 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=worldPos, + .map=map, + .outPath=&path, + .pool=game->pools.pathData + }); + if (!path.paths) continue; + ecs_set_ptr(ECS, entity, Path, &path); + + } } - } break; case INPUT_SELECTED_OBJECT: @@ -154,12 +167,13 @@ void updatePlayerInput(ecs_iter_t *it) { } } -void drawPlayerInputUI(ecs_iter_t *it) { +void drawPlayerInputUI() { Game *game = ecs_singleton_get_mut(ECS, Game); InputState *input = ecs_singleton_get_mut(ECS, InputState); BzTileMap *map = &game->map; Vector2 worldPos = GetScreenToWorld2D(GetMousePosition(), game->camera); + i32 selectedUnitCount = ecs_count_id(ECS, UnitSelected); switch (input->state) { case INPUT_NONE: if (isInputDragged(input)) { @@ -178,7 +192,7 @@ void drawPlayerInputUI(ecs_iter_t *it) { Rectangle area = {start.x, start.y, end.x - start.x, end.y - start.y}; DrawRectangleLines(area.x, area.y, area.width, area.height, RED); - pickEntities(game->entityGrid, area, &input->entities); + pickEntities(game->entityGrid, area); } break; case INPUT_BUILDING: { @@ -195,8 +209,8 @@ void drawPlayerInputUI(ecs_iter_t *it) { break; } case INPUT_SELECTED_UNITS: { - if (bzArraySize(input->entities) > 1 && isInputDragged(input)) { - i32 numUnits = bzArraySize(input->entities); + if (selectedUnitCount > 1 && isInputDragged(input)) { + i32 numUnits = selectedUnitCount; f32 unitSpacing = 3.5f; bzArrayClear(input->unitPositions); placeUnits(numUnits, unitSpacing, input->mouseDownWorld, worldPos, @@ -216,10 +230,27 @@ void drawPlayerInputUI(ecs_iter_t *it) { case INPUT_SELECTED_BUILDING: break; } - drawSelectionCircles(&input->entities); - + ecs_iter_t it = ecs_query_iter(ECS, input->unitSelectedQuery); + while (ecs_query_next(&it)) { + Position *pos = ecs_field(&it, Position, 1); + Size *size = ecs_field(&it, Size, 2); + for (i32 i = 0; i < it.count; i++) { + f32 radius = size[i].x; + if (size[i].y > radius) + radius = size[i].y; + radius *= 0.5f; + DrawCircleLines(pos[i].x, pos[i].y, radius, GREEN); + } + } +} +Rectangle calculateEntityBounds(Position pos, Size size) { + return (Rectangle) { + pos.x - size.x * 0.5f, + pos.y - size.x * 0.5f, + size.x, size.y + }; } bool getEntityBounds(ecs_entity_t entity, Position *outPos, Size *outSize, Rectangle *outBounds) { @@ -248,9 +279,8 @@ bool getEntityBounds(ecs_entity_t entity, Position *outPos, Size *outSize, Recta return true; } -void pickEntity(BzSpatialGrid *entityGrid, Vector2 point, ecs_entity_t **outEntities) { - BZ_ASSERT(*outEntities); - bzArrayClear(*outEntities); +void pickEntity(BzSpatialGrid *entityGrid, Vector2 point) { + ecs_remove_all(ECS, UnitSelected); BzSpatialGridIter it = bzSpatialGridIter(entityGrid, point.x, point.y, 0.0f, 0.0f); f32 closestDst = INFINITY; ecs_entity_t closest = 0; @@ -269,14 +299,12 @@ void pickEntity(BzSpatialGrid *entityGrid, Vector2 point, ecs_entity_t **outEnti } } if (closest) { - bzArrayPush(*outEntities, closest); + ecs_add(ECS, closest, UnitSelected); } } -void pickEntities(BzSpatialGrid *entityGrid, Rectangle area, ecs_entity_t **outEntities) { - BZ_ASSERT(*outEntities); - bzArrayClear(*outEntities); - +void pickEntities(BzSpatialGrid *entityGrid, Rectangle area) { + ecs_remove_all(ECS, UnitSelected); BzSpatialGridIter it = bzSpatialGridIter(entityGrid, area.x, area.y, area.width, area.height); while (bzSpatialGridQueryNext(&it)) { ecs_entity_t entity = *(ecs_entity_t *) it.data; @@ -284,7 +312,7 @@ void pickEntities(BzSpatialGrid *entityGrid, Rectangle area, ecs_entity_t **outE if (!getEntityBounds(entity, NULL, NULL, &bounds)) continue; if (!CheckCollisionRecs(area, bounds)) continue; - bzArrayPush(*outEntities, entity); + ecs_add(ECS, entity, UnitSelected); } } @@ -327,15 +355,3 @@ void placeUnits(i32 numUnits, f32 unitSpacing, Vector2 start, Vector2 end, BzTil pos.x += unitSpacing * 2.0f; } } - -void drawSelectionCircles(ecs_entity_t **selected) { - bzArrayFor(*selected, i) { - ecs_entity_t entity = bzArrayGet(*selected, i); - Position pos = {0}; - if (!getEntityBounds(entity, &pos, NULL, NULL)) - continue; - DrawCircleLines(pos.x, pos.y, 4.5f, GREEN); - - - } -}