Add basic input system

This commit is contained in:
2023-11-23 11:07:46 +01:00
parent 36690f8066
commit 19d84a5dbb
5 changed files with 280 additions and 82 deletions

View File

@@ -14,6 +14,7 @@
#include <raymath.h>
ECS_COMPONENT_DECLARE(Game);
ECS_COMPONENT_DECLARE(InputState);
ecs_world_t *ECS = NULL;
@@ -50,21 +51,27 @@ bool init(void *userData) {
ECS = ecs_init();
ECS_COMPONENT_DEFINE(ECS, Game);
initComponentIDs(ECS);
// For ecs explorer
//ecs_singleton_set(ECS, EcsRest, {0});
//ECS_IMPORT(ECS, FlecsMonitor);
ECS_COMPONENT_DEFINE(ECS, Game);
ecs_singleton_set(ECS, Game, {});
Game *game = ecs_singleton_get_mut(ECS, Game);
game->input.LMB = MOUSE_LEFT_BUTTON;
game->input.RMB = MOUSE_RIGHT_BUTTON;
game->input.MMB = MOUSE_MIDDLE_BUTTON;
ECS_COMPONENT_DEFINE(ECS, InputState);
ecs_singleton_set(ECS, InputState, {});
InputState *input = ecs_singleton_get_mut(ECS, InputState);
game->input.ESC = KEY_ESCAPE;
input->LMB = MOUSE_LEFT_BUTTON;
input->RMB = MOUSE_RIGHT_BUTTON;
input->MMB = MOUSE_MIDDLE_BUTTON;
input->ESC = KEY_ESCAPE;
input->CLICK_LIMIT = 0.2f;
input->entities = bzArrayCreate(ecs_entity_t, 16);
// init pools
@@ -156,6 +163,7 @@ bool init(void *userData) {
void deinit(void *userData) {
BZ_UNUSED(userData);
Game *game = ecs_singleton_get_mut(ECS, Game);
InputState *input = ecs_singleton_get_mut(ECS, InputState);
bzTileMapDestroy(&game->map);
bzTilesetDestroy(&game->terrainTileset);
@@ -163,10 +171,12 @@ void deinit(void *userData) {
bzTilesetDestroy(&game->entitiesTileset);
Game gameCopy = *game;
InputState inputCopy = *input;
ecs_fini(ECS);
ECS = NULL;
bzArrayDestroy(inputCopy.entities);
bzObjectPoolDestroy(gameCopy.pools.pathData);
bzSpatialGridDestroy(gameCopy.entityGrid);
}
@@ -174,74 +184,12 @@ void deinit(void *userData) {
void update(float dt, void *userData) {
BZ_UNUSED(userData);
Game *game = ecs_singleton_get_mut(ECS, Game);
char titleBuf[32];
snprintf(titleBuf, sizeof(titleBuf), "FPS: %d | %.2f ms", GetFPS(), GetFrameTime() * 1000);
SetWindowTitle(titleBuf);
ImGuiIO *io = igGetIO();
if (io->WantCaptureMouse || io->WantCaptureKeyboard)
return;
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;
InputState *input = &game->input;
if (IsMouseButtonPressed(input->LMB)) {
game->input.mouseDown = GetMousePosition();
game->input.mouseDownWorld = GetScreenToWorld2D(game->input.mouseDown, game->camera);
game->input.mouseDownElapsed = 0;
} else if (IsMouseButtonDown(input->LMB)) {
game->input.mouseDownElapsed += dt;
}
switch (input->state) {
case INPUT_NONE:
if (IsMouseButtonUp(input->LMB)) {
}
break;
case INPUT_BUILDING:
if (IsKeyPressed(input->ESC) ||
IsMouseButtonPressed(input->RMB) ||
input->building == 0) {
input->state = INPUT_NONE;
input->building = 0;
break;
}
Vector2 worldPos = GetScreenToWorld2D(GetMousePosition(), game->camera);
int tileX = (int) worldPos.x / map->tileWidth;
int tileY = (int) worldPos.y / map->tileHeight;
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:
break;
case INPUT_SELECTED_OBJECT:
break;
case INPUT_SELECTED_BUILDING:
break;
}
updatePlayerInput(NULL);
}
static bool isUnitObstructed(f32 x, f32 y, BzTileMap *map) {
@@ -299,27 +247,44 @@ static void placeUnits(i32 numUnits, f32 unitSpacing, Vector2 start, Vector2 end
void render(float dt, void *userData) {
BZ_UNUSED(userData);
Game *game = ecs_singleton_get_mut(ECS, Game);
InputState *input = ecs_singleton_get_mut(ECS, InputState);
ClearBackground(RAYWHITE);
BeginMode2D(game->camera);
bzTileMapDraw(&game->map);
InputState *input = &game->input;
Vector2 worldPos = GetScreenToWorld2D(GetMousePosition(), game->camera);
switch (input->state) {
case INPUT_NONE:
if (IsMouseButtonDown(input->LMB) && input->mouseDownElapsed > input->CLICK_LIMIT) {
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 area = {start.x, start.y, end.x - start.x, end.y - start.y};
DrawRectangleLines(area.x, area.y, area.width, area.height, RED);
}
break;
case INPUT_BUILDING: {
Color placeColor = game->input.buildingCanPlace ?
Color placeColor = input->buildingCanPlace ?
(Color) {0, 255, 0, 200} :
(Color) {255, 0, 0, 200};
BzTile width = game->map.tileWidth;
BzTile height = game->map.tileHeight;
DrawRectangleLines(game->input.buildingPos.x * width,
game->input.buildingPos.y * height,
game->input.buildingSize.sizeX * width,
game->input.buildingSize.sizeY * height, placeColor);
DrawRectangleLines(input->buildingPos.x * width,
input->buildingPos.y * height,
input->buildingSize.sizeX * width,
input->buildingSize.sizeY * height, placeColor);
break;
}
case INPUT_SELECTED_UNITS:
@@ -414,11 +379,12 @@ void render(float dt, void *userData) {
void imguiRender(float dt, void *userData) {
BZ_UNUSED(userData);
Game *game = ecs_singleton_get_mut(ECS, Game);
InputState *input = ecs_singleton_get_mut(ECS, InputState);
igSetNextWindowSize((ImVec2){300, 400}, ImGuiCond_FirstUseEver);
igBegin("Debug Menu", NULL, 0);
const char *inputState = "NONE";
switch (game->input.state) {
switch (input->state) {
case INPUT_NONE:
inputState = "NONE";
break;
@@ -437,6 +403,21 @@ void imguiRender(float dt, void *userData) {
}
igText("Input state: %s", inputState);
if (igCollapsingHeader_TreeNodeFlags("Selection", 0)) {
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));
}
break;
case INPUT_SELECTED_OBJECT:
break;
case INPUT_SELECTED_BUILDING:
break;
default:
igText("NONE");
break;
}
}
if (igCollapsingHeader_TreeNodeFlags("Resources", 0)) {
@@ -448,11 +429,11 @@ void imguiRender(float dt, void *userData) {
}
if (igCollapsingHeader_TreeNodeFlags("BuildMenu", 0)) {
for (int i = 0; i < BUILDINGS_COUNT; i++) {
if (igSelectable_Bool(getBuildingStr(i), game->input.building == i, 0, (ImVec2){0, 0}))
game->input.building = i;
if (igSelectable_Bool(getBuildingStr(i), input->building == i, 0, (ImVec2){0, 0}))
input->building = i;
}
if (game->input.building)
game->input.state = INPUT_BUILDING;
if (input->building)
input->state = INPUT_BUILDING;
}
if (igCollapsingHeader_TreeNodeFlags("DebugDraw", 0)) {