203 lines
6.9 KiB
C
203 lines
6.9 KiB
C
#include "systems.h"
|
|
#include "game_state.h"
|
|
#include "buildings.h"
|
|
#include "pathfinding.h"
|
|
#include <rlImGui.h>
|
|
#include <raymath.h>
|
|
|
|
void pickEntity(BzSpatialGrid *entityGrid, Vector2 point, ecs_entity_t **outEntities);
|
|
void pickEntities(BzSpatialGrid *entityGrid, Rectangle area, ecs_entity_t **outEntities);
|
|
|
|
void updatePlayerInput(ecs_iter_t *it) {
|
|
f32 dt = GetFrameTime();
|
|
ImGuiIO *io = igGetIO();
|
|
if (io->WantCaptureMouse || io->WantCaptureKeyboard)
|
|
return;
|
|
|
|
Game *game = ecs_singleton_get_mut(ECS, Game);
|
|
InputState *input = ecs_singleton_get_mut(ECS, InputState);
|
|
if (IsKeyDown(KEY_W)) game->camera.target.y -= 20;
|
|
if (IsKeyDown(KEY_S)) game->camera.target.y += 20;
|
|
if (IsKeyDown(KEY_A)) game->camera.target.x -= 20;
|
|
if (IsKeyDown(KEY_D)) game->camera.target.x += 20;
|
|
|
|
if (IsKeyDown(KEY_Q)) game->camera.rotation--;
|
|
if (IsKeyDown(KEY_E)) game->camera.rotation++;
|
|
|
|
|
|
game->camera.zoom += ((float) GetMouseWheelMove() * 0.05f);
|
|
BzTileMap *map = &game->map;
|
|
|
|
if (IsMouseButtonPressed(input->LMB)) {
|
|
input->mouseDown = GetMousePosition();
|
|
input->mouseDownWorld = GetScreenToWorld2D(input->mouseDown, game->camera);
|
|
input->mouseDownElapsed = 0;
|
|
} else if (IsMouseButtonDown(input->LMB)) {
|
|
input->mouseDownElapsed += dt;
|
|
}
|
|
|
|
Vector2 worldPos = GetScreenToWorld2D(GetMousePosition(), game->camera);
|
|
int tileX = (int) worldPos.x / map->tileWidth;
|
|
int tileY = (int) worldPos.y / map->tileHeight;
|
|
switch (input->state) {
|
|
case INPUT_NONE:
|
|
if (IsMouseButtonReleased(input->LMB) && input->mouseDownElapsed > input->CLICK_LIMIT) {
|
|
// Dragging
|
|
|
|
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 pickArea = {start.x, start.y, end.x - start.x, end.y - start.y};
|
|
|
|
pickEntities(game->entityGrid, pickArea, &input->entities);
|
|
if (bzArraySize(input->entities) > 0) {
|
|
input->state = INPUT_SELECTED_UNITS;
|
|
break;
|
|
}
|
|
|
|
} else if (IsMouseButtonReleased(input->LMB)) {
|
|
// Click
|
|
|
|
// 1. Entity
|
|
pickEntity(game->entityGrid, worldPos, &input->entities);
|
|
if (bzArraySize(input->entities) > 0) {
|
|
input->state = INPUT_SELECTED_UNITS;
|
|
break;
|
|
}
|
|
|
|
// 2. Object
|
|
|
|
// 3. Building
|
|
}
|
|
break;
|
|
case INPUT_BUILDING:
|
|
if (IsKeyPressed(input->ESC) ||
|
|
IsMouseButtonPressed(input->RMB) ||
|
|
input->building == 0) {
|
|
input->state = INPUT_NONE;
|
|
input->building = 0;
|
|
break;
|
|
}
|
|
BZ_ASSERT(input->building);
|
|
BzTile sizeX = 0, sizeY = 0;
|
|
getBuildingSize(input->building, &sizeX, &sizeY);
|
|
bool canPlace = canPlaceBuilding(&game->map, input->building, tileX, tileY);
|
|
if (canPlace && IsMouseButtonDown(input->LMB)) {
|
|
placeBuilding(&game->map, input->building, tileX, tileY);
|
|
}
|
|
input->buildingCanPlace = canPlace;
|
|
input->buildingPos = (TilePosition) {tileX, tileY};
|
|
input->buildingSize = (TileSize) {sizeX, sizeY};
|
|
break;
|
|
case INPUT_SELECTED_UNITS:
|
|
if (IsKeyPressed(input->ESC)) {
|
|
input->state = INPUT_NONE;
|
|
break;
|
|
}
|
|
if (IsMouseButtonPressed(input->LMB)) {
|
|
bzArrayFor(input->entities, i) {
|
|
ecs_entity_t entity = bzArrayGet(input->entities, i);
|
|
ecs_remove(ECS, entity, Path);
|
|
|
|
const Position *start = ecs_get(ECS, entity, Position);
|
|
Path path = {NULL, 0};
|
|
findPath(&(PathfindingDesc) {
|
|
.start=(TilePosition) {
|
|
start->x / game->map.tileWidth,
|
|
start->y / game->map.tileHeight,
|
|
},
|
|
.target=(TilePosition) {tileX, tileY},
|
|
.map=&game->map,
|
|
.outPath=&path,
|
|
.pool=game->pools.pathData
|
|
});
|
|
if (!path.paths) continue;
|
|
ecs_set_ptr(ECS, entity, Path, &path);
|
|
input->state = INPUT_NONE;
|
|
}
|
|
|
|
}
|
|
break;
|
|
case INPUT_SELECTED_OBJECT:
|
|
break;
|
|
case INPUT_SELECTED_BUILDING:
|
|
break;
|
|
}
|
|
}
|
|
|
|
static 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);
|
|
if (!pos)
|
|
return false;
|
|
const Size *size = ecs_get(ECS, entity, Size);
|
|
if (!size)
|
|
return false;
|
|
|
|
if (outPos) {
|
|
*outPos = *pos;
|
|
}
|
|
if (outSize) {
|
|
*outSize = *size;
|
|
}
|
|
if (outBounds) {
|
|
*outBounds = (Rectangle) {
|
|
pos->x - size->x * 0.5f,
|
|
pos->y - size->y * 0.5f,
|
|
size->x, size->y
|
|
};
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void pickEntity(BzSpatialGrid *entityGrid, Vector2 point, ecs_entity_t **outEntities) {
|
|
BZ_ASSERT(*outEntities);
|
|
bzArrayClear(*outEntities);
|
|
BzSpatialGridIter it = bzSpatialGridIter(entityGrid, point.x, point.y, 0.0f, 0.0f);
|
|
f32 closestDst = INFINITY;
|
|
ecs_entity_t closest = 0;
|
|
while (bzSpatialGridQueryNext(&it)) {
|
|
ecs_entity_t entity = *(ecs_entity_t *) it.data;
|
|
Vector2 pos;
|
|
Rectangle bounds;
|
|
if (!getEntityBounds(entity, &pos, NULL, &bounds)) continue;
|
|
|
|
if (!CheckCollisionPointRec(point, bounds)) continue;
|
|
|
|
f32 curDst = Vector2Distance(point, pos);
|
|
if (closestDst > curDst) {
|
|
closestDst = curDst;
|
|
closest = entity;
|
|
}
|
|
}
|
|
if (closest) {
|
|
bzArrayPush(*outEntities, closest);
|
|
}
|
|
}
|
|
|
|
void pickEntities(BzSpatialGrid *entityGrid, Rectangle area, ecs_entity_t **outEntities) {
|
|
BZ_ASSERT(*outEntities);
|
|
bzArrayClear(*outEntities);
|
|
|
|
BzSpatialGridIter it = bzSpatialGridIter(entityGrid, area.x, area.y, area.width, area.height);
|
|
while (bzSpatialGridQueryNext(&it)) {
|
|
ecs_entity_t entity = *(ecs_entity_t *) it.data;
|
|
Rectangle bounds;
|
|
if (!getEntityBounds(entity, NULL, NULL, &bounds)) continue;
|
|
|
|
if (!CheckCollisionRecs(area, bounds)) continue;
|
|
bzArrayPush(*outEntities, entity);
|
|
}
|
|
}
|