diff --git a/CMakeLists.txt b/CMakeLists.txt index 496359c..6236525 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,6 +24,7 @@ add_executable(PixelDefense game/buildings.h game/components.c game/components.h + game/constants.h game/entity_factory.c game/entity_factory.h game/entrypoint.c diff --git a/engine/breeze/map/map.c b/engine/breeze/map/map.c index 63d793b..4ff275d 100644 --- a/engine/breeze/map/map.c +++ b/engine/breeze/map/map.c @@ -112,47 +112,6 @@ static void handleTileObjectLayer(BzTileObjectGroup *layer, cute_tiled_layer_t * } -static void updateCollisionMap(BzTileMap *map, i32 startX, i32 startY, i32 endX, i32 endY) { - 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] = false; - } - } - - // Top-most layer takes priority - for (i32 i = map->layerCount - 1; i >= 0; i--) { - BzTileLayer *layer = map->layers + i; - if (!layer->desc.applyColliders) continue; - if (!layer->data) continue; - if (layer->tilesetIdx == -1) continue; - BzTileset *tileset = map->tilesets + layer->tilesetIdx; - for (i32 y = startY; y < endY; y++) { - for (i32 x = startX; x < endX; x++) { - i32 idx = y * map->width + x; - if (map->collisionMap[idx]) continue; - - BzTile tile = bzTileLayerGetTile(layer, x, y); - BzTileID tileID = bzTilesetGetTileID(tileset, tile); - BzTileShape tilesetShape = bzTilesetGetTileCollider(tileset, tileID); - if (tilesetShape.type == BZ_TILE_SHAPE_NONE || - tilesetShape.type == BZ_TILE_SHAPE_POINT) - continue; - - map->collisionMap[idx] = true; - } - } - } -} - -static void createColliders(BzTileMap *map) { - map->collisionMap = bzAlloc(map->width * map->height * sizeof(*map->collisionMap)); - updateCollisionMap(map, 0, 0, map->width, map->height); -} - BzTileMap bzTileMapCreate(const BzTileMapDesc *desc) { BzTileMap map = {.backgroundColor=BLACK}; // Auto detect tileset count. @@ -257,8 +216,11 @@ BzTileMap bzTileMapCreate(const BzTileMapDesc *desc) { } cute_tiled_free_map(cuteMap); - if (desc->generateCollisionMap) - createColliders(&map); + if (desc->collisionMap) { + i32 numBytes = map.width * map.height; + map.collisionMap = bzAlloc(numBytes); + bzMemSet(map.collisionMap, 0, numBytes); + } map.isValid = true; return map; @@ -407,7 +369,7 @@ f32 bzTileMapRayCast(BzTileMap *map, Vector2 from, Vector2 to, f32 maxDst, Vecto i32 cellX = (i32) from.x; i32 cellY = (i32) from.y; - if (bzTileMapHasCollision(map, cellX, cellY)) { + if (bzTileMapHasAnyCollision(map, cellX, cellY)) { return 0.0f; } Vector2 rayLength = Vector2Zero(); @@ -503,25 +465,61 @@ void bzTileMapDrawCollisions(BzTileMap *map) { } } -bool bzTileMapHasCollision(BzTileMap *map, i32 x, i32 y) { +bool bzTileMapHasAnyCollision(BzTileMap *map, i32 x, i32 y) { if (!map->collisionMap) return false; i32 idx = y * map->width + x; - return map->collisionMap[idx]; + return map->collisionMap[idx] != 0; } -void bzTileMapSetCollisions(BzTileMap *map, bool collision, i32 startX, i32 startY, i32 sizeX, i32 sizeY) { +bool bzTileMapHasCollision(BzTileMap *map, i32 layer, i32 x, i32 y) { + BZ_ASSERT(layer >= 0 && layer < 8); + if (!map->collisionMap) return false; + i32 idx = y * map->width + x; + return (map->collisionMap[idx] & (1 << layer)) != 0; +} +void bzTileMapSetCollisions(BzTileMap *map, bool collision, i32 layer, i32 startX, i32 startY, i32 sizeX, i32 sizeY) { i32 endX = startX + sizeX; i32 endY = startY + sizeY; + BZ_ASSERT(layer >= 0 && layer < 8); 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; + i32 idxOffset = y * map->width + x; + u8 *cell = map->collisionMap + idxOffset; + if (collision) + *cell |= (1 << layer); + else + *cell &= ~(1 << layer); } } } -void bzTileMapUpdateCollisions(BzTileMap *map, i32 x, i32 y, i32 sizeX, i32 sizeY) { - if (!map->collisionMap) return; - updateCollisionMap(map, x, y, x + sizeX, y + sizeY); +void bzTileMapAddLayerCollisions(BzTileMap *map, i32 mapLayer, i32 collLayer) { + BZ_ASSERT(map); + BZ_ASSERT(mapLayer >= 0 && mapLayer < map->layerCount); + BZ_ASSERT(collLayer >= 0 && collLayer < 8); + + const i32 layerBit = (1 << collLayer); + + BzTileLayer *layer = map->layers + mapLayer; + BzTileset *tileset = map->tilesets + layer->tilesetIdx; + for (i32 y = 0; y < map->height; y++) { + for (i32 x = 0; x < map->width; x++) { + i32 idx = y * map->width + x; + if (map->collisionMap[idx]) continue; + + BzTile tile = bzTileLayerGetTile(layer, x, y); + BzTileID tileID = bzTilesetGetTileID(tileset, tile); + BzTileShape tilesetShape = bzTilesetGetTileCollider(tileset, tileID); + u8 *cell = map->collisionMap + idx; + if (tilesetShape.type == BZ_TILE_SHAPE_NONE || + tilesetShape.type == BZ_TILE_SHAPE_POINT) { + // Reset + *cell &= ~layerBit; + } else { + *cell |= layerBit; + } + } + } } diff --git a/engine/breeze/map/map.h b/engine/breeze/map/map.h index 2baa05e..2fcbaf1 100644 --- a/engine/breeze/map/map.h +++ b/engine/breeze/map/map.h @@ -32,7 +32,7 @@ typedef struct BzTileObjectsDesc { typedef struct BzTileMapDesc { const char *path; - bool generateCollisionMap; + bool collisionMap; BzTileset tilesets[BZ_MAP_MAX_TILESETS]; BzTileLayerDesc layers[BZ_MAP_MAX_LAYERS]; @@ -86,7 +86,8 @@ typedef struct BzTileMap { i32 tileWidth; i32 tileHeight; - bool *collisionMap; + u8 *collisionMap; + i32 resolution; BzTileLayer layers[BZ_MAP_MAX_LAYERS]; i32 layerCount; @@ -129,10 +130,12 @@ f32 bzTileMapRayCast(BzTileMap *map, Vector2 from, Vector2 to, f32 maxDst, Vecto 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); +bool bzTileMapHasAnyCollision(BzTileMap *map, i32 x, i32 y); +bool bzTileMapHasCollision(BzTileMap *map, i32 layer, i32 x, i32 y); +void bzTileMapSetCollisions(BzTileMap *map, bool collision, i32 layer, i32 startX, i32 startY, i32 sizeX, i32 sizeY); +void bzTileMapAddLayerCollisions(BzTileMap *map, i32 mapLayer, i32 layer); diff --git a/game/buildings.c b/game/buildings.c index 3347cdd..6c9d8ed 100644 --- a/game/buildings.c +++ b/game/buildings.c @@ -78,7 +78,7 @@ 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); + bzTileMapSetCollisions(&game->map, true, COLL_LAYER_BUILDINGS, posX, posY, sizeX, sizeY); switch (type) { case BUILDING_KEEP: diff --git a/game/constants.h b/game/constants.h new file mode 100644 index 0000000..41c17f3 --- /dev/null +++ b/game/constants.h @@ -0,0 +1,9 @@ +#ifndef PIXELDEFENSE_CONSTANTS_H +#define PIXELDEFENSE_CONSTANTS_H + +enum { + COLL_LAYER_TERRAIN = 0, + COLL_LAYER_BUILDINGS = 1, +}; + +#endif //PIXELDEFENSE_CONSTANTS_H diff --git a/game/game_state.h b/game/game_state.h index 031e1af..fe52585 100644 --- a/game/game_state.h +++ b/game/game_state.h @@ -4,6 +4,8 @@ #include #include +#include "constants.h" + typedef enum GameScreen { SCREEN_GAME, SCREEN_PAUSE_MENU, diff --git a/game/main.c b/game/main.c index 0706a62..9f35e2f 100644 --- a/game/main.c +++ b/game/main.c @@ -95,7 +95,7 @@ void unloadMap(Game *game) { void loadMap(Game *game, const char *path) { game->map = bzTileMapCreate(&(BzTileMapDesc) { .path=path, - .generateCollisionMap=true, + .collisionMap=true, .tilesets[0]=game->tileset, .layers[LAYER_TERRAIN]=(BzTileLayerDesc) {"terrain", .renderer=terrainRender, .applyColliders=true}, @@ -123,6 +123,8 @@ void loadMap(Game *game, const char *path) { game->camera.rotation = 0.0f; game->camera.zoom = 3.0f; + bzTileMapAddLayerCollisions(&game->map, LAYER_TERRAIN, COLL_LAYER_TERRAIN); + bzTileMapOverrideLayer(&game->map, LAYER_TREES, initTreesLayer); bzTileMapOverrideLayer(&game->map, LAYER_TREES2, initTreesLayer); diff --git a/game/pathfinding.c b/game/pathfinding.c index a4ff2ed..6275d77 100644 --- a/game/pathfinding.c +++ b/game/pathfinding.c @@ -192,7 +192,7 @@ bool pathfindAStar(const PathfindingDesc *desc) { x < 0 || x >= map->width) continue; // not walkable - if (bzTileMapHasCollision(map, x, y)) + if (bzTileMapHasAnyCollision(map, x, y)) continue; PathNodeRecord *curRecord = &closedSet[y * map->width + x]; if (curRecord->visited) diff --git a/game/systems/s_input.c b/game/systems/s_input.c index c167f35..396dd89 100644 --- a/game/systems/s_input.c +++ b/game/systems/s_input.c @@ -412,7 +412,7 @@ void addEntityToInspected(ecs_entity_t entity, Game *game) { } static bool isUnitObstructed(f32 x, f32 y, BzTileMap *map) { - return bzTileMapHasCollision(map, x / map->tileWidth, y / map->tileHeight); + return bzTileMapHasAnyCollision(map, x / map->tileWidth, y / map->tileHeight); } static bool canPlaceUnit(Vector2 pos, f32 space, BzTileMap *map) { diff --git a/game/systems/systems.c b/game/systems/systems.c index 600d3e6..e3fdce2 100644 --- a/game/systems/systems.c +++ b/game/systems/systems.c @@ -81,7 +81,7 @@ 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); + bzTileMapSetCollisions(&game->map, false, COLL_LAYER_BUILDINGS, pos.x, pos.y, size.x, size.y); }) ECS_MOVE(Building, dst, src, { *dst = *src;