Rework input

This commit is contained in:
2023-12-07 14:19:10 +01:00
parent d3485303c9
commit 8543cc7b43
6 changed files with 220 additions and 122 deletions

View File

@@ -4,8 +4,6 @@ ECS_TAG_DECLARE(TextureTerrain);
ECS_TAG_DECLARE(TextureBuildings); ECS_TAG_DECLARE(TextureBuildings);
ECS_TAG_DECLARE(TextureEntities); ECS_TAG_DECLARE(TextureEntities);
ECS_TAG_DECLARE(UnitSelected);
ECS_COMPONENT_DECLARE(Resource); ECS_COMPONENT_DECLARE(Resource);
ECS_COMPONENT_DECLARE(TilePosition); ECS_COMPONENT_DECLARE(TilePosition);
@@ -13,26 +11,34 @@ ECS_COMPONENT_DECLARE(TileSize);
ECS_COMPONENT_DECLARE(Owner); ECS_COMPONENT_DECLARE(Owner);
ECS_COMPONENT_DECLARE(SpatialGridID); ECS_COMPONENT_DECLARE(SpatialGridID);
ECS_COMPONENT_DECLARE(Position); ECS_COMPONENT_DECLARE(Position);
ECS_COMPONENT_DECLARE(Size); ECS_COMPONENT_DECLARE(Size);
ECS_COMPONENT_DECLARE(Velocity); ECS_COMPONENT_DECLARE(Velocity);
ECS_COMPONENT_DECLARE(TargetPosition);
ECS_COMPONENT_DECLARE(Steering);
ECS_COMPONENT_DECLARE(Rotation); ECS_COMPONENT_DECLARE(Rotation);
ECS_COMPONENT_DECLARE(Steering);
ECS_COMPONENT_DECLARE(TargetPosition);
ECS_COMPONENT_DECLARE(Path);
ECS_COMPONENT_DECLARE(TextureRegion); ECS_COMPONENT_DECLARE(TextureRegion);
ECS_COMPONENT_DECLARE(Animation); ECS_COMPONENT_DECLARE(Animation);
ECS_COMPONENT_DECLARE(AnimationType); ECS_COMPONENT_DECLARE(AnimationType);
ECS_COMPONENT_DECLARE(Path);
ECS_TAG_DECLARE(Selectable);
ECS_TAG_DECLARE(Selected);
ECS_TAG_DECLARE(Unit);
ECS_TAG_DECLARE(Worker);
ECS_TAG_DECLARE(Harvestable);
ECS_TAG_DECLARE(Buildable);
ECS_TAG_DECLARE(Workable);
ECS_TAG_DECLARE(Attackable);
void initComponentIDs(ecs_world_t *ecs) { void initComponentIDs(ecs_world_t *ecs) {
ECS_TAG_DEFINE(ecs, TextureTerrain); ECS_TAG_DEFINE(ecs, TextureTerrain);
ECS_TAG_DEFINE(ecs, TextureBuildings); ECS_TAG_DEFINE(ecs, TextureBuildings);
ECS_TAG_DEFINE(ecs, TextureEntities); ECS_TAG_DEFINE(ecs, TextureEntities);
ECS_TAG_DEFINE(ecs, UnitSelected);
ECS_COMPONENT_DEFINE(ecs, Resource); ECS_COMPONENT_DEFINE(ecs, Resource);
ECS_COMPONENT_DEFINE(ecs, TilePosition); ECS_COMPONENT_DEFINE(ecs, TilePosition);
@@ -40,16 +46,26 @@ void initComponentIDs(ecs_world_t *ecs) {
ECS_COMPONENT_DEFINE(ecs, Owner); ECS_COMPONENT_DEFINE(ecs, Owner);
ECS_COMPONENT_DEFINE(ecs, SpatialGridID); ECS_COMPONENT_DEFINE(ecs, SpatialGridID);
ECS_COMPONENT_DEFINE(ecs, Position); ECS_COMPONENT_DEFINE(ecs, Position);
ECS_COMPONENT_DEFINE(ecs, Size); ECS_COMPONENT_DEFINE(ecs, Size);
ECS_COMPONENT_DEFINE(ecs, Velocity); ECS_COMPONENT_DEFINE(ecs, Velocity);
ECS_COMPONENT_DEFINE(ecs, TargetPosition);
ECS_COMPONENT_DEFINE(ecs, Steering);
ECS_COMPONENT_DEFINE(ecs, Rotation); ECS_COMPONENT_DEFINE(ecs, Rotation);
ECS_COMPONENT_DEFINE(ecs, Steering);
ECS_COMPONENT_DEFINE(ecs, TargetPosition);
ECS_COMPONENT_DEFINE(ecs, Path);
ECS_COMPONENT_DEFINE(ecs, TextureRegion); ECS_COMPONENT_DEFINE(ecs, TextureRegion);
ECS_COMPONENT_DEFINE(ecs, Animation); ECS_COMPONENT_DEFINE(ecs, Animation);
ECS_COMPONENT_DEFINE(ecs, AnimationType); ECS_COMPONENT_DEFINE(ecs, AnimationType);
ECS_COMPONENT_DEFINE(ecs, Path);
ECS_TAG_DEFINE(ecs, Selectable);
ECS_TAG_DEFINE(ecs, Selected);
ECS_TAG_DEFINE(ecs, Unit);
ECS_TAG_DEFINE(ecs, Worker);
ECS_TAG_DEFINE(ecs, Harvestable);
ECS_TAG_DEFINE(ecs, Buildable);
ECS_TAG_DEFINE(ecs, Workable);
ECS_TAG_DEFINE(ecs, Attackable);
} }

View File

@@ -11,7 +11,6 @@ extern ECS_TAG_DECLARE(TextureTerrain);
extern ECS_TAG_DECLARE(TextureBuildings); extern ECS_TAG_DECLARE(TextureBuildings);
extern ECS_TAG_DECLARE(TextureEntities); extern ECS_TAG_DECLARE(TextureEntities);
extern ECS_TAG_DECLARE(UnitSelected);
typedef enum ResourceType { typedef enum ResourceType {
RES_IRON, RES_IRON,
@@ -21,6 +20,16 @@ typedef enum ResourceType {
RES_COUNT, RES_COUNT,
} ResourceType; } ResourceType;
static const char *getResourceTypePrettyName(ResourceType type) {
switch (type) {
case RES_IRON: return "Iron";
case RES_WOOD: return "Wood";
case RES_GOLD: return "Gold";
case RES_FOOD: return "Food";
default: return "Invalid";
}
}
typedef struct Resource { typedef struct Resource {
ResourceType type; ResourceType type;
i32 amount; i32 amount;
@@ -44,39 +53,24 @@ typedef struct Owner {
} Owner; } Owner;
extern ECS_COMPONENT_DECLARE(Owner); extern ECS_COMPONENT_DECLARE(Owner);
/**********************************************************
* Movement components
*********************************************************/
typedef BzSpatialGridID SpatialGridID; typedef BzSpatialGridID SpatialGridID;
extern ECS_COMPONENT_DECLARE(SpatialGridID); extern ECS_COMPONENT_DECLARE(SpatialGridID);
typedef Vector2 Position, Size, Velocity, TargetPosition, Steering; typedef Vector2 Position, Size, Velocity, TargetPosition, Steering;
typedef f32 Rotation;
extern ECS_COMPONENT_DECLARE(Position); extern ECS_COMPONENT_DECLARE(Position);
extern ECS_COMPONENT_DECLARE(Size); extern ECS_COMPONENT_DECLARE(Size);
extern ECS_COMPONENT_DECLARE(Velocity); extern ECS_COMPONENT_DECLARE(Velocity);
extern ECS_COMPONENT_DECLARE(TargetPosition);
extern ECS_COMPONENT_DECLARE(Steering);
typedef f32 Rotation;
extern ECS_COMPONENT_DECLARE(Rotation); extern ECS_COMPONENT_DECLARE(Rotation);
extern ECS_COMPONENT_DECLARE(Steering);
typedef struct TextureRegion { extern ECS_COMPONENT_DECLARE(TargetPosition);
Texture2D texture;
Rectangle rec;
f32 rotation;
bool flipX : 1;
bool flipY : 1;
} TextureRegion;
extern ECS_COMPONENT_DECLARE(TextureRegion);
typedef struct Animation {
EntityType entityType;
AnimationType animType;
AnimationSequence sequence;
BzTileset *tileset;
i32 curFrame;
f32 frameDuration;
f32 elapsed;
} Animation;
extern ECS_COMPONENT_DECLARE(Animation);
extern ECS_COMPONENT_DECLARE(AnimationType);
#define PATH_DATA_SIZE 8 #define PATH_DATA_SIZE 8
typedef struct PathData { typedef struct PathData {
@@ -91,12 +85,66 @@ typedef struct Path {
} Path; } Path;
extern ECS_COMPONENT_DECLARE(Path); extern ECS_COMPONENT_DECLARE(Path);
/**********************************************************
* Render components
*********************************************************/
typedef struct TextureRegion {
Texture2D texture;
Rectangle rec;
f32 rotation;
bool flipX : 1;
bool flipY : 1;
} TextureRegion;
extern ECS_COMPONENT_DECLARE(TextureRegion);
/**********************************************************
* Animation components
*********************************************************/
typedef struct Animation {
EntityType entityType;
AnimationType animType;
AnimationSequence sequence;
BzTileset *tileset;
i32 curFrame;
f32 frameDuration;
f32 elapsed;
} Animation;
extern ECS_COMPONENT_DECLARE(Animation);
extern ECS_COMPONENT_DECLARE(AnimationType);
typedef struct EntityArms { typedef struct EntityArms {
ecs_entity_t left; ecs_entity_t left;
ecs_entity_t right; ecs_entity_t right;
} EntityArms; } EntityArms;
//extern ECS_COMPONENT_DECLARE(EntityArms); //extern ECS_COMPONENT_DECLARE(EntityArms);
/**********************************************************
* Gameplay components
*********************************************************/
extern ECS_TAG_DECLARE(Selectable);
extern ECS_TAG_DECLARE(Selected);
// Unit can:
// - Attack
extern ECS_TAG_DECLARE(Unit);
// Worker can:
// - Harvest
// - Build
// - Work
// - Attack (since it is also a unit)
extern ECS_TAG_DECLARE(Worker);
extern ECS_TAG_DECLARE(Harvestable);
extern ECS_TAG_DECLARE(Buildable);
extern ECS_TAG_DECLARE(Workable);
extern ECS_TAG_DECLARE(Attackable);
void initComponentIDs(ecs_world_t *ecs); void initComponentIDs(ecs_world_t *ecs);

View File

@@ -29,13 +29,18 @@ typedef struct InputState {
bool buildingCanPlace; bool buildingCanPlace;
TilePosition buildingPos; TilePosition buildingPos;
TileSize buildingSize; TileSize buildingSize;
// SELECTED_UNITS // Units
/* Rectangle pickArea;
* 1: Position
* 2: Size struct {
* 3: UnitSelected /* Selected units
*/ * 1: Position
ecs_query_t *unitSelectedQuery; * 2: Size
* 3: UnitSelected
*/
ecs_query_t *selected;
//ecs_query_t *selectedBuilding;
} queries;
Position *unitPositions; Position *unitPositions;
// SELECTED_OBJECT // SELECTED_OBJECT
// SELECTED_BUILDING // SELECTED_BUILDING

View File

@@ -71,11 +71,13 @@ bool init(void *userData) {
input->ESC = KEY_ESCAPE; input->ESC = KEY_ESCAPE;
input->CLICK_LIMIT = 0.2f; input->CLICK_LIMIT = 0.2f;
input->unitSelectedQuery = ecs_query(ECS, { // Create queries
input->queries.selected = ecs_query(ECS, {
.filter.terms = { .filter.terms = {
{ ecs_id(Position) }, { ecs_id(Size) }, { ecs_id(UnitSelected) } { ecs_id(Position) }, { ecs_id(Size) }, { ecs_id(Selected) }
} }
}); });
input->unitPositions = bzArrayCreate(Position, 16); input->unitPositions = bzArrayCreate(Position, 16);
@@ -94,7 +96,7 @@ bool init(void *userData) {
game->camera.target = (Vector2) {0, 0}; game->camera.target = (Vector2) {0, 0};
game->camera.offset = (Vector2) {screenWidth / 2.0f, screenHeight / 2.0f}; game->camera.offset = (Vector2) {screenWidth / 2.0f, screenHeight / 2.0f};
game->camera.rotation = 0.0f; game->camera.rotation = 0.0f;
game->camera.zoom = 1.0f; game->camera.zoom = 3.0f;
game->frameDuration = 0.16f; game->frameDuration = 0.16f;
game->terrainTileset = bzTilesetCreate( &(BzTilesetDesc) { game->terrainTileset = bzTilesetCreate( &(BzTilesetDesc) {
@@ -188,6 +190,9 @@ void deinit(void *userData) {
Game gameCopy = *game; Game gameCopy = *game;
InputState inputCopy = *input; InputState inputCopy = *input;
// Destroy queries
ecs_query_fini(inputCopy.queries.selected);
ecs_fini(ECS); ecs_fini(ECS);
ECS = NULL; ECS = NULL;
@@ -265,19 +270,33 @@ void imguiRender(float dt, void *userData) {
igText("Input state: %s", inputState); igText("Input state: %s", inputState);
if (igCollapsingHeader_TreeNodeFlags("Selection", 0)) { if (igCollapsingHeader_TreeNodeFlags("Selection", 0)) {
switch (input->state) { switch (input->state) {
case INPUT_SELECTED_UNITS: case INPUT_SELECTED_UNITS: {
igText("Selected units:"); igText("Selected units:");
ecs_iter_t it = ecs_query_iter(ECS, input->unitSelectedQuery); ecs_iter_t it = ecs_query_iter(ECS, input->queries.selected);
while (ecs_iter_next(&it)) { while (ecs_iter_next(&it)) {
for (i32 i = 0; i < it.count; i++) { for (i32 i = 0; i < it.count; i++) {
igText("\t%llu", it.entities[i]); ecs_entity_t entity = it.entities[i];
igText("\tEntity %llu", entity);
} }
} }
break; break;
case INPUT_SELECTED_OBJECT: }
break; case INPUT_SELECTED_OBJECT: {
case INPUT_SELECTED_BUILDING: igText("Selected objects:");
ecs_iter_t it = ecs_query_iter(ECS, input->queries.selected);
while (ecs_iter_next(&it)) {
for (i32 i = 0; i < it.count; i++) {
ecs_entity_t entity = it.entities[i];
if (ecs_has(ECS, entity, Harvestable) &&
ecs_has(ECS, entity, Resource)) {
Resource res = *ecs_get(ECS, entity, Resource);
const char *resName = getResourceTypePrettyName(res.type);
igText("\tEntity %llu: %d %s", entity, res.amount, resName);
}
}
}
break; break;
}
default: default:
igText("NONE"); igText("NONE");
break; break;

View File

@@ -47,6 +47,9 @@ bool initEntityObjectsLayer(BzTileMap *map, BzTileObjectGroup *objectGroup) {
.elapsed=i * 0.1f, .elapsed=i * 0.1f,
}); });
ecs_set(ECS, e, AnimationType, {ANIM_IDLE}); ecs_set(ECS, e, AnimationType, {ANIM_IDLE});
ecs_add_id(ECS, e, Selectable);
ecs_add_id(ECS, e, Unit);
ecs_add_id(ECS, e, Worker);
//EntityArms arms = { //EntityArms arms = {
// .left=ecs_new_id(ECS), // .left=ecs_new_id(ECS),
// .right=ecs_new_id(ECS), // .right=ecs_new_id(ECS),
@@ -84,6 +87,7 @@ bool initBuildingsLayer(BzTileMap *map, BzTileLayer *layer) {
ownerTile = bzTilesetGetTile(buildingTileset, ownerTile); ownerTile = bzTilesetGetTile(buildingTileset, ownerTile);
ownerTile = getTileBuilding(ownerTile); ownerTile = getTileBuilding(ownerTile);
ecs_set(ECS, e, Owner, {.playerID=ownerTile}); ecs_set(ECS, e, Owner, {.playerID=ownerTile});
ecs_add_id(ECS, e, Selectable);
//bzTileMapUpdateCollider(&GAME.map, x, y); //bzTileMapUpdateCollider(&GAME.map, x, y);
} }
@@ -118,6 +122,8 @@ bool initTreesLayer(BzTileMap *map, BzTileLayer *layer) {
ecs_set(ECS, e, Rotation, {0}); ecs_set(ECS, e, Rotation, {0});
ecs_set(ECS, e, TextureRegion, {tileset->tiles, bzTilesetGetTileRegion(tileset, layerTile)}); ecs_set(ECS, e, TextureRegion, {tileset->tiles, bzTilesetGetTileRegion(tileset, layerTile)});
ecs_set(ECS, e, Resource, {RES_WOOD, 20}); ecs_set(ECS, e, Resource, {RES_WOOD, 20});
ecs_add_id(ECS, e, Selectable);
ecs_add_id(ECS, e, Harvestable);
} }
} }

View File

@@ -8,8 +8,8 @@
Rectangle calculateEntityBounds(Position pos, Size size); Rectangle calculateEntityBounds(Position pos, Size size);
bool getEntityBounds(ecs_entity_t entity, Position *outPos, Size *outSize, Rectangle *outBounds); bool getEntityBounds(ecs_entity_t entity, Position *outPos, Size *outSize, Rectangle *outBounds);
void pickEntity(BzSpatialGrid *entityGrid, Vector2 point); bool pickEntity(BzSpatialGrid *entityGrid, Vector2 point, ecs_entity_t tag);
void pickEntities(BzSpatialGrid *entityGrid, Rectangle area); void pickUnits(BzSpatialGrid *entityGrid, Rectangle area);
static void iterateSelectedUnits(ecs_query_t *query, void (*fn)(ecs_entity_t entity, Position *pos, Size *size)); static void iterateSelectedUnits(ecs_query_t *query, void (*fn)(ecs_entity_t entity, Position *pos, Size *size));
static void iterRemovePaths(ecs_entity_t entity, Position *pos, Size *size); static void iterRemovePaths(ecs_entity_t entity, Position *pos, Size *size);
@@ -23,7 +23,7 @@ static bool wasInputDragged(InputState *input) {
return IsMouseButtonReleased(input->LMB) && input->mouseDownElapsed > input->CLICK_LIMIT; return IsMouseButtonReleased(input->LMB) && input->mouseDownElapsed > input->CLICK_LIMIT;
} }
static bool wasInputClicked(InputState *input) { static bool wasInputClicked(InputState *input) {
return IsMouseButtonReleased(input->LMB); return IsMouseButtonReleased(input->LMB) && input->mouseDownElapsed <= input->CLICK_LIMIT;
} }
void updatePlayerInput() { void updatePlayerInput() {
@@ -34,10 +34,10 @@ void updatePlayerInput() {
Game *game = ecs_singleton_get_mut(ECS, Game); Game *game = ecs_singleton_get_mut(ECS, Game);
InputState *input = ecs_singleton_get_mut(ECS, InputState); InputState *input = ecs_singleton_get_mut(ECS, InputState);
if (IsKeyDown(KEY_W)) game->camera.target.y -= 20; if (IsKeyDown(KEY_W)) game->camera.target.y -= 5;
if (IsKeyDown(KEY_S)) game->camera.target.y += 20; if (IsKeyDown(KEY_S)) game->camera.target.y += 5;
if (IsKeyDown(KEY_A)) game->camera.target.x -= 20; if (IsKeyDown(KEY_A)) game->camera.target.x -= 5;
if (IsKeyDown(KEY_D)) game->camera.target.x += 20; if (IsKeyDown(KEY_D)) game->camera.target.x += 5;
if (IsKeyDown(KEY_Q)) game->camera.rotation--; if (IsKeyDown(KEY_Q)) game->camera.rotation--;
if (IsKeyDown(KEY_E)) game->camera.rotation++; if (IsKeyDown(KEY_E)) game->camera.rotation++;
@@ -57,30 +57,39 @@ void updatePlayerInput() {
Vector2 worldPos = GetScreenToWorld2D(GetMousePosition(), game->camera); Vector2 worldPos = GetScreenToWorld2D(GetMousePosition(), game->camera);
BzTile tileX = 0, tileY = 0; BzTile tileX = 0, tileY = 0;
bzTileMapPosToTile(map, worldPos, &tileX, &tileY); bzTileMapPosToTile(map, worldPos, &tileX, &tileY);
i32 selectedUnitCount = ecs_query_entity_count(input->unitSelectedQuery);
switch (input->state) { switch (input->state) {
case INPUT_NONE: case INPUT_NONE: {
if (wasInputDragged(input)) { if (isInputDragged(input)) {
if (selectedUnitCount > 0) { Vector2 start = input->mouseDownWorld;
input->state = INPUT_SELECTED_UNITS; Vector2 end = worldPos;
break; if (start.x > end.x) {
f32 tmp = start.x;
start.x = end.x;
end.x = tmp;
} }
if (start.y > end.y) {
} else if (wasInputClicked(input)) { f32 tmp = start.y;
// Click start.y = end.y;
end.y = tmp;
// 1. Entity
if (selectedUnitCount > 0) {
input->state = INPUT_SELECTED_UNITS;
break;
} }
input->pickArea = (Rectangle) {start.x, start.y, end.x - start.x, end.y - start.y};
// 2. Object pickUnits(game->entityGrid, input->pickArea);
}
// 3. Building i32 selectedCount = ecs_query_entity_count(input->queries.selected);
if (wasInputClicked(input)) {
if (pickEntity(game->entityGrid, input->mouseDownWorld, Unit)) {
input->state = INPUT_SELECTED_UNITS;
} else if (pickEntity(game->entityGrid, input->mouseDownWorld, Harvestable)) {
input->state = INPUT_SELECTED_OBJECT;
} else if (pickEntity(game->entityGrid, input->mouseDownWorld, Buildable)) {
input->state = INPUT_SELECTED_BUILDING;
}
} else if (wasInputDragged(input) && selectedCount > 0) {
input->state = INPUT_SELECTED_UNITS;
} }
break; break;
case INPUT_BUILDING: }
case INPUT_BUILDING: {
if (IsKeyPressed(input->ESC) || if (IsKeyPressed(input->ESC) ||
IsMouseButtonPressed(input->RMB) || IsMouseButtonPressed(input->RMB) ||
input->building == 0) { input->building == 0) {
@@ -99,15 +108,17 @@ void updatePlayerInput() {
input->buildingPos = (TilePosition) {tileX, tileY}; input->buildingPos = (TilePosition) {tileX, tileY};
input->buildingSize = (TileSize) {sizeX, sizeY}; input->buildingSize = (TileSize) {sizeX, sizeY};
break; break;
case INPUT_SELECTED_UNITS: }
case INPUT_SELECTED_UNITS: {
if (IsKeyPressed(input->ESC) || IsMouseButtonPressed(input->RMB)) { if (IsKeyPressed(input->ESC) || IsMouseButtonPressed(input->RMB)) {
ecs_remove_all(ECS, UnitSelected); ecs_remove_all(ECS, Selected);
input->state = INPUT_NONE; input->state = INPUT_NONE;
break; break;
} }
if (selectedUnitCount > 1 && wasInputDragged(input)) { i32 selectedCount = ecs_query_entity_count(input->queries.selected);
if (selectedCount > 1 && wasInputDragged(input)) {
// TODO: For click it should just move them // TODO: For click it should just move them
i32 numUnits = selectedUnitCount; i32 numUnits = selectedCount;
f32 unitSpacing = 3.5f; f32 unitSpacing = 3.5f;
bzArrayClear(input->unitPositions); bzArrayClear(input->unitPositions);
placeUnits(numUnits, unitSpacing, input->mouseDownWorld, worldPos, placeUnits(numUnits, unitSpacing, input->mouseDownWorld, worldPos,
@@ -117,10 +128,10 @@ void updatePlayerInput() {
i32 unitPosIdx = 0; i32 unitPosIdx = 0;
ecs_defer_begin(ECS); ecs_defer_begin(ECS);
iterateSelectedUnits(input->unitSelectedQuery, iterRemovePaths); iterateSelectedUnits(input->queries.selected, iterRemovePaths);
ecs_defer_end(ECS); ecs_defer_end(ECS);
ecs_iter_t it = ecs_query_iter(ECS, input->unitSelectedQuery); ecs_iter_t it = ecs_query_iter(ECS, input->queries.selected);
ecs_defer_begin(ECS); ecs_defer_begin(ECS);
while (ecs_iter_next(&it)) { while (ecs_iter_next(&it)) {
Position *pos = ecs_field(&it, Position, 1); Position *pos = ecs_field(&it, Position, 1);
@@ -149,10 +160,10 @@ void updatePlayerInput() {
ecs_defer_end(ECS); ecs_defer_end(ECS);
} else if (wasInputClicked(input)) { } else if (wasInputClicked(input)) {
ecs_defer_begin(ECS); ecs_defer_begin(ECS);
iterateSelectedUnits(input->unitSelectedQuery, iterRemovePaths); iterateSelectedUnits(input->queries.selected, iterRemovePaths);
ecs_defer_end(ECS); ecs_defer_end(ECS);
ecs_iter_t it = ecs_query_iter(ECS, input->unitSelectedQuery); ecs_iter_t it = ecs_query_iter(ECS, input->queries.selected);
ecs_defer_begin(ECS); ecs_defer_begin(ECS);
while (ecs_iter_next(&it)) { while (ecs_iter_next(&it)) {
@@ -163,12 +174,12 @@ void updatePlayerInput() {
Path path = {NULL, 0}; Path path = {NULL, 0};
pathfindAStar(&(PathfindingDesc) { pathfindAStar(&(PathfindingDesc) {
.start=pos[i], .start=pos[i],
.target=worldPos, .target=worldPos,
.map=map, .map=map,
.outPath=&path, .outPath=&path,
.pool=game->pools.pathData, .pool=game->pools.pathData,
.alloc=&game->stackAlloc .alloc=&game->stackAlloc
}); });
if (!path.paths) continue; if (!path.paths) continue;
ecs_set_ptr(ECS, entity, Path, &path); ecs_set_ptr(ECS, entity, Path, &path);
@@ -178,10 +189,16 @@ void updatePlayerInput() {
ecs_defer_end(ECS); ecs_defer_end(ECS);
} }
break; break;
}
case INPUT_SELECTED_OBJECT: case INPUT_SELECTED_OBJECT:
break;
case INPUT_SELECTED_BUILDING: case INPUT_SELECTED_BUILDING:
if (IsKeyPressed(input->ESC) || IsMouseButtonPressed(input->RMB)) {
ecs_remove_all(ECS, Selected);
input->state = INPUT_NONE;
break;
}
break; break;
} }
} }
@@ -191,26 +208,12 @@ void drawPlayerInputUI() {
BzTileMap *map = &game->map; BzTileMap *map = &game->map;
Vector2 worldPos = GetScreenToWorld2D(GetMousePosition(), game->camera); Vector2 worldPos = GetScreenToWorld2D(GetMousePosition(), game->camera);
i32 selectedUnitCount = ecs_count_id(ECS, UnitSelected); i32 selectedUnitCount = ecs_count_id(ECS, Selected);
switch (input->state) { switch (input->state) {
case INPUT_NONE: case INPUT_NONE:
if (isInputDragged(input)) { if (isInputDragged(input)) {
Vector2 start = input->mouseDownWorld; Rectangle area = input->pickArea;
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); DrawRectangleLines(area.x, area.y, area.width, area.height, RED);
pickEntities(game->entityGrid, area);
} }
break; break;
case INPUT_BUILDING: { case INPUT_BUILDING: {
@@ -243,12 +246,8 @@ void drawPlayerInputUI() {
break; break;
} }
case INPUT_SELECTED_OBJECT:
break;
case INPUT_SELECTED_BUILDING:
break;
} }
ecs_iter_t it = ecs_query_iter(ECS, input->unitSelectedQuery); ecs_iter_t it = ecs_query_iter(ECS, input->queries.selected);
rlSetLineWidth(2.0f); rlSetLineWidth(2.0f);
while (ecs_query_next(&it)) { while (ecs_query_next(&it)) {
Position *pos = ecs_field(&it, Position, 1); Position *pos = ecs_field(&it, Position, 1);
@@ -298,13 +297,15 @@ bool getEntityBounds(ecs_entity_t entity, Position *outPos, Size *outSize, Recta
return true; return true;
} }
void pickEntity(BzSpatialGrid *entityGrid, Vector2 point) { bool pickEntity(BzSpatialGrid *entityGrid, Vector2 point, ecs_entity_t tag) {
ecs_remove_all(ECS, UnitSelected); ecs_remove_all(ECS, Selected);
BzSpatialGridIter it = bzSpatialGridIter(entityGrid, point.x, point.y, 0.0f, 0.0f); BzSpatialGridIter it = bzSpatialGridIter(entityGrid, point.x, point.y, 0.0f, 0.0f);
f32 closestDst = INFINITY; f32 closestDst = INFINITY;
ecs_entity_t closest = 0; ecs_entity_t closest = 0;
while (bzSpatialGridQueryNext(&it)) { while (bzSpatialGridQueryNext(&it)) {
ecs_entity_t entity = *(ecs_entity_t *) it.data; ecs_entity_t entity = *(ecs_entity_t *) it.data;
if (!ecs_has_id(ECS, entity, Selectable)) continue;
if (!ecs_has_id(ECS, entity, tag)) continue;
Vector2 pos; Vector2 pos;
Rectangle bounds; Rectangle bounds;
if (!getEntityBounds(entity, &pos, NULL, &bounds)) continue; if (!getEntityBounds(entity, &pos, NULL, &bounds)) continue;
@@ -318,20 +319,23 @@ void pickEntity(BzSpatialGrid *entityGrid, Vector2 point) {
} }
} }
if (closest) { if (closest) {
ecs_add(ECS, closest, UnitSelected); ecs_add(ECS, closest, Selected);
return true;
} }
return false;
} }
void pickEntities(BzSpatialGrid *entityGrid, Rectangle area) { void pickUnits(BzSpatialGrid *entityGrid, Rectangle area) {
ecs_remove_all(ECS, UnitSelected); ecs_remove_all(ECS, Selected);
BzSpatialGridIter it = bzSpatialGridIter(entityGrid, area.x, area.y, area.width, area.height); BzSpatialGridIter it = bzSpatialGridIter(entityGrid, area.x, area.y, area.width, area.height);
while (bzSpatialGridQueryNext(&it)) { while (bzSpatialGridQueryNext(&it)) {
ecs_entity_t entity = *(ecs_entity_t *) it.data; ecs_entity_t entity = *(ecs_entity_t *) it.data;
if (!ecs_has_id(ECS, entity, Unit)) continue;
Rectangle bounds; Rectangle bounds;
if (!getEntityBounds(entity, NULL, NULL, &bounds)) continue; if (!getEntityBounds(entity, NULL, NULL, &bounds)) continue;
if (!CheckCollisionRecs(area, bounds)) continue; if (!CheckCollisionRecs(area, bounds)) continue;
ecs_add(ECS, entity, UnitSelected); ecs_add(ECS, entity, Selected);
} }
} }