From fa79af2a178cb57fbddcae2e56f95c7121e3c668 Mon Sep 17 00:00:00 2001 From: Klemen Plestenjak Date: Thu, 9 Nov 2023 08:38:57 +0100 Subject: [PATCH] Separate object layers, asign layers to proper slots --- engine/CMakeLists.txt | 3 + engine/breeze.h | 1 + engine/breeze/utils/string.h | 20 +++++ engine/breeze/world/map.c | 135 +++++++++++++++++++++++++--------- engine/breeze/world/map.h | 33 ++++++++- engine/breeze/world/tileset.c | 34 ++++++--- engine/breeze/world/tileset.h | 30 ++++---- game/main.c | 40 +++++++--- tiled/test.tmx | 2 +- 9 files changed, 226 insertions(+), 72 deletions(-) create mode 100644 engine/breeze/utils/string.h diff --git a/engine/CMakeLists.txt b/engine/CMakeLists.txt index 933153c..4f47eec 100644 --- a/engine/CMakeLists.txt +++ b/engine/CMakeLists.txt @@ -3,6 +3,8 @@ project(Breeze C) set(CMAKE_C_STANDARD 11) +add_compile_definitions(DEBUG_MODE) + set(BUILD_EXAMPLES false) add_subdirectory(libs/raylib-4.5.0) @@ -38,6 +40,7 @@ set(BreezeHeaders breeze/math/vec2i.h + breeze/utils/string.h breeze/utils/tokenizer.h breeze/world/map.h diff --git a/engine/breeze.h b/engine/breeze.h index 541f45b..6e5ab05 100644 --- a/engine/breeze.h +++ b/engine/breeze.h @@ -6,6 +6,7 @@ #include "breeze/math/vec2i.h" +#include "breeze/utils/string.h" #include "breeze/utils/tokenizer.h" #include "breeze/world/map.h" diff --git a/engine/breeze/utils/string.h b/engine/breeze/utils/string.h new file mode 100644 index 0000000..ed60e6f --- /dev/null +++ b/engine/breeze/utils/string.h @@ -0,0 +1,20 @@ +#ifndef BREEZE_STRING_H +#define BREEZE_STRING_H + +#include "../defines.h" + +typedef u32 BzStringHashFunc(const char *str); + +// djb2 hash algorithm +// From: https://stackoverflow.com/questions/7666509/hash-function-for-string +// http://www.cse.yorku.ca/~oz/hash.html +static u32 bzStringDefaultHash(const char *str) { + u32 hash = 5381; + int c; + while ((c = (int) *str++)) { + hash = ((hash << 5) + hash) + c; /* hash + 33 + c */ + } + return hash; +} + +#endif //BREEZE_STRING_H diff --git a/engine/breeze/world/map.c b/engine/breeze/world/map.c index 6fc7178..c541ccb 100644 --- a/engine/breeze/world/map.c +++ b/engine/breeze/world/map.c @@ -4,6 +4,7 @@ #include "../math/vec2i.h" #include +#include BzTileMap BZ_TILEMAP_INVALID = {.isValid = false}; @@ -12,18 +13,71 @@ int16_t bzTileLayerGetTile(BzTileLayer *layer, i32 x, i32 y) { return layer->data[layer->width * y + x]; } -BzTileMap bzTileMapCreate(const BzTileMapDesc *desc) { - BzTileMap map = {}; - i32 tilesetCount = desc->tilesetCount; - if (tilesetCount == 0) { - // Auto detect tileset count. - for (i32 i = 0; i < BZ_MAX_MAP_TILESETS; i++) { - if (!desc->tilesets[i].isValid) - break; - tilesetCount++; +static void handleTileLayer(BzTileLayer *layer, cute_tiled_layer_t *cuteLayer) { + layer->id = cuteLayer->id; + layer->dataCount = cuteLayer->data_count; + layer->data = NULL; + if (layer->dataCount > 0) { + layer->data = bzAlloc(layer->dataCount * sizeof(*layer->data)); + layer->minData = layer->maxData = (i16) cuteLayer->data[0]; + for (i32 i = 0; i < layer->dataCount; i++) { + layer->data[i] = (i16) cuteLayer->data[i]; + if (layer->data[i] < layer->minData) + layer->minData = layer->data[i]; + else if (layer->data[i] > layer->maxData) + layer->maxData = layer->data[i]; } } - map.tilesetCount = tilesetCount; + + layer->width = cuteLayer->width; + layer->height = cuteLayer->height; + + layer->offsetX = cuteLayer->offsetx; + layer->offsetY = cuteLayer->offsety; + layer->opacity = cuteLayer->opacity; + +} + +// tileset.c +BzTileShape bzCuteObjectToTileShape(cute_tiled_object_t *object); + +static void handleTileObjectLayer(BzTileObjectLayer *layer, cute_tiled_layer_t *cuteLayer, + BzStringHashFunc hashFunc) { + // Count objects + layer->objectCount = 0; + cute_tiled_object_t *object = cuteLayer->objects; + while (object) { + layer->objectCount++; + object = object->next; + } + + layer->objects = bzAlloc(layer->objectCount * sizeof(*layer->objects)); + object = cuteLayer->objects; + for (i32 i = 0; i < layer->objectCount; i++) { + layer->objects[i].id = hashFunc(object->name.ptr); + layer->objects[i].shape = bzCuteObjectToTileShape(object); + object = object->next; + } + +} + +static i32 findSlot(const char *name, const BzTileLayerDesc desc[BZ_MAX_MAP_LAYERS]) { + for (i32 i = 0; i < BZ_MAX_MAP_LAYERS; i++) { + if (!desc[i].name) break; + if (strcmp(name, desc[i].name) == 0) return i; + } + + return -1; +} + +BzTileMap bzTileMapCreate(const BzTileMapDesc *desc) { + BzTileMap map = {}; + // Auto detect tileset count. + for (i32 i = 0; i < BZ_MAX_MAP_TILESETS; i++) { + if (!desc->tilesets[i].isValid) + break; + map.tilesetCount++; + } for (i32 i = 0; i < map.tilesetCount; i++) { map.tilesets[i] = desc->tilesets[i]; } @@ -40,38 +94,49 @@ BzTileMap bzTileMapCreate(const BzTileMapDesc *desc) { cute_tiled_layer_t *cuteLayer = cuteMap->layers; while (cuteLayer) { BZ_ASSERT(map.layerCount < BZ_MAX_MAP_LAYERS); + BZ_ASSERT(map.objectLayerCount < BZ_MAX_MAP_LAYERS); - BzTileLayer *layer = map.layers + map.layerCount; - layer->id = cuteLayer->id; - - layer->dataCount = cuteLayer->data_count; - layer->data = NULL; - if (layer->dataCount > 0) { - layer->data = bzAlloc(layer->dataCount * sizeof(*layer->data)); - layer->minData = layer->maxData = (i16) cuteLayer->data[0]; - for (i32 i = 0; i < layer->dataCount; i++) { - layer->data[i] = (i16) cuteLayer->data[i]; - if (layer->data[i] < layer->minData) - layer->minData = layer->data[i]; - else if (layer->data[i] > layer->maxData) - layer->maxData = layer->data[i]; + // Find slot + i32 slot = -1; + for (i32 i = 0; i < BZ_MAX_MAP_LAYERS; i++) { + const BzTileLayerDesc *layerDesc = desc->layers + i; + const BzTileObjectsDesc *objectsDesc = desc->objectLayers + i; + if (layerDesc->name && strcmp(layerDesc->name, cuteLayer->name.ptr) == 0 || + objectsDesc->name && strcmp(objectsDesc->name, cuteLayer->name.ptr) == 0) { + slot = i; + break; + } else if (!layerDesc->name && !objectsDesc->name) { + break; } } + if (slot == -1) { + cuteLayer = cuteLayer->next; + continue; + } - layer->width = cuteLayer->width; - layer->height = cuteLayer->height; + if (cuteLayer->data) { + BzTileLayer *layer = map.layers + slot; + const BzTileLayerDesc *layerDesc = desc->layers + slot; + handleTileLayer(layer, cuteLayer); + if (layerDesc->handler) layerDesc->handler(layer); + map.layerCount++; + } else { + BzTileObjectLayer *objectLayer = map.objectLayers + slot; + const BzTileObjectsDesc *objectLayerDesc = desc->objectLayers + slot; + BzStringHashFunc *hashFunc = objectLayerDesc->hashFunc; + if (!hashFunc) + hashFunc = bzStringDefaultHash; + handleTileObjectLayer(objectLayer, cuteLayer, hashFunc); + if (objectLayerDesc->handler) objectLayerDesc->handler(objectLayer); + map.objectLayerCount++; + } - layer->offsetX = cuteLayer->offsetx; - layer->offsetY = cuteLayer->offsety; - layer->opacity = cuteLayer->opacity; - - map.layerCount++; cuteLayer = cuteLayer->next; } cute_tiled_tileset_t *cuteTileset = cuteMap->tilesets; - tilesetCount = 0; - while ((cuteTileset = cuteTileset->next)) tilesetCount++; + int tilesetCount = 0; + for (; cuteTileset; cuteTileset = cuteTileset->next) tilesetCount++; BZ_ASSERT(tilesetCount == map.tilesetCount); cuteTileset = cuteMap->tilesets; @@ -155,8 +220,8 @@ bool bzTileMapCanPlace(BzTileMap *map, i32 tileX, i32 tileY, i32 sizeX, i32 size BzTileset *tileset = map->tilesets + layer->tilesetIdx; i16 tile = bzTileLayerGetTile(layer, x, y); - BzTileCollider collider = bzTilesetGetTileCollider(tileset, tile); - if (collider.type != BZ_TILE_COLLIDER_NONE) + BzTileShape collider = bzTilesetGetTileCollider(tileset, tile); + if (collider.type != BZ_TILE_SHAPE_NONE) return false; } } diff --git a/engine/breeze/world/map.h b/engine/breeze/world/map.h index 30e1c34..6aa6b9d 100644 --- a/engine/breeze/world/map.h +++ b/engine/breeze/world/map.h @@ -2,8 +2,9 @@ #define BREEZE_MAP_H #include "tileset.h" +#include "../utils/string.h" -#define BZ_MAX_MAP_LAYERS 16 +#define BZ_MAX_MAP_LAYERS 8 #define BZ_MAX_MAP_TILESETS 8 @@ -25,11 +26,36 @@ typedef struct BzTileLayer { i32 tilesetIdx; } BzTileLayer; +typedef struct BzTileObject { + u32 id; + BzTileShape shape; +} BzTileObject; + +typedef struct BzTileObjectLayer { + BzTileObject *objects; + i32 objectCount; +} BzTileObjectLayer; + +// Return true, if it should be added to map +typedef bool BzTileLayerHandler(BzTileLayer *layer); +typedef bool BzTileObjectsHandler(BzTileObjectLayer *objectLayer); + +typedef struct BzTileLayerDesc { + const char *name; // Matches map layer names + BzTileLayerHandler *handler; +} BzTileLayerDesc; +typedef struct BzTileObjectsDesc { + const char *name; // Matches map layer names + BzTileObjectsHandler *handler; + BzStringHashFunc *hashFunc; +} BzTileObjectsDesc; typedef struct BzTileMapDesc { const char *path; BzTileset tilesets[BZ_MAX_MAP_TILESETS]; - i32 tilesetCount; + + BzTileLayerDesc layers[BZ_MAX_MAP_LAYERS]; + BzTileObjectsDesc objectLayers[BZ_MAX_MAP_LAYERS]; } BzTileMapDesc; typedef struct BzTileMap { @@ -43,6 +69,9 @@ typedef struct BzTileMap { BzTileLayer layers[BZ_MAX_MAP_LAYERS]; i32 layerCount; + BzTileObjectLayer objectLayers[BZ_MAX_MAP_LAYERS]; + i32 objectLayerCount; + BzTileset tilesets[BZ_MAX_MAP_TILESETS]; i32 tilesetCount; diff --git a/engine/breeze/world/tileset.c b/engine/breeze/world/tileset.c index 0950378..48484c5 100644 --- a/engine/breeze/world/tileset.c +++ b/engine/breeze/world/tileset.c @@ -6,6 +6,25 @@ BzTileset BZ_TILESET_INVALID = {.isValid = false}; +BzTileShape bzCuteObjectToTileShape(cute_tiled_object_t *object) { + BzTileShape shape = {BZ_TILE_SHAPE_NONE}; + if (object->ellipse) + shape.type = BZ_TILE_SHAPE_ELLIPSE; + else if (object->point) + shape.type = BZ_TILE_SHAPE_POINT; + else if (!object->vertices) + shape.type = BZ_TILE_SHAPE_RECT; + else + return shape; + + shape.x = object->x; + shape.y = object->y; + shape.sizeX = object->width; + shape.sizeY = object->height; + + return shape; +} + BzTileset bzTilesetCreate(const BzTilesetDesc *desc) { BzTileset tileset = {}; cute_tiled_tileset_t *cuteTileset = cute_tiled_load_external_tileset(desc->path, NULL); @@ -24,7 +43,7 @@ BzTileset bzTilesetCreate(const BzTilesetDesc *desc) { tileset.tileCount = tileset.width * tileset.tileHeight; tileset.tileColliders = bzAlloc(tileset.tileCount * sizeof(*tileset.tileColliders)); for (i32 i = 0; i < tileset.tileCount; i++) { - tileset.tileColliders[i] = (BzTileCollider) {BZ_TILE_COLLIDER_NONE}; + tileset.tileColliders[i] = (BzTileShape) {BZ_TILE_SHAPE_NONE}; } cute_tiled_tile_descriptor_t *cuteTile = cuteTileset->tiles; @@ -34,14 +53,7 @@ BzTileset bzTilesetCreate(const BzTilesetDesc *desc) { // NOTE: Only supporting single collider (integer values) if (cuteObject) { - BzTileCollider collider = {BZ_TILE_COLLIDER_RECT}; - if (cuteObject->ellipse) - collider.type = BZ_TILE_COLLIDER_ELLIPSE; - collider.x = (i8) cuteObject->x; - collider.y = (i8) cuteObject->y; - collider.sizeX = (i8) cuteObject->width; - collider.sizeY = (i8) cuteObject->height; - + BzTileShape collider = bzCuteObjectToTileShape(cuteObject); tileset.tileColliders[cuteTile->tile_index] = collider; } } @@ -68,11 +80,11 @@ Rectangle bzTilesetGetTileRegion(BzTileset *tileset, int tileID) { return (Rectangle) {posX * tileset->tileWidth, posY * tileset->tileHeight, tileset->tileWidth, tileset->tileHeight}; } -BzTileCollider bzTilesetGetTileCollider(BzTileset *tileset, int tileID) { +BzTileShape bzTilesetGetTileCollider(BzTileset *tileset, int tileID) { tileID = tileID - tileset->startID; if (tileID < 0 || tileID >= tileset->tileCount) { - return (BzTileCollider) {.type = BZ_TILE_COLLIDER_NONE}; + return (BzTileShape) {.type = BZ_TILE_SHAPE_NONE}; } return tileset->tileColliders[tileID]; diff --git a/engine/breeze/world/tileset.h b/engine/breeze/world/tileset.h index 7166e3c..a23bb5c 100644 --- a/engine/breeze/world/tileset.h +++ b/engine/breeze/world/tileset.h @@ -10,24 +10,26 @@ typedef struct BzTilesetDesc { const char *texturePath; } BzTilesetDesc; -typedef enum BzTileColliderType { - BZ_TILE_COLLIDER_NONE, - BZ_TILE_COLLIDER_RECT, - BZ_TILE_COLLIDER_ELLIPSE -} BzTileColliderType; +typedef enum BzTileShapeType { + BZ_TILE_SHAPE_NONE, + BZ_TILE_SHAPE_POINT, + BZ_TILE_SHAPE_RECT, + BZ_TILE_SHAPE_ELLIPSE, + //BZ_TILE_SHAPE_POLYGON +} BzTileShapeType; -typedef struct BzTileCollider { - BzTileColliderType type; - u8 x; - u8 y; - u8 sizeX; - u8 sizeY; -} BzTileCollider; +typedef struct BzTileShape { + BzTileShapeType type; + f32 x; + f32 y; + f32 sizeX; + f32 sizeY; +} BzTileShape; typedef struct BzTileset { Texture2D tiles; i32 tileCount; - BzTileCollider *tileColliders; + BzTileShape *tileColliders; i32 startID; i32 tileWidth; i32 tileHeight; @@ -43,7 +45,7 @@ extern BzTileset BZ_TILESET_INVALID; BzTileset bzTilesetCreate(const BzTilesetDesc *desc); Rectangle bzTilesetGetTileRegion(BzTileset *tileset, int tileID); -BzTileCollider bzTilesetGetTileCollider(BzTileset *tileset, int tileID); +BzTileShape bzTilesetGetTileCollider(BzTileset *tileset, int tileID); void bzTilesetDestroy(BzTileset *tileset); diff --git a/game/main.c b/game/main.c index 8ee4437..27c2c10 100644 --- a/game/main.c +++ b/game/main.c @@ -15,7 +15,28 @@ typedef struct Game { static Game GAME = {}; +bool handleGameObjects(BzTileObjectLayer *objectLayer) { + for (i32 i = 0; i < objectLayer->objectCount; i++) { + BzTileObject object = objectLayer->objects[i]; + if (bzStringDefaultHash("camera") == object.id) { + printf("Got camera\n"); + GAME.camera.target.x = object.shape.x; + GAME.camera.target.y = object.shape.y; + } + } + return false; +} + bool init(Game *game) { + int screenWidth = 1280; + int screenHeight = 720; + + game->camera = (Camera2D){ 0 }; + game->camera.target = (Vector2) {0, 0}; + game->camera.offset = (Vector2) {screenWidth / 2.0f, screenHeight / 2.0f}; + game->camera.rotation = 0.0f; + game->camera.zoom = 1.0f; + game->terrainTileset = bzTilesetCreate( &(BzTilesetDesc) { .path="assets/terrain.tsj", .texturePath="assets/terrain.png" @@ -28,18 +49,19 @@ bool init(Game *game) { game->map = bzTileMapCreate(&(BzTileMapDesc) { .path="assets/maps/test.tmj", .tilesets[0]=game->terrainTileset, - .tilesets[1]=game->buildingsTileset + .tilesets[1]=game->buildingsTileset, + + .layers[0]=(BzTileLayerDesc) {"Terrain", NULL}, + .layers[1]=(BzTileLayerDesc) {"Foliage", NULL}, + .layers[2]=(BzTileLayerDesc) {"Trees", NULL}, + .layers[3]=(BzTileLayerDesc) {"TreesS", NULL}, + .layers[4]=(BzTileLayerDesc) {"Buildings", NULL}, + + .objectLayers[0]=(BzTileObjectsDesc) {"Game", handleGameObjects}, + .objectLayers[1]=(BzTileObjectsDesc ) {"Entities", NULL} }); - int screenWidth = 1280; - int screenHeight = 720; - - game->camera = (Camera2D){ 0 }; - game->camera.target = (Vector2) {0, 0}; - game->camera.offset = (Vector2) {screenWidth / 2.0f, screenHeight / 2.0f}; - game->camera.rotation = 0.0f; - game->camera.zoom = 1.0f; return true; } void deinit(Game *game) { diff --git a/tiled/test.tmx b/tiled/test.tmx index 03e59b7..8394f85 100644 --- a/tiled/test.tmx +++ b/tiled/test.tmx @@ -1,5 +1,5 @@ - +