diff --git a/CMakeLists.txt b/CMakeLists.txt index e2912ec..2f6fa69 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,8 +11,11 @@ add_subdirectory(engine/) add_executable(PixelDefense ${lib_sources} - game/main.c + game/utils/buildings.h + game/common.h + game/components.h + game/main.c ) diff --git a/engine/breeze/map/map.c b/engine/breeze/map/map.c index 6e072dd..3376f3f 100644 --- a/engine/breeze/map/map.c +++ b/engine/breeze/map/map.c @@ -19,9 +19,15 @@ bool bzTileObjectsClear(BzTileObjectGroup *objectGroup, BzTileObject *objects, i BzTileLayerFunc BZ_TILE_LAYER_CLEAR = bzTileLayerClear; BzTileObjectsFunc BZ_TILE_OBJECTS_CLEAR = bzTileObjectsClear; -int16_t bzTileLayerGetTile(BzTileLayer *layer, i32 x, i32 y) { +BzTile bzTileLayerGetTile(BzTileLayer *layer, i32 x, i32 y) { return layer->data[layer->width * y + x]; } +BzTileset *bzTileLayerGetTileset(BzTileMap *map, BzTileLayer *layer) { + i32 idx = layer->tilesetIdx; + if (idx < 0 || idx >= map->tilesetCount) + return NULL; + return &map->tilesets[idx]; +} static void handleTileLayer(BzTileLayer *layer, cute_tiled_layer_t *cuteLayer) { layer->id = cuteLayer->id; @@ -313,6 +319,15 @@ static void drawObjectLayer(BzTileObjectGroup *objectLayer) { } } +BzTileLayer *bzTileMapGetLayer(BzTileMap *map, i32 slotID) { + BZ_ASSERT(slotID >= 0 && slotID < map->layerCount); + return &map->layers[slotID]; +} +BzTileObjectGroup *bzTileMapGetObjects(BzTileMap *map, i32 slotID) { + BZ_ASSERT(slotID >= 0 && slotID < map->objectGroupCount); + return &map->objectGroups[slotID]; +} + void bzTileMapDraw(BzTileMap *map) { for (i32 i = 0; i < map->layerCount; i++) { BzTileLayer *layer = map->layers + i; diff --git a/engine/breeze/map/map.h b/engine/breeze/map/map.h index 31fc91b..07fa55a 100644 --- a/engine/breeze/map/map.h +++ b/engine/breeze/map/map.h @@ -97,14 +97,15 @@ typedef struct BzTileMap { extern BzTileMap BZ_TILEMAP_INVALID; -// Return true, if you want to override data (you are responsible for cleanup, if you override) +// Return true, if you want to override data pointer (you are responsible for cleanup, if you override) typedef bool (*BzTileLayerFunc)(BzTileLayer *layer, BzTile *data, i32 dataCount); typedef bool (*BzTileObjectsFunc)(BzTileObjectGroup *objectGroup, BzTileObject *objects, i32 objectsCount); extern BzTileLayerFunc BZ_TILE_LAYER_CLEAR; extern BzTileObjectsFunc BZ_TILE_OBJECTS_CLEAR; -int16_t bzTileLayerGetTile(BzTileLayer *layer, i32 x, i32 y); +BzTile bzTileLayerGetTile(BzTileLayer *layer, i32 x, i32 y); +BzTileset *bzTileLayerGetTileset(BzTileMap *map, BzTileLayer *layer); BzTileMap bzTileMapCreate(const BzTileMapDesc *desc); void bzTileMapDestroy(BzTileMap *map); @@ -112,6 +113,9 @@ void bzTileMapDestroy(BzTileMap *map); void bzTileMapOverrideLayer(BzTileMap *map, i32 slotID, BzTileLayerFunc func); void bzTileMapOverrideObjectGroup(BzTileMap *map, i32 slotID, BzTileObjectsFunc func); +BzTileLayer *bzTileMapGetLayer(BzTileMap *map, i32 slotID); +BzTileObjectGroup *bzTileMapGetObjects(BzTileMap *map, i32 slotID); + void bzTileMapDraw(BzTileMap *map); void bzTileMapDrawColliders(BzTileMap *map); BzTileCollider bzTileMapGetCollider(BzTileMap *map, i32 x, i32 y); diff --git a/engine/breeze/map/tileset.c b/engine/breeze/map/tileset.c index 5b37267..1f35c7e 100644 --- a/engine/breeze/map/tileset.c +++ b/engine/breeze/map/tileset.c @@ -78,6 +78,11 @@ BzTileset bzTilesetCreate(const BzTilesetDesc *desc) { return tileset; } +BzTile bzTilesetGetTile(BzTileset *tileset, BzTile tile) { + tile = tile - tileset->startID; + BZ_ASSERT(tile >= tile && tile < tileset->tileCount); + return tile; +} Rectangle bzTilesetGetTileRegion(BzTileset *tileset, BzTile tileID) { tileID = tileID - tileset->startID; if (tileID < 0 || tileID >= tileset->tileCount) { diff --git a/engine/breeze/map/tileset.h b/engine/breeze/map/tileset.h index bc48bcb..0f06a97 100644 --- a/engine/breeze/map/tileset.h +++ b/engine/breeze/map/tileset.h @@ -46,6 +46,7 @@ extern BzTileset BZ_TILESET_INVALID; BzTileset bzTilesetCreate(const BzTilesetDesc *desc); +BzTile bzTilesetGetTile(BzTileset *tileset, BzTile tile); Rectangle bzTilesetGetTileRegion(BzTileset *tileset, BzTile tileID); BzTileShape bzTilesetGetTileCollider(BzTileset *tileset, BzTile tileID); diff --git a/game/components.h b/game/components.h index 6fb8286..8dcd61a 100644 --- a/game/components.h +++ b/game/components.h @@ -3,9 +3,14 @@ #include -typedef struct { - f32 x; - f32 y; -} Position, Velocity; +typedef struct TilePosition { + BzTile x; + BzTile y; +} TilePosition; + +typedef struct TileSize { + BzTile w; + BzTile h; +} TileSize; #endif //PIXELDEFENSE_COMPONENTS_H diff --git a/game/main.c b/game/main.c index 4d28d8d..697916b 100644 --- a/game/main.c +++ b/game/main.c @@ -5,6 +5,23 @@ #define BZ_ENTRYPOINT #include +#include "utils/buildings.h" + +#include "components.h" + +typedef enum Layers { + LAYER_TERRAIN = 0, + LAYER_FOLIAGE, + LAYER_TREES, + LAYER_TREES2, + LAYER_BUILDINGS, + LAYER_BUILDING_OWNER, +} Layers; + +typedef enum ObjectGroup { + OBJECTS_GAME = 0, + OBJECTS_ENTITIES, +} ObjectGroup; typedef struct Game { Camera2D camera; @@ -27,12 +44,64 @@ bool handleGameObjects(BzTileObjectGroup *objectLayer, BzTileObject *objects, i3 return true; } +bool prepareBuildingLayer(BzTileLayer *layer, BzTile *data, i32 dataCount) { + BzTileset *tileset = bzTileLayerGetTileset(&GAME.map, layer); + for (i32 i = 0; i < dataCount; i++) { + BzTile tile = bzTilesetGetTile(tileset, data[i]); + data[i] = getTileBuilding(tile); + } + return false; +} + +static void detectSize(BzTile *const data, BzTile * const ownData, + const BzTile tile, const BzTile ownerTile, + const i32 width, const i32 height, + BzTile x, BzTile y, TileSize * const max) { + if (x >= width || y >= height) return; + + BzTile *curTile = data + y * width + x; + BzTile *curOwn = ownData + y * width + x; + + if (*curTile != tile || *curOwn != ownerTile) return; + + max->w = max->w > x ? max->w : x; + max->h = max->h > y ? max->h : y; + + *curTile = 0; + *curOwn = 0; + + detectSize(data, ownData, tile, ownerTile, width, height, x + 1, y, max); + detectSize(data, ownData, tile, ownerTile, width, height, x, y + 1, max); +} + bool handleBuildLayer(BzTileLayer *layer, BzTile *data, i32 dataCount) { + ECS_COMPONENT(ECS, TilePosition); + ECS_COMPONENT(ECS, TileSize); + + BzTileMap *map = &GAME.map; + BzTileLayer *ownershipLayer = bzTileMapGetLayer(map, LAYER_BUILDING_OWNER); + BzTile *ownData = ownershipLayer->data; + for (i32 y = 0; y < layer->height; y++) { for (i32 x = 0; x < layer->width; x++) { BzTile *tile = data + y * layer->width + x; + BzTile *ownTile = ownData + y * layer->width + x; if (*tile == 0) continue; - *tile = 0; + // We have a building + TileSize size = {.w=(BzTile)x, .h=(BzTile)y}; + if (*tile != BUILDINGS_ROAD) { + detectSize(data, ownData, *tile, *ownTile, + layer->width, layer->height, (BzTile) x, (BzTile) y, &size); + } + size.w -= x - 1; + size.h -= y - 1; + + bzLogInfo("Got size: %2d %2d", size.w, size.h); + + ecs_entity_t e = ecs_new_id(ECS); + ecs_set(ECS, e, TilePosition, {.x=x, .y=y}); + ecs_set(ECS, e, TileSize, {.w=0, .h=0}); + bzTileMapUpdateCollider(&GAME.map, x, y); } } @@ -49,7 +118,6 @@ bool canBuildOn(BzTileMap *map, i32 tileX, i32 tileY, i32 sizeX, i32 sizeY) { sizeX * map->tileWidth, sizeY * map->tileHeight}; // Need to check neighbour tiles - // FIXME: Can't place right next to obstacle tileX -= 1; tileY -= 1; sizeX += 2; @@ -90,20 +158,6 @@ bool canBuildOn(BzTileMap *map, i32 tileX, i32 tileY, i32 sizeX, i32 sizeY) { return true; } -typedef enum Layers { - LAYER_TERRAIN = 0, - LAYER_FOLIAGE, - LAYER_TREES, - LAYER_TREES2, - LAYER_BUILDINGS, - LAYER_BUILDING_OWNER, -} Layers; - -typedef enum ObjectGroup { - OBJECTS_GAME = 0, - OBJECTS_ENTITIES, -} ObjectGroup; - bool init(Game *game) { int screenWidth = 1280; int screenHeight = 720; @@ -139,6 +193,7 @@ bool init(Game *game) { .objectGroups[OBJECTS_ENTITIES]=(BzTileObjectsDesc ) {"Entities"} }); + bzTileMapOverrideLayer(&game->map, LAYER_BUILDINGS, prepareBuildingLayer); bzTileMapOverrideLayer(&game->map, LAYER_BUILDINGS, handleBuildLayer); bzTileMapOverrideLayer(&game->map, LAYER_BUILDING_OWNER, BZ_TILE_LAYER_CLEAR); @@ -223,6 +278,7 @@ bool bzMain(BzAppDesc *appDesc, int argc, const char **argv) { appDesc->userData = &GAME; appDesc->useNuklear = true; + appDesc->useFlecs = true; return true; } diff --git a/game/utils/buildings.h b/game/utils/buildings.h new file mode 100644 index 0000000..971375e --- /dev/null +++ b/game/utils/buildings.h @@ -0,0 +1,114 @@ +// This file was generated by: extract_tileset_classes.py + +#include +#include + + +typedef enum BUILDINGS { + BUILDINGS_NONE, + BUILDINGS_KEEP, + BUILDINGS_GRANARY, + BUILDINGS_ARMORY, + BUILDINGS_WAREHOUSE, + BUILDINGS_MINE, + BUILDINGS_BARACKS, + BUILDINGS_ORCHARD, + BUILDINGS_ANIMAL_FARM, + BUILDINGS_FLETCHER, + BUILDINGS_SMITHY, + BUILDINGS_WORKSHOP, + BUILDINGS_FARM, + BUILDINGS_ROAD, + BUILDINGS_WALL, + BUILDINGS_GATEHOUSE, + BUILDINGS_TOWER, + BUILDINGS_SMALL_TOWER, + BUILDINGS_COUNT +} BUILDINGS; + + +static bool getTileBuilding(BzTile tile) { + switch (tile) { + case 0: + case 1: + case 2: + case 32: + case 33: + case 34: + case 64: + case 65: + case 66: + return BUILDINGS_KEEP; + case 3: + return BUILDINGS_GRANARY; + case 4: + return BUILDINGS_ARMORY; + case 5: + return BUILDINGS_WAREHOUSE; + case 6: + case 7: + return BUILDINGS_MINE; + case 8: + case 9: + case 40: + case 41: + return BUILDINGS_BARACKS; + case 10: + case 11: + case 42: + case 43: + return BUILDINGS_ORCHARD; + case 12: + case 13: + case 44: + case 45: + return BUILDINGS_ANIMAL_FARM; + case 35: + case 36: + return BUILDINGS_FLETCHER; + case 67: + case 68: + return BUILDINGS_SMITHY; + case 72: + case 73: + return BUILDINGS_WORKSHOP; + case 74: + return BUILDINGS_FARM; + case 96: + return BUILDINGS_ROAD; + case 97: + return BUILDINGS_WALL; + case 98: + return BUILDINGS_GATEHOUSE; + case 128: + case 129: + case 160: + case 161: + return BUILDINGS_TOWER; + case 130: + return BUILDINGS_SMALL_TOWER; + default: + return BUILDINGS_NONE; + } +} + +static BUILDINGS getBuildingFromStr(const char *str) { + if (strncmp("keep", str, 4)) return BUILDINGS_KEEP; + if (strncmp("granary", str, 7)) return BUILDINGS_GRANARY; + if (strncmp("armory", str, 6)) return BUILDINGS_ARMORY; + if (strncmp("warehouse", str, 9)) return BUILDINGS_WAREHOUSE; + if (strncmp("mine", str, 4)) return BUILDINGS_MINE; + if (strncmp("baracks", str, 7)) return BUILDINGS_BARACKS; + if (strncmp("orchard", str, 7)) return BUILDINGS_ORCHARD; + if (strncmp("animal_farm", str, 11)) return BUILDINGS_ANIMAL_FARM; + if (strncmp("fletcher", str, 8)) return BUILDINGS_FLETCHER; + if (strncmp("smithy", str, 6)) return BUILDINGS_SMITHY; + if (strncmp("workshop", str, 8)) return BUILDINGS_WORKSHOP; + if (strncmp("farm", str, 4)) return BUILDINGS_FARM; + if (strncmp("road", str, 4)) return BUILDINGS_ROAD; + if (strncmp("wall", str, 4)) return BUILDINGS_WALL; + if (strncmp("gatehouse", str, 9)) return BUILDINGS_GATEHOUSE; + if (strncmp("tower", str, 5)) return BUILDINGS_TOWER; + if (strncmp("small_tower", str, 11)) return BUILDINGS_SMALL_TOWER; + else return BUILDINGS_NONE; +}