Use component for unit selection
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
14
game/main.c
14
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:
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user