Use component for unit selection

This commit is contained in:
2023-12-02 11:53:45 +01:00
parent 6fe4449adf
commit 17bfe7f52d
6 changed files with 106 additions and 73 deletions

View File

@@ -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);

View File

@@ -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,

View File

@@ -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

View File

@@ -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:

View File

@@ -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

View File

@@ -5,14 +5,13 @@
#include <rlImGui.h>
#include <raymath.h>
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);
}
}