Properly handle map collisions when placing/destroying buildings

This commit is contained in:
2024-01-08 15:27:58 +01:00
parent c08fca9670
commit 88cbfe4a37
8 changed files with 56 additions and 7 deletions

View File

@@ -508,7 +508,19 @@ bool bzTileMapHasCollision(BzTileMap *map, i32 x, i32 y) {
i32 idx = y * map->width + x; i32 idx = y * map->width + x;
return map->collisionMap[idx]; 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) { void bzTileMapUpdateCollisions(BzTileMap *map, i32 x, i32 y, i32 sizeX, i32 sizeY) {
if (!map->collisionMap) return; if (!map->collisionMap) return;
updateCollisionMap(map, x, y, x + sizeX, y + sizeY); updateCollisionMap(map, x, y, x + sizeX, y + sizeY);

View File

@@ -131,6 +131,7 @@ bool bzTileMapCanRayCastLine(BzTileMap *map, Vector2 from, Vector2 to);
void bzTileMapDraw(BzTileMap *map); void bzTileMapDraw(BzTileMap *map);
void bzTileMapDrawCollisions(BzTileMap *map); void bzTileMapDrawCollisions(BzTileMap *map);
bool bzTileMapHasCollision(BzTileMap *map, i32 x, i32 y); 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); void bzTileMapUpdateCollisions(BzTileMap *map, i32 x, i32 y, i32 sizeX, i32 sizeY);

View File

@@ -34,7 +34,7 @@ bool canPlaceBuilding(Game *game, BuildingType type, BzTile tileX, BzTile tileY)
} }
ecs_entity_t placeBuilding(Game *game, BuildingType type, 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) if (type <= BUILDING_NONE || type >= BUILDING_COUNT)
return 0; return 0;
i32 sizeX, sizeY; i32 sizeX, sizeY;
@@ -45,9 +45,15 @@ ecs_entity_t placeBuilding(Game *game, BuildingType type,
// Create entity // Create entity
ecs_entity_t building = entityCreateEmpty(); 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 = { Position pos = {
.x = tileX * tileWidth + sizeX * tileWidth * 0.5f, .x = posX * tileWidth + sizeX * tileWidth * 0.5f,
.y = tileY * tileHeight + sizeY * tileHeight * 0.5f .y = posY * tileHeight + sizeY * tileHeight * 0.5f
}; };
Size size = { Size size = {
.x = sizeX * tileWidth, .x = sizeX * tileWidth,
@@ -72,6 +78,8 @@ ecs_entity_t placeBuilding(Game *game, BuildingType type,
region.rec.height *= sizeY; region.rec.height *= sizeY;
ecs_set_ptr(ECS, building, TextureRegion, &region); ecs_set_ptr(ECS, building, TextureRegion, &region);
bzTileMapSetCollisions(&game->map, true, posX, posY, sizeX, sizeY);
switch (type) { switch (type) {
case BUILDING_KEEP: case BUILDING_KEEP:
ecs_add_id(ECS, building, Storage); ecs_add_id(ECS, building, Storage);

View File

@@ -10,7 +10,7 @@
typedef struct Game Game; typedef struct Game Game;
bool canPlaceBuilding(Game *game, BuildingType type, i32 tileX, i32 tileY); 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); Vector2 getPositionNearBuilding(ecs_entity_t building, Vector2 fromPos);

View File

@@ -33,6 +33,7 @@ ECS_TAG_DECLARE(Selectable);
ECS_TAG_DECLARE(Selected); ECS_TAG_DECLARE(Selected);
ECS_COMPONENT_DECLARE(Worker); ECS_COMPONENT_DECLARE(Worker);
ECS_COMPONENT_DECLARE(Building);
ECS_COMPONENT_DECLARE(Unit); ECS_COMPONENT_DECLARE(Unit);
ECS_TAG_DECLARE(Storage); ECS_TAG_DECLARE(Storage);
ECS_TAG_DECLARE(Harvestable); ECS_TAG_DECLARE(Harvestable);
@@ -71,6 +72,7 @@ void initComponentIDs(ecs_world_t *ecs) {
ECS_TAG_DEFINE(ecs, Selected); ECS_TAG_DEFINE(ecs, Selected);
ECS_COMPONENT_DEFINE(ecs, Worker); ECS_COMPONENT_DEFINE(ecs, Worker);
ECS_COMPONENT_DEFINE(ecs, Building);
ECS_COMPONENT_DEFINE(ecs, Unit); ECS_COMPONENT_DEFINE(ecs, Unit);
ECS_TAG_DEFINE(ecs, Storage); ECS_TAG_DEFINE(ecs, Storage);
ECS_TAG_DEFINE(ecs, Harvestable); ECS_TAG_DEFINE(ecs, Harvestable);

View File

@@ -189,6 +189,12 @@ typedef struct Unit {
f32 deceleration; f32 deceleration;
} Unit; } Unit;
extern ECS_COMPONENT_DECLARE(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(Storage);
extern ECS_TAG_DECLARE(Harvestable); extern ECS_TAG_DECLARE(Harvestable);
extern ECS_TAG_DECLARE(Buildable); extern ECS_TAG_DECLARE(Buildable);

View File

@@ -645,6 +645,12 @@ void igInspectWindow(ecs_entity_t entity, bool *open) {
char buf[64]; char buf[64];
snprintf(buf, sizeof(buf), "Entity: %ld", entity); snprintf(buf, sizeof(buf), "Entity: %ld", entity);
if (igBegin(buf, open, 0)) { if (igBegin(buf, open, 0)) {
if (igSmallButton("Destroy")) {
ecs_delete(ECS, entity);
igEnd();
*open = false;
return;
}
if (igCollapsingHeader_TreeNodeFlags("Tags", 0)) { if (igCollapsingHeader_TreeNodeFlags("Tags", 0)) {
//igTagCheckbox("GameEntity", ECS, entity, GameEntity); //igTagCheckbox("GameEntity", ECS, entity, GameEntity);
igTagCheckbox("Selectable", ECS, entity, Selectable); igTagCheckbox("Selectable", ECS, entity, Selectable);
@@ -711,7 +717,6 @@ void imguiRender(float dt, void *userData) {
case INPUT_SELECTED_UNITS: case INPUT_SELECTED_UNITS:
case INPUT_SELECTED_OBJECT: case INPUT_SELECTED_OBJECT:
case INPUT_SELECTED_BUILDING: { case INPUT_SELECTED_BUILDING: {
ecs_defer_begin(ECS);
ecs_iter_t it = ecs_query_iter(ECS, input->queries.selected); 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++) {
@@ -719,7 +724,6 @@ void imguiRender(float dt, void *userData) {
igText("Entity: %ld", entity); igText("Entity: %ld", entity);
} }
} }
ecs_defer_end(ECS);
break; break;
} }
default: default:
@@ -761,6 +765,7 @@ void imguiRender(float dt, void *userData) {
} }
igEnd(); igEnd();
ecs_defer_begin(ECS);
i32 inspectLen = bzArraySize(game->debug.inspecting); i32 inspectLen = bzArraySize(game->debug.inspecting);
for (i32 i = inspectLen - 1; i >= 0; i--) { for (i32 i = inspectLen - 1; i >= 0; i--) {
bool open = true; bool open = true;
@@ -769,5 +774,6 @@ void imguiRender(float dt, void *userData) {
bzArrayDelSwap(game->debug.inspecting, i); bzArrayDelSwap(game->debug.inspecting, i);
} }
} }
ecs_defer_end(ECS);
} }

View File

@@ -75,7 +75,17 @@ ECS_DTOR(Arms, arms, {
}) })
ECS_MOVE(Arms, dst, src, { ECS_MOVE(Arms, dst, src, {
*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() { void setupSystems() {
ecs_set_hooks(ECS, SpatialGridID, { ecs_set_hooks(ECS, SpatialGridID, {
@@ -90,6 +100,10 @@ void setupSystems() {
.dtor = ecs_dtor(Arms), .dtor = ecs_dtor(Arms),
.move_dtor = ecs_move(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); ECS_OBSERVER(ECS, entityPathRemove, EcsOnRemove, Path);