From 88cbfe4a378c2ffb20ff2fdec9b80886b87dd404 Mon Sep 17 00:00:00 2001 From: Klemen Plestenjak Date: Mon, 8 Jan 2024 15:27:58 +0100 Subject: [PATCH] Properly handle map collisions when placing/destroying buildings --- engine/breeze/map/map.c | 12 ++++++++++++ engine/breeze/map/map.h | 1 + game/buildings.c | 14 +++++++++++--- game/buildings.h | 2 +- game/components.c | 2 ++ game/components.h | 6 ++++++ game/main.c | 10 ++++++++-- game/systems/systems.c | 16 +++++++++++++++- 8 files changed, 56 insertions(+), 7 deletions(-) diff --git a/engine/breeze/map/map.c b/engine/breeze/map/map.c index b088241..a529336 100644 --- a/engine/breeze/map/map.c +++ b/engine/breeze/map/map.c @@ -508,7 +508,19 @@ bool bzTileMapHasCollision(BzTileMap *map, i32 x, i32 y) { i32 idx = y * map->width + x; return map->collisionMap[idx]; } +void bzTileMapSetCollisions(BzTileMap *map, bool collision, i32 startX, i32 startY, i32 sizeX, i32 sizeY) { + i32 endX = startX + sizeX; + i32 endY = startY + sizeY; + BZ_ASSERT(map->collisionMap); + BZ_ASSERT(startX >= 0 && endX <= map->width && + startY >= 0 && endY <= map->height); + for (i32 y = startY; y < endY; y++) { + for (i32 x = startX; x < endX; x++) { + map->collisionMap[y * map->width + x] = collision; + } + } +} void bzTileMapUpdateCollisions(BzTileMap *map, i32 x, i32 y, i32 sizeX, i32 sizeY) { if (!map->collisionMap) return; updateCollisionMap(map, x, y, x + sizeX, y + sizeY); diff --git a/engine/breeze/map/map.h b/engine/breeze/map/map.h index 5a8e204..2baa05e 100644 --- a/engine/breeze/map/map.h +++ b/engine/breeze/map/map.h @@ -131,6 +131,7 @@ bool bzTileMapCanRayCastLine(BzTileMap *map, Vector2 from, Vector2 to); void bzTileMapDraw(BzTileMap *map); void bzTileMapDrawCollisions(BzTileMap *map); bool bzTileMapHasCollision(BzTileMap *map, i32 x, i32 y); +void bzTileMapSetCollisions(BzTileMap *map, bool collision, i32 startX, i32 startY, i32 sizeX, i32 sizeY); void bzTileMapUpdateCollisions(BzTileMap *map, i32 x, i32 y, i32 sizeX, i32 sizeY); diff --git a/game/buildings.c b/game/buildings.c index d472a14..a624f0a 100644 --- a/game/buildings.c +++ b/game/buildings.c @@ -34,7 +34,7 @@ bool canPlaceBuilding(Game *game, BuildingType type, BzTile tileX, BzTile tileY) } ecs_entity_t placeBuilding(Game *game, BuildingType type, - BzTile tileX, BzTile tileY, Owner owner) { + BzTile posX, BzTile posY, Owner owner) { if (type <= BUILDING_NONE || type >= BUILDING_COUNT) return 0; i32 sizeX, sizeY; @@ -45,9 +45,15 @@ ecs_entity_t placeBuilding(Game *game, BuildingType type, // Create entity ecs_entity_t building = entityCreateEmpty(); + ecs_add_id(ECS, building, Selectable); + ecs_set(ECS, building, Building, { + .type = type, + .pos = (Vec2i) { posX, posY }, + .size = (Vec2i) { sizeX, sizeY } + }); Position pos = { - .x = tileX * tileWidth + sizeX * tileWidth * 0.5f, - .y = tileY * tileHeight + sizeY * tileHeight * 0.5f + .x = posX * tileWidth + sizeX * tileWidth * 0.5f, + .y = posY * tileHeight + sizeY * tileHeight * 0.5f }; Size size = { .x = sizeX * tileWidth, @@ -72,6 +78,8 @@ ecs_entity_t placeBuilding(Game *game, BuildingType type, region.rec.height *= sizeY; ecs_set_ptr(ECS, building, TextureRegion, ®ion); + bzTileMapSetCollisions(&game->map, true, posX, posY, sizeX, sizeY); + switch (type) { case BUILDING_KEEP: ecs_add_id(ECS, building, Storage); diff --git a/game/buildings.h b/game/buildings.h index 6405e37..9b79208 100644 --- a/game/buildings.h +++ b/game/buildings.h @@ -10,7 +10,7 @@ typedef struct Game Game; bool canPlaceBuilding(Game *game, BuildingType type, i32 tileX, i32 tileY); -ecs_entity_t placeBuilding(Game *game, BuildingType type, i32 tileX, i32 tileY, Owner owner); +ecs_entity_t placeBuilding(Game *game, BuildingType type, i32 posX, i32 posY, Owner owner); Vector2 getPositionNearBuilding(ecs_entity_t building, Vector2 fromPos); diff --git a/game/components.c b/game/components.c index 0b3a107..051d9c2 100644 --- a/game/components.c +++ b/game/components.c @@ -33,6 +33,7 @@ ECS_TAG_DECLARE(Selectable); ECS_TAG_DECLARE(Selected); ECS_COMPONENT_DECLARE(Worker); +ECS_COMPONENT_DECLARE(Building); ECS_COMPONENT_DECLARE(Unit); ECS_TAG_DECLARE(Storage); ECS_TAG_DECLARE(Harvestable); @@ -71,6 +72,7 @@ void initComponentIDs(ecs_world_t *ecs) { ECS_TAG_DEFINE(ecs, Selected); ECS_COMPONENT_DEFINE(ecs, Worker); + ECS_COMPONENT_DEFINE(ecs, Building); ECS_COMPONENT_DEFINE(ecs, Unit); ECS_TAG_DEFINE(ecs, Storage); ECS_TAG_DEFINE(ecs, Harvestable); diff --git a/game/components.h b/game/components.h index e6c9fe1..ae46f62 100644 --- a/game/components.h +++ b/game/components.h @@ -189,6 +189,12 @@ typedef struct Unit { f32 deceleration; } Unit; extern ECS_COMPONENT_DECLARE(Unit); +typedef struct Building { + BuildingType type; + Vec2i pos; + Vec2i size; +} Building; +extern ECS_COMPONENT_DECLARE(Building); extern ECS_TAG_DECLARE(Storage); extern ECS_TAG_DECLARE(Harvestable); extern ECS_TAG_DECLARE(Buildable); diff --git a/game/main.c b/game/main.c index f097e18..979f6eb 100644 --- a/game/main.c +++ b/game/main.c @@ -645,6 +645,12 @@ void igInspectWindow(ecs_entity_t entity, bool *open) { char buf[64]; snprintf(buf, sizeof(buf), "Entity: %ld", entity); if (igBegin(buf, open, 0)) { + if (igSmallButton("Destroy")) { + ecs_delete(ECS, entity); + igEnd(); + *open = false; + return; + } if (igCollapsingHeader_TreeNodeFlags("Tags", 0)) { //igTagCheckbox("GameEntity", ECS, entity, GameEntity); igTagCheckbox("Selectable", ECS, entity, Selectable); @@ -711,7 +717,6 @@ void imguiRender(float dt, void *userData) { case INPUT_SELECTED_UNITS: case INPUT_SELECTED_OBJECT: case INPUT_SELECTED_BUILDING: { - ecs_defer_begin(ECS); ecs_iter_t it = ecs_query_iter(ECS, input->queries.selected); while (ecs_iter_next(&it)) { for (i32 i = 0; i < it.count; i++) { @@ -719,7 +724,6 @@ void imguiRender(float dt, void *userData) { igText("Entity: %ld", entity); } } - ecs_defer_end(ECS); break; } default: @@ -761,6 +765,7 @@ void imguiRender(float dt, void *userData) { } igEnd(); + ecs_defer_begin(ECS); i32 inspectLen = bzArraySize(game->debug.inspecting); for (i32 i = inspectLen - 1; i >= 0; i--) { bool open = true; @@ -769,5 +774,6 @@ void imguiRender(float dt, void *userData) { bzArrayDelSwap(game->debug.inspecting, i); } } + ecs_defer_end(ECS); } diff --git a/game/systems/systems.c b/game/systems/systems.c index fd7cff0..eecd230 100644 --- a/game/systems/systems.c +++ b/game/systems/systems.c @@ -75,7 +75,17 @@ ECS_DTOR(Arms, arms, { }) ECS_MOVE(Arms, dst, src, { *dst = *src; -}); +}) + +ECS_DTOR(Building, building, { + Vec2i pos = building->pos; + Vec2i size = building->size; + Game *game = ecs_singleton_get_mut(ECS, Game); + bzTileMapSetCollisions(&game->map, false, pos.x, pos.y, size.x, size.y); +}) +ECS_MOVE(Building, dst, src, { + *dst = *src; +}) void setupSystems() { ecs_set_hooks(ECS, SpatialGridID, { @@ -90,6 +100,10 @@ void setupSystems() { .dtor = ecs_dtor(Arms), .move_dtor = ecs_move(Arms) }); + ecs_set_hooks(ECS, Building, { + .dtor = ecs_dtor(Building), + .move_dtor = ecs_move(Building) + }); ECS_OBSERVER(ECS, entityPathRemove, EcsOnRemove, Path);