diff --git a/assets/terrain.tsj b/assets/terrain.tsj index ff9a7e4..488a989 100644 --- a/assets/terrain.tsj +++ b/assets/terrain.tsj @@ -8,6 +8,34 @@ "tilecount":297, "tiledversion":"1.10.2", "tileheight":16, + "tiles":[ + { + "id":185, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "ellipse":true, + "height":6, + "id":1, + "name":"collision", + "rotation":0, + "type":"", + "visible":true, + "width":6, + "x":5, + "y":8 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + } + }], "tilewidth":16, "type":"tileset", "version":"1.10", diff --git a/assets/test.json b/assets/test.json new file mode 100644 index 0000000..1d8ce85 --- /dev/null +++ b/assets/test.json @@ -0,0 +1,59 @@ +{ "columns":18, + "image":"tilemap_packed.png", + "imageheight":176, + "imagewidth":288, + "margin":0, + "name":"test", + "spacing":0, + "tilecount":198, + "tiledversion":"1.10.2", + "tileheight":16, + "tiles":[ + { + "id":0, + "objectgroup": + { + "draworder":"index", + "id":2, + "name":"", + "objects":[ + { + "height":12, + "id":1, + "name":"test", + "properties":[ + { + "name":"test", + "type":"string", + "value":"123" + }], + "rotation":0, + "type":"test", + "visible":true, + "width":12, + "x":2, + "y":2 + }, + { + "height":4, + "id":2, + "name":"", + "rotation":0, + "type":"", + "visible":true, + "width":4, + "x":6, + "y":6 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "x":0, + "y":0 + }, + "type":"grass" + }], + "tilewidth":16, + "type":"tileset", + "version":"1.10" +} \ No newline at end of file diff --git a/engine/breeze/world/map.c b/engine/breeze/world/map.c index 290c0f0..6fc7178 100644 --- a/engine/breeze/world/map.c +++ b/engine/breeze/world/map.c @@ -7,6 +7,11 @@ BzTileMap BZ_TILEMAP_INVALID = {.isValid = false}; + +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; @@ -97,6 +102,17 @@ BzTileMap bzTileMapCreate(const BzTileMapDesc *desc) { return map; } +void bzTileMapDestroy(BzTileMap *tilemap) { + for (i32 i = 0; i < tilemap->layerCount; i++) { + BzTileLayer *layer = tilemap->layers + i; + bzFree(layer->data); + layer->data = NULL; + layer->dataCount = 0; + } + *tilemap = BZ_TILEMAP_INVALID; +} + + static void drawLayer(BzTileLayer *layer, BzTileset *tileset) { if (!tileset) return; if (layer->minData == layer->maxData) return; @@ -128,17 +144,23 @@ void bzTileMapDraw(BzTileMap *map) { } } -void bzTileMapDestroy(BzTileMap *tilemap) { - for (i32 i = 0; i < tilemap->layerCount; i++) { - BzTileLayer *layer = tilemap->layers + i; - bzFree(layer->data); - layer->data = NULL; - layer->dataCount = 0; +bool bzTileMapCanPlace(BzTileMap *map, i32 tileX, i32 tileY, i32 sizeX, i32 sizeY) { + for (i32 y = tileY; y < tileY + sizeY; y++) { + for (i32 x = tileX; x < tileX + sizeX; x++) { + + for (i32 i = 0; i < map->layerCount; i++) { + BzTileLayer *layer = map->layers + i; + if (layer->tilesetIdx == -1) continue; + + BzTileset *tileset = map->tilesets + layer->tilesetIdx; + + i16 tile = bzTileLayerGetTile(layer, x, y); + BzTileCollider collider = bzTilesetGetTileCollider(tileset, tile); + if (collider.type != BZ_TILE_COLLIDER_NONE) + return false; + } + } } - *tilemap = BZ_TILEMAP_INVALID; -} - -int16_t bzTileLayerGetTile(BzTileLayer *layer, i32 x, i32 y) { - return layer->data[layer->width * y + x]; + return true; } diff --git a/engine/breeze/world/map.h b/engine/breeze/world/map.h index 105d436..30e1c34 100644 --- a/engine/breeze/world/map.h +++ b/engine/breeze/world/map.h @@ -54,9 +54,11 @@ extern BzTileMap BZ_TILEMAP_INVALID; int16_t bzTileLayerGetTile(BzTileLayer *layer, i32 x, i32 y); BzTileMap bzTileMapCreate(const BzTileMapDesc *desc); -void bzTileMapDraw(BzTileMap *map); void bzTileMapDestroy(BzTileMap *tilemap); +void bzTileMapDraw(BzTileMap *map); +bool bzTileMapCanPlace(BzTileMap *map, i32 tileX, i32 tileY, i32 sizeX, i32 sizeY); + #endif //BREEZE_MAP_H diff --git a/engine/breeze/world/tileset.c b/engine/breeze/world/tileset.c index 377ccef..e32187c 100644 --- a/engine/breeze/world/tileset.c +++ b/engine/breeze/world/tileset.c @@ -1,31 +1,57 @@ -#include +#include #include -#include - #include "tileset.h" +#include "../core/memory.h" BzTileset BZ_TILESET_INVALID = {.isValid = false}; BzTileset bzTilesetCreate(const BzTilesetDesc *desc) { BzTileset tileset = {}; - cute_tiled_tileset_t *source = cute_tiled_load_external_tileset(desc->path, NULL); + cute_tiled_tileset_t *cuteTileset = cute_tiled_load_external_tileset(desc->path, NULL); tileset.tiles = LoadTexture(desc->texturePath); - tileset.startID = source->firstgid; - tileset.tileWidth = source->tilewidth; - tileset.tileHeight = source->tileheight; + tileset.startID = cuteTileset->firstgid; + tileset.tileWidth = cuteTileset->tilewidth; + tileset.tileHeight = cuteTileset->tileheight; - tileset.offsetX = source->tileoffset_x; - tileset.offsetY = source->tileoffset_y; + tileset.offsetX = cuteTileset->tileoffset_x; + tileset.offsetY = cuteTileset->tileoffset_y; tileset.width = tileset.tiles.width / tileset.tileWidth; tileset.height = tileset.tiles.height / tileset.tileHeight; - cute_tiled_free_external_tileset(source); + 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}; + } - if (tileset.tiles.width != source->imagewidth || - tileset.tiles.height != source->imageheight) { + cute_tiled_tile_descriptor_t *cuteTile = cuteTileset->tiles; + while (cuteTile) { + if (!cuteTile->objectgroup) break; + cute_tiled_object_t *cuteObject = cuteTile->objectgroup->objects; + // NOTE: Only supporting single collider (integer values) + if (cuteObject) { + if (cuteObject->vertices) break; + + 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; + + tileset.tileColliders[cuteTile->tile_index] = collider; + } + cuteTile = cuteTile->next; + } + + cute_tiled_free_external_tileset(cuteTileset); + + if (tileset.tiles.width != cuteTileset->imagewidth || + tileset.tiles.height != cuteTileset->imageheight) { bzTilesetDestroy(&tileset); return BZ_TILESET_INVALID; } @@ -36,11 +62,23 @@ BzTileset bzTilesetCreate(const BzTilesetDesc *desc) { Rectangle bzTilesetGetTileRegion(BzTileset *tileset, int tileID) { tileID = tileID - tileset->startID; + if (tileID < 0 || tileID >= tileset->tileCount) { + return (Rectangle){}; + } int posX = tileID % tileset->width; int posY = tileID / tileset->width; return (Rectangle) {posX * tileset->tileWidth, posY * tileset->tileHeight, tileset->tileWidth, tileset->tileHeight}; } +BzTileCollider bzTilesetGetTileCollider(BzTileset *tileset, int tileID) { + tileID = tileID - tileset->startID; + + if (tileID < 0 || tileID >= tileset->tileCount) { + return (BzTileCollider) {.type = BZ_TILE_COLLIDER_NONE}; + } + + return tileset->tileColliders[tileID]; +} void bzTilesetDestroy(BzTileset *tileset) { UnloadTexture(tileset->tiles); diff --git a/engine/breeze/world/tileset.h b/engine/breeze/world/tileset.h index 78eecee..7166e3c 100644 --- a/engine/breeze/world/tileset.h +++ b/engine/breeze/world/tileset.h @@ -10,8 +10,24 @@ typedef struct BzTilesetDesc { const char *texturePath; } BzTilesetDesc; +typedef enum BzTileColliderType { + BZ_TILE_COLLIDER_NONE, + BZ_TILE_COLLIDER_RECT, + BZ_TILE_COLLIDER_ELLIPSE +} BzTileColliderType; + +typedef struct BzTileCollider { + BzTileColliderType type; + u8 x; + u8 y; + u8 sizeX; + u8 sizeY; +} BzTileCollider; + typedef struct BzTileset { Texture2D tiles; + i32 tileCount; + BzTileCollider *tileColliders; i32 startID; i32 tileWidth; i32 tileHeight; @@ -27,6 +43,7 @@ extern BzTileset BZ_TILESET_INVALID; BzTileset bzTilesetCreate(const BzTilesetDesc *desc); Rectangle bzTilesetGetTileRegion(BzTileset *tileset, int tileID); +BzTileCollider bzTilesetGetTileCollider(BzTileset *tileset, int tileID); void bzTilesetDestroy(BzTileset *tileset); diff --git a/engine/tests/CMakeLists.txt b/engine/tests/CMakeLists.txt index 0056c23..78eb081 100644 --- a/engine/tests/CMakeLists.txt +++ b/engine/tests/CMakeLists.txt @@ -5,3 +5,6 @@ target_link_libraries(window_test LINK_PRIVATE Breeze) add_executable(nuklear_test nuklear_test.c) target_link_libraries(nuklear_test LINK_PRIVATE Breeze) + +add_executable(cute_tiled_test cute_tiled_test.c) +target_link_libraries(cute_tiled_test LINK_PRIVATE Breeze) diff --git a/engine/tests/cute_tiled_test.c b/engine/tests/cute_tiled_test.c new file mode 100644 index 0000000..530aafa --- /dev/null +++ b/engine/tests/cute_tiled_test.c @@ -0,0 +1,26 @@ +#include +#include + +int main() { + cute_tiled_tileset_t *tileset = cute_tiled_load_external_tileset("test.json", NULL); + + cute_tiled_tile_descriptor_t *tile = tileset->tiles; + + printf("Tileset name: %p %s\n", tileset->name.ptr, tileset->name.ptr); + while (tile) { + cute_tiled_layer_t *layer = tile->objectgroup; + cute_tiled_object_t *object = layer->objects; + + while (object) { + printf("[%p]: ellipse:%d x:%2.f y:%2.f w:%2.f h:%2.f\n", + object->name.ptr, object->ellipse, + object->x, object->y, object->width, object->height); + + object = object->next; + } + + tile = tile->next; + } + + cute_tiled_free_external_tileset(tileset); +} \ No newline at end of file diff --git a/game/main.c b/game/main.c index 22af5dc..f73193e 100644 --- a/game/main.c +++ b/game/main.c @@ -47,6 +47,10 @@ void deinit(Game *game) { bzTilesetDestroy(&game->buildingsTileset); bzTileMapDestroy(&game->map); } + +int sizeX = 1; +int sizeY = 1; + void render(float dt, Game *game) { Camera2D *camera = &game->camera; if (IsKeyDown(KEY_W)) camera->target.y -= 20; @@ -64,15 +68,34 @@ void render(float dt, Game *game) { bzTileMapDraw(&game->map); + Vector2 worldPos = GetScreenToWorld2D(GetMousePosition(), game->camera); + int tileX = (int) worldPos.x / 16; + int tileY = (int) worldPos.y / 16; + + if (tileX != 0 && tileY != 0) { + + bool canPlace = bzTileMapCanPlace(&game->map, tileX, tileY, sizeX, sizeY); + Color placeColor = canPlace ? + (Color) {0, 255, 0, 200} : + (Color) {255, 0, 0, 200}; + + DrawRectangleLines(tileX * 16, tileY * 16, sizeX * 16, sizeY * 16, placeColor); + } + EndMode2D(); if (nk_begin(NK, "Show", nk_rect(50, 50, 220, 220), NK_WINDOW_BORDER|NK_WINDOW_MOVABLE|NK_WINDOW_CLOSABLE)) { // fixed widget pixel width nk_layout_row_static(NK, 30, 80, 1); - if (nk_button_label(NK, "button")) { - // event handling - } + nk_labelf(NK, NK_TEXT_LEFT, "tileX: %d", tileX); + nk_labelf(NK, NK_TEXT_LEFT, "tileY: %d", tileY); + + nk_labelf(NK, NK_TEXT_LEFT, "x: %d", sizeX); + nk_labelf(NK, NK_TEXT_LEFT, "y: %d", sizeY); + nk_slider_int(NK, 0, &sizeX, 10, 1); + nk_slider_int(NK, 0, &sizeY, 10, 1); + } nk_end(NK); } diff --git a/tiled/terrain.tsx b/tiled/terrain.tsx index 8953382..003d100 100644 --- a/tiled/terrain.tsx +++ b/tiled/terrain.tsx @@ -1,6 +1,16 @@ + + + + + + + + + +