Support for colliders

This commit is contained in:
2023-11-08 16:41:00 +01:00
parent e56c2a067e
commit 50241f9c26
10 changed files with 255 additions and 27 deletions

View File

@@ -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",

59
assets/test.json Normal file
View File

@@ -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"
}

View File

@@ -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;
}

View File

@@ -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

View File

@@ -1,31 +1,57 @@
#include <assert.h>
#include <cute_tiled.h>
#include <stdio.h>
#include <cute_tiled.h>
#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);

View File

@@ -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);

View File

@@ -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)

View File

@@ -0,0 +1,26 @@
#include <cute_tiled.h>
#include <stdio.h>
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);
}

View File

@@ -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);
}

View File

@@ -1,6 +1,16 @@
<?xml version="1.0" encoding="UTF-8"?>
<tileset version="1.10" tiledversion="1.10.2" name="terrain" tilewidth="16" tileheight="16" tilecount="297" columns="27">
<editorsettings>
<export target="../assets/terrain.tsj" format="json"/>
</editorsettings>
<image source="../assets/terrain.png" width="432" height="176"/>
<tile id="185">
<objectgroup draworder="index" id="2">
<object id="1" x="5" y="8" width="6" height="6">
<ellipse/>
</object>
</objectgroup>
</tile>
<wangsets>
<wangset name="River" type="edge" tile="-1">
<wangcolor name="" color="#1c95ff" tile="-1" probability="1"/>