Add input logic for building
This commit is contained in:
@@ -18,28 +18,22 @@ bool canPlaceBuilding(BzTileMap *map, BuildingType type, BzTile tileX, BzTile ti
|
|||||||
sizeX * map->tileWidth, sizeY * map->tileHeight};
|
sizeX * map->tileWidth, sizeY * map->tileHeight};
|
||||||
|
|
||||||
// Need to check neighbour tiles
|
// Need to check neighbour tiles
|
||||||
tileX -= 1;
|
//tileX -= 1;
|
||||||
tileY -= 1;
|
//tileY -= 1;
|
||||||
sizeX += 2;
|
//sizeX += 2;
|
||||||
sizeY += 2;
|
//sizeY += 2;
|
||||||
|
|
||||||
BzTileLayer *buildLayer = bzTileMapGetLayer(map, LAYER_BUILDINGS);
|
BzTileLayer *buildLayer = bzTileMapGetLayer(map, LAYER_BUILDINGS);
|
||||||
BzTileset *tileset = bzTileLayerGetTileset(map, buildLayer);
|
BzTileset *tileset = bzTileLayerGetTileset(map, buildLayer);
|
||||||
|
|
||||||
for (i32 y = tileY; y < tileY + sizeY; y++) {
|
for (i32 y = tileY; y < tileY + sizeY; y++) {
|
||||||
for (i32 x = tileX; x < tileX + sizeX; x++) {
|
for (i32 x = tileX; x < tileX + sizeX; x++) {
|
||||||
if (x != tileX && x != tileX + sizeX - 1 &&
|
BzTile tile = bzTileLayerGetTile(buildLayer, x, y);
|
||||||
y != tileY && y != tileY + sizeY - 1) {
|
tile = bzTilesetGetTile(tileset, tile);
|
||||||
// Without padding
|
tile = getTileBuilding(tile);
|
||||||
BzTile tile = bzTileLayerGetTile(buildLayer, x, y);
|
if (tile == BUILDINGS_ROAD)
|
||||||
tile = bzTilesetGetTile(tileset, tile);
|
return false;
|
||||||
tile = getTileBuilding(tile);
|
if (bzTileMapHasCollision(map, x, y)) {
|
||||||
if (tile == BUILDINGS_ROAD)
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
f32 posX = x * map->tileWidth;
|
|
||||||
f32 posY = y * map->tileHeight;
|
|
||||||
if (bzTileMapHasCollision(map, posX, posY)) {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,12 +4,34 @@
|
|||||||
#include <breeze.h>
|
#include <breeze.h>
|
||||||
#include <flecs.h>
|
#include <flecs.h>
|
||||||
|
|
||||||
typedef enum InputState {
|
typedef enum InputType {
|
||||||
INPUT_NONE,
|
INPUT_NONE,
|
||||||
INPUT_PLACING,
|
INPUT_BUILDING,
|
||||||
INPUT_DRAGGING,
|
|
||||||
INPUT_SELECTED_UNITS,
|
INPUT_SELECTED_UNITS,
|
||||||
INPUT_SELECTED_OBJECT,
|
INPUT_SELECTED_OBJECT,
|
||||||
|
INPUT_SELECTED_BUILDING,
|
||||||
|
} InputType;
|
||||||
|
|
||||||
|
typedef struct InputState {
|
||||||
|
InputType state;
|
||||||
|
// Input mapping
|
||||||
|
MouseButton LMB;
|
||||||
|
MouseButton RMB;
|
||||||
|
MouseButton MMB;
|
||||||
|
KeyboardKey ESC;
|
||||||
|
f32 DRAG_LIMIT;
|
||||||
|
// Common
|
||||||
|
Vector2 mouseDown;
|
||||||
|
Vector2 mouseDownWorld;
|
||||||
|
f32 mouseDownElapsed;
|
||||||
|
// INPUT_BUILDING
|
||||||
|
int building;
|
||||||
|
bool buildingCanPlace;
|
||||||
|
TilePosition buildingPos;
|
||||||
|
TileSize buildingSize;
|
||||||
|
// SELECTED_UNITS
|
||||||
|
// SELECTED_OBJECTS
|
||||||
|
// SELECTED_BUILDING
|
||||||
} InputState;
|
} InputState;
|
||||||
|
|
||||||
typedef struct Game {
|
typedef struct Game {
|
||||||
@@ -21,15 +43,7 @@ typedef struct Game {
|
|||||||
BzSpatialGrid *entityGrid;
|
BzSpatialGrid *entityGrid;
|
||||||
f32 frameDuration;
|
f32 frameDuration;
|
||||||
ecs_entity_t entity;
|
ecs_entity_t entity;
|
||||||
struct {
|
InputState input;
|
||||||
InputState state;
|
|
||||||
int building;
|
|
||||||
bool buildingCanPlace;
|
|
||||||
TilePosition buildingPos;
|
|
||||||
TileSize buildingSize;
|
|
||||||
Vector2 mouseDown;
|
|
||||||
f32 mouseDownElapsed;
|
|
||||||
} input;
|
|
||||||
struct {
|
struct {
|
||||||
i64 wood;
|
i64 wood;
|
||||||
i64 iron;
|
i64 iron;
|
||||||
|
|||||||
219
game/main.c
219
game/main.c
@@ -11,6 +11,7 @@
|
|||||||
#include "pathfinding.h"
|
#include "pathfinding.h"
|
||||||
|
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
#include <raymath.h>
|
||||||
|
|
||||||
ECS_COMPONENT_DECLARE(Game);
|
ECS_COMPONENT_DECLARE(Game);
|
||||||
|
|
||||||
@@ -45,7 +46,7 @@ bool bzMain(BzAppDesc *appDesc, int argc, const char **argv) {
|
|||||||
|
|
||||||
bool init(void *userData) {
|
bool init(void *userData) {
|
||||||
BZ_UNUSED(userData);
|
BZ_UNUSED(userData);
|
||||||
SetExitKey(KEY_ESCAPE);
|
SetExitKey(0);
|
||||||
|
|
||||||
ECS = ecs_init();
|
ECS = ecs_init();
|
||||||
|
|
||||||
@@ -59,6 +60,13 @@ bool init(void *userData) {
|
|||||||
ecs_singleton_set(ECS, Game, {});
|
ecs_singleton_set(ECS, Game, {});
|
||||||
Game *game = ecs_singleton_get_mut(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;
|
||||||
|
|
||||||
|
game->input.ESC = KEY_ESCAPE;
|
||||||
|
|
||||||
|
|
||||||
// init pools
|
// init pools
|
||||||
game->pools.pathData = bzObjectPoolCreate(&(BzObjectPoolDesc) {
|
game->pools.pathData = bzObjectPoolCreate(&(BzObjectPoolDesc) {
|
||||||
.objectSize=sizeof(PathData),
|
.objectSize=sizeof(PathData),
|
||||||
@@ -141,6 +149,7 @@ bool init(void *userData) {
|
|||||||
renderCollidersSystem = renderColliders;
|
renderCollidersSystem = renderColliders;
|
||||||
|
|
||||||
game->debugDraw.mapColliders = true;
|
game->debugDraw.mapColliders = true;
|
||||||
|
game->debugDraw.spatialGrid = true;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -187,50 +196,104 @@ void update(float dt, void *userData) {
|
|||||||
game->camera.zoom += ((float) GetMouseWheelMove() * 0.05f);
|
game->camera.zoom += ((float) GetMouseWheelMove() * 0.05f);
|
||||||
BzTileMap *map = &game->map;
|
BzTileMap *map = &game->map;
|
||||||
|
|
||||||
Vector2 worldPos = GetScreenToWorld2D(GetMousePosition(), game->camera);
|
InputState *input = &game->input;
|
||||||
int tileX = (int) worldPos.x / map->tileWidth;
|
if (IsMouseButtonPressed(input->LMB)) {
|
||||||
int tileY = (int) worldPos.y / map->tileHeight;
|
game->input.mouseDown = GetMousePosition();
|
||||||
|
game->input.mouseDownWorld = GetScreenToWorld2D(game->input.mouseDown, game->camera);
|
||||||
if (IsKeyPressed(KEY_ESCAPE) || IsMouseButtonPressed(MOUSE_BUTTON_RIGHT)) {
|
game->input.mouseDownElapsed = 0;
|
||||||
game->input.state = INPUT_NONE;
|
} else if (IsMouseButtonDown(input->LMB)) {
|
||||||
}
|
game->input.mouseDownElapsed += dt;
|
||||||
if (game->input.state == INPUT_NONE) {
|
|
||||||
game->input.building = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (game->input.state) {
|
switch (input->state) {
|
||||||
case INPUT_NONE:
|
case INPUT_NONE:
|
||||||
break;
|
if (IsMouseButtonUp(input->LMB)) {
|
||||||
case INPUT_PLACING:
|
|
||||||
BZ_ASSERT(game->input.building);
|
|
||||||
BzTile sizeX = 0, sizeY = 0;
|
|
||||||
getBuildingSize(game->input.building, &sizeX, &sizeY);
|
|
||||||
bool canPlace = canPlaceBuilding(&game->map, game->input.building, tileX, tileY);
|
|
||||||
if (canPlace && IsMouseButtonDown(MOUSE_BUTTON_LEFT)) {
|
|
||||||
placeBuilding(&game->map, game->input.building, tileX, tileY);
|
|
||||||
}
|
}
|
||||||
game->input.buildingCanPlace = canPlace;
|
|
||||||
game->input.buildingPos = (TilePosition) {tileX, tileY};
|
|
||||||
game->input.buildingSize = (TileSize) {sizeX, sizeY};
|
|
||||||
break;
|
break;
|
||||||
case INPUT_DRAGGING:
|
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;
|
break;
|
||||||
case INPUT_SELECTED_UNITS:
|
case INPUT_SELECTED_UNITS:
|
||||||
break;
|
break;
|
||||||
case INPUT_SELECTED_OBJECT:
|
case INPUT_SELECTED_OBJECT:
|
||||||
break;
|
break;
|
||||||
|
case INPUT_SELECTED_BUILDING:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) {
|
|
||||||
game->input.mouseDown = GetMousePosition();
|
}
|
||||||
game->input.mouseDownElapsed = 0;
|
|
||||||
bzLogInfo("Pressed");
|
static bool isUnitObstructed(f32 x, f32 y, BzTileMap *map) {
|
||||||
} else if (IsMouseButtonDown(MOUSE_BUTTON_LEFT)) {
|
return bzTileMapHasCollision(map, x / map->tileWidth, y / map->tileHeight);
|
||||||
game->input.mouseDownElapsed += dt;
|
}
|
||||||
bzLogInfo("Down: %.2f", game->input.mouseDownElapsed);
|
|
||||||
} else if (IsMouseButtonReleased(MOUSE_BUTTON_LEFT)) {
|
static bool canPlaceUnit(Vector2 pos, f32 space, BzTileMap *map) {
|
||||||
bzLogInfo("Released");
|
for (i32 y = -1; y <= 1; y++) {
|
||||||
|
for (i32 x = -1; x <= 1; x++) {
|
||||||
|
if (isUnitObstructed(pos.x + x * space, pos.y + y * space, map))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void placeUnits(i32 numUnits, f32 unitSpacing, Vector2 start, Vector2 end, BzTileMap *map, Vector2 **outPlaces) {
|
||||||
|
BZ_UNUSED(outPlaces);
|
||||||
|
|
||||||
|
f32 angle = Vector2Angle(start, end);
|
||||||
|
|
||||||
|
Vector2 size = {Vector2Distance(start, end), 20.0f};
|
||||||
|
Rectangle rec = {start.x, start.y, size.x, size.y};
|
||||||
|
Color color = RED;
|
||||||
|
color.a = 80;
|
||||||
|
|
||||||
|
Vector2 pos = Vector2Zero();
|
||||||
|
pos.x = unitSpacing;
|
||||||
|
|
||||||
|
for (i32 i = 0; i < numUnits; i++) {
|
||||||
|
if (pos.x + unitSpacing * 2.0f > size.x) {
|
||||||
|
pos.x = unitSpacing;
|
||||||
|
pos.y += unitSpacing * 2.0f;
|
||||||
|
}
|
||||||
|
Vector2 unitPos = Vector2Add(start, Vector2Rotate(pos, angle));
|
||||||
|
Color color = ORANGE;
|
||||||
|
if (!canPlaceUnit(unitPos, 4.0f, map)) {
|
||||||
|
color = RED;
|
||||||
|
color.a = 80;
|
||||||
|
i--;
|
||||||
|
} else {
|
||||||
|
bzArrayPush(*outPlaces, unitPos);
|
||||||
|
}
|
||||||
|
DrawCircle(unitPos.x, unitPos.y, 2.0f, color);
|
||||||
|
pos.x += unitSpacing * 2.0f;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char buf[128];
|
||||||
|
snprintf(buf, sizeof(buf), "Num units: %d", bzArraySize(*outPlaces));
|
||||||
|
DrawText(buf, 800, 200, 32, BLUE);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void render(float dt, void *userData) {
|
void render(float dt, void *userData) {
|
||||||
@@ -242,24 +305,72 @@ void render(float dt, void *userData) {
|
|||||||
|
|
||||||
bzTileMapDraw(&game->map);
|
bzTileMapDraw(&game->map);
|
||||||
|
|
||||||
if (game->input.building) {
|
InputState *input = &game->input;
|
||||||
Color placeColor = game->input.buildingCanPlace ?
|
switch (input->state) {
|
||||||
(Color) {0, 255, 0, 200} :
|
case INPUT_NONE:
|
||||||
(Color) {255, 0, 0, 200};
|
break;
|
||||||
|
case INPUT_BUILDING: {
|
||||||
|
Color placeColor = game->input.buildingCanPlace ?
|
||||||
|
(Color) {0, 255, 0, 200} :
|
||||||
|
(Color) {255, 0, 0, 200};
|
||||||
|
|
||||||
BzTile width = game->map.tileWidth;
|
BzTile width = game->map.tileWidth;
|
||||||
BzTile height = game->map.tileHeight;
|
BzTile height = game->map.tileHeight;
|
||||||
DrawRectangleLines(game->input.buildingPos.x * width,
|
DrawRectangleLines(game->input.buildingPos.x * width,
|
||||||
game->input.buildingPos.y * height,
|
game->input.buildingPos.y * height,
|
||||||
game->input.buildingSize.sizeX * width,
|
game->input.buildingSize.sizeX * width,
|
||||||
game->input.buildingSize.sizeY * height, placeColor);
|
game->input.buildingSize.sizeY * height, placeColor);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case INPUT_SELECTED_UNITS:
|
||||||
|
break;
|
||||||
|
case INPUT_SELECTED_OBJECT:
|
||||||
|
break;
|
||||||
|
case INPUT_SELECTED_BUILDING:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
Vector2 worldPos = GetScreenToWorld2D(GetMousePosition(), game->camera);
|
Vector2 worldPos = GetScreenToWorld2D(GetMousePosition(), game->camera);
|
||||||
int tileX = (int) worldPos.x / 16;
|
int tileX = (int) worldPos.x / 16;
|
||||||
int tileY = (int) worldPos.y / 16;
|
int tileY = (int) worldPos.y / 16;
|
||||||
|
|
||||||
|
i32 numUnits = 240;
|
||||||
|
static Vector2 *units = NULL;
|
||||||
|
if (!units) units = bzArrayCreate(Vector2, 3);
|
||||||
|
if (IsMouseButtonDown(MOUSE_BUTTON_LEFT) && game->input.mouseDownElapsed > 0.1) {
|
||||||
|
Vector2 start = game->input.mouseDownWorld;
|
||||||
|
Vector2 end = worldPos;
|
||||||
|
//bzArrayClear(units);
|
||||||
|
placeUnits(numUnits, 3.5f, start, end, &game->map, &units);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
Vector2 size = Vector2Subtract(end, start);
|
||||||
|
|
||||||
|
DrawRectangleLines(start.x, start.y, size.x, size.y, RED);
|
||||||
|
|
||||||
|
BzSpatialGridIter it = bzSpatialGridIter(game->entityGrid, start.x, start.y, size.x, size.y);
|
||||||
|
i32 count = 0;
|
||||||
|
while (bzSpatialGridQueryNext(&it)) {
|
||||||
|
ecs_entity_t *e = it.data;
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
bzLogInfo("%d", count);
|
||||||
|
|
||||||
|
//bzArrayClear(units);
|
||||||
|
//placeUnits(numUnits, 3.5f, start, end, &game->map, &units);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static PathNode *heap = NULL;
|
static PathNode *heap = NULL;
|
||||||
if (!heap)
|
if (!heap)
|
||||||
@@ -287,6 +398,7 @@ void render(float dt, void *userData) {
|
|||||||
timeSpent *= 1000;
|
timeSpent *= 1000;
|
||||||
bzLogInfo("A* took: %.3fms", timeSpent);
|
bzLogInfo("A* took: %.3fms", timeSpent);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
ecs_progress(ECS, dt);
|
ecs_progress(ECS, dt);
|
||||||
ecs_enable(ECS, renderDebugPathSystem, game->debugDraw.path);
|
ecs_enable(ECS, renderDebugPathSystem, game->debugDraw.path);
|
||||||
@@ -305,6 +417,25 @@ void imguiRender(float dt, void *userData) {
|
|||||||
|
|
||||||
igSetNextWindowSize((ImVec2){300, 400}, ImGuiCond_FirstUseEver);
|
igSetNextWindowSize((ImVec2){300, 400}, ImGuiCond_FirstUseEver);
|
||||||
igBegin("Debug Menu", NULL, 0);
|
igBegin("Debug Menu", NULL, 0);
|
||||||
|
const char *inputState = "NONE";
|
||||||
|
switch (game->input.state) {
|
||||||
|
case INPUT_NONE:
|
||||||
|
inputState = "NONE";
|
||||||
|
break;
|
||||||
|
case INPUT_BUILDING:
|
||||||
|
inputState = "BUILDING";
|
||||||
|
break;
|
||||||
|
case INPUT_SELECTED_UNITS:
|
||||||
|
inputState = "SELECTED_UNITS";
|
||||||
|
break;
|
||||||
|
case INPUT_SELECTED_OBJECT:
|
||||||
|
inputState = "SELECTED_OBJECT";
|
||||||
|
break;
|
||||||
|
case INPUT_SELECTED_BUILDING:
|
||||||
|
inputState = "SELECTED_BUILDING";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
igText("Input state: %s", inputState);
|
||||||
if (igCollapsingHeader_TreeNodeFlags("Selection", 0)) {
|
if (igCollapsingHeader_TreeNodeFlags("Selection", 0)) {
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -321,7 +452,7 @@ void imguiRender(float dt, void *userData) {
|
|||||||
game->input.building = i;
|
game->input.building = i;
|
||||||
}
|
}
|
||||||
if (game->input.building)
|
if (game->input.building)
|
||||||
game->input.state = INPUT_PLACING;
|
game->input.state = INPUT_BUILDING;
|
||||||
|
|
||||||
}
|
}
|
||||||
if (igCollapsingHeader_TreeNodeFlags("DebugDraw", 0)) {
|
if (igCollapsingHeader_TreeNodeFlags("DebugDraw", 0)) {
|
||||||
|
|||||||
@@ -24,4 +24,7 @@ typedef struct PathfindingDesc {
|
|||||||
|
|
||||||
bool findPath(const PathfindingDesc *desc);
|
bool findPath(const PathfindingDesc *desc);
|
||||||
|
|
||||||
|
// TODO: Flowfield
|
||||||
|
void calculateFlowField();
|
||||||
|
|
||||||
#endif //PIXELDEFENSE_PATHFINDING_H
|
#endif //PIXELDEFENSE_PATHFINDING_H
|
||||||
|
|||||||
Reference in New Issue
Block a user