Overhaul tilemap, add building ownership layer

This commit is contained in:
2023-11-09 15:46:35 +01:00
parent dd96b23d32
commit f32c19dc3d
15 changed files with 324 additions and 103 deletions

View File

@@ -107,14 +107,18 @@ int main(int argc, const char **argv) {
}
while (!WindowShouldClose()) {
float dt = GetFrameTime();
if (NK)
UpdateNuklear(NK);
if (appDesc.update)
appDesc.update(0.0f, appDesc.userData);
appDesc.update(dt, appDesc.userData);
if (ECS)
ecs_progress(ECS, dt);
BeginDrawing();
if (appDesc.render)
appDesc.render(0.0f, appDesc.userData);
appDesc.render(dt, appDesc.userData);
if (NK)
DrawNuklear(NK);
EndDrawing();

View File

@@ -1,5 +1,6 @@
#include "map.h"
#include "../core/logger.h"
#include "../core/memory.h"
#include "../math/vec2i.h"
@@ -8,6 +9,15 @@
BzTileMap BZ_TILEMAP_INVALID = {.isValid = false};
bool bzTileLayerClear(BzTileLayer *layer, BzTile *data, i32 dataCount) {
return true;
}
bool bzTileObjectsClear(BzTileObjectGroup *objectGroup, BzTileObject *objects, i32 objectCount) {
return true;
}
BzTileLayerFunc BZ_TILE_LAYER_CLEAR = bzTileLayerClear;
BzTileObjectsFunc BZ_TILE_OBJECTS_CLEAR = bzTileObjectsClear;
int16_t bzTileLayerGetTile(BzTileLayer *layer, i32 x, i32 y) {
return layer->data[layer->width * y + x];
@@ -19,9 +29,9 @@ static void handleTileLayer(BzTileLayer *layer, cute_tiled_layer_t *cuteLayer) {
layer->data = NULL;
if (layer->dataCount > 0) {
layer->data = bzAlloc(layer->dataCount * sizeof(*layer->data));
layer->minData = layer->maxData = (i16) cuteLayer->data[0];
layer->minData = layer->maxData = (BzTile) cuteLayer->data[0];
for (i32 i = 0; i < layer->dataCount; i++) {
layer->data[i] = (i16) cuteLayer->data[i];
layer->data[i] = (BzTile) cuteLayer->data[i];
if (layer->data[i] < layer->minData)
layer->minData = layer->data[i];
else if (layer->data[i] > layer->maxData)
@@ -41,7 +51,7 @@ static void handleTileLayer(BzTileLayer *layer, cute_tiled_layer_t *cuteLayer) {
// tileset.c
BzTileShape bzCuteObjectToTileShape(cute_tiled_object_t *object);
static void handleTileObjectLayer(BzTileObjectLayer *layer, cute_tiled_layer_t *cuteLayer,
static void handleTileObjectLayer(BzTileObjectGroup *layer, cute_tiled_layer_t *cuteLayer,
BzStringHashFunc hashFunc) {
// Count objects
layer->objectCount = 0;
@@ -61,12 +71,9 @@ static void handleTileObjectLayer(BzTileObjectLayer *layer, cute_tiled_layer_t *
}
static void createColliders(BzTileMap *map) {
map->collidersCount = map->width * map->height;
map->colliderMap = bzAlloc(map->collidersCount * sizeof(*map->colliderMap));
for (i32 i = 0; i < map->collidersCount; i++) {
map->colliderMap[i] = (BzTileCollider) {{BZ_TILE_SHAPE_NONE}};
}
static void updateColliders(BzTileMap *map, i32 startX, i32 startY, i32 endX, i32 endY) {
BZ_ASSERT(startX >= 0 && endX <= map->width &&
startY >= 0 && endY <= map->height);
// Top-most layer takes priority
for (i32 i = map->layerCount - 1; i >= 0; i--) {
@@ -74,8 +81,8 @@ static void createColliders(BzTileMap *map) {
if (!layer->data) continue;
if (layer->tilesetIdx == -1) continue;
BzTileset *tileset = map->tilesets + layer->tilesetIdx;
for (i32 y = 0; y < map->height; y++) {
for (i32 x = 0; x < map->width; x++) {
for (i32 y = startY; y < endY; y++) {
for (i32 x = startX; x < endX; x++) {
i32 tile = bzTileLayerGetTile(layer, x, y);
BzTileShape tilesetShape = bzTilesetGetTileCollider(tileset, tile);
if (tilesetShape.type == BZ_TILE_SHAPE_NONE ||
@@ -99,6 +106,16 @@ static void createColliders(BzTileMap *map) {
}
}
static void createColliders(BzTileMap *map) {
map->collidersCount = map->width * map->height;
map->colliderMap = bzAlloc(map->collidersCount * sizeof(*map->colliderMap));
for (i32 i = 0; i < map->collidersCount; i++) {
map->colliderMap[i] = (BzTileCollider) {{BZ_TILE_SHAPE_NONE}};
}
updateColliders(map, 0, 0, map->width, map->height);
}
BzTileMap bzTileMapCreate(const BzTileMapDesc *desc) {
BzTileMap map = {};
// Auto detect tileset count.
@@ -123,13 +140,13 @@ 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);
BZ_ASSERT(map.objectGroupCount < BZ_MAX_MAP_LAYERS);
// 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;
const BzTileObjectsDesc *objectsDesc = desc->objectGroups + i;
if (layerDesc->name && strcmp(layerDesc->name, cuteLayer->name.ptr) == 0 ||
objectsDesc->name && strcmp(objectsDesc->name, cuteLayer->name.ptr) == 0) {
slot = i;
@@ -139,33 +156,25 @@ BzTileMap bzTileMapCreate(const BzTileMapDesc *desc) {
}
}
if (slot == -1) {
bzLogWarning("Dangling layer: %s", cuteLayer->name.ptr);
cuteLayer = cuteLayer->next;
continue;
}
if (cuteLayer->data) {
BzTileLayer *layer = map.layers + slot;
const BzTileLayerDesc *layerDesc = desc->layers + slot;
layer->desc = desc->layers[slot];
handleTileLayer(layer, cuteLayer);
if (layerDesc->handler && !layerDesc->handler(layer)) {
bzFree(layer->data);
layer->data = NULL;
layer->dataCount = 0;
}
layer->hasOwnership = true;
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)) {
bzFree(objectLayer->objects);
objectLayer->objects = NULL;
objectLayer->objectCount = 0;
}
map.objectLayerCount++;
BzTileObjectGroup *objectGroup = map.objectGroups + slot;
objectGroup->desc = desc->objectGroups[slot];
if (!objectGroup->desc.hashFunc)
objectGroup->desc.hashFunc = bzStringDefaultHash;
handleTileObjectLayer(objectGroup, cuteLayer, objectGroup->desc.hashFunc);
map.objectGroupCount++;
}
cuteLayer = cuteLayer->next;
@@ -197,7 +206,6 @@ BzTileMap bzTileMapCreate(const BzTileMapDesc *desc) {
}
}
}
cute_tiled_free_map(cuteMap);
createColliders(&map);
@@ -206,28 +214,62 @@ BzTileMap bzTileMapCreate(const BzTileMapDesc *desc) {
return map;
}
void bzTileMapDestroy(BzTileMap *tilemap) {
for (i32 i = 0; i < tilemap->layerCount; i++) {
BzTileLayer *layer = tilemap->layers + i;
if (layer->data) {
void bzTileMapDestroy(BzTileMap *map) {
for (i32 i = 0; i < map->layerCount; i++) {
BzTileLayer *layer = map->layers + i;
if (layer->hasOwnership && layer->data) {
bzFree(layer->data);
layer->data = NULL;
layer->dataCount = 0;
}
}
for (i32 i = 0; i < tilemap->objectLayerCount; i++) {
BzTileObjectLayer *objectLayer = tilemap->objectLayers + i;
if (objectLayer->objects) {
for (i32 i = 0; i < map->objectGroupCount; i++) {
BzTileObjectGroup *objectLayer = map->objectGroups + i;
if (objectLayer->hasOwnership && objectLayer->objects) {
bzFree(objectLayer->objects);
objectLayer->objects = NULL;
objectLayer->objectCount = 0;
}
}
bzFree(tilemap->colliderMap);
tilemap->collidersCount = 0;
bzFree(map->colliderMap);
map->collidersCount = 0;
*tilemap = BZ_TILEMAP_INVALID;
*map = BZ_TILEMAP_INVALID;
}
void bzTileMapOverrideLayer(BzTileMap *map, i32 slotID, BzTileLayerFunc func) {
BZ_ASSERT(slotID >= 0 && slotID < map->layerCount);
BzTileLayer *layer = map->layers + slotID;
i32 dataCount = layer->dataCount;
BzTile *data = layer->data;
if (func(layer, data, dataCount)) {
if (!layer->hasOwnership) return;
bzFree(layer->data);
if (layer->data == data) {
layer->data = NULL;
layer->dataCount = 0;
}
layer->hasOwnership = false;
} else {
BZ_ASSERT(data == layer->data && dataCount == layer->dataCount);
}
}
void bzTileMapOverrideObjectGroup(BzTileMap *map, i32 slotID, BzTileObjectsFunc func) {
BZ_ASSERT(slotID >= 0 && slotID < map->objectGroupCount);
BzTileObjectGroup *objectGroup = map->objectGroups + slotID;
BzTileObject *objects = objectGroup->objects;
i32 objectCount = objectGroup->objectCount;
if (func(objectGroup, objects, objectCount)) {
bzFree(objectGroup->objects);
if (objectGroup->objects == objects) {
objectGroup->objects = NULL;
objectGroup->objectCount = 0;
}
objectGroup->hasOwnership = false;
} else {
BZ_ASSERT(objects == objectGroup->objects && objectCount == objectGroup->objectCount);
}
}
@@ -238,7 +280,7 @@ static void drawLayer(BzTileLayer *layer, BzTileset *tileset) {
for (i32 y = 0; y < layer->height; y++) {
for (i32 x = 0; x < layer->width; x++) {
i16 tile = bzTileLayerGetTile(layer, x, y);
BzTile tile = bzTileLayerGetTile(layer, x, y);
if (tile - tileset->startID != -1) {
Rectangle rec = bzTilesetGetTileRegion(tileset, tile);
DrawTextureRec(tileset->tiles, rec, drawPos, WHITE);
@@ -251,7 +293,7 @@ static void drawLayer(BzTileLayer *layer, BzTileset *tileset) {
}
static void drawObjectLayer(BzTileObjectLayer *objectLayer) {
static void drawObjectLayer(BzTileObjectGroup *objectLayer) {
Color color = ORANGE;
for (int i = 0; i < objectLayer->objectCount; i++) {
BzTileShape shape = objectLayer->objects[i].shape;
@@ -282,8 +324,8 @@ void bzTileMapDraw(BzTileMap *map) {
drawLayer(map->layers + i, tileset);
}
for (i32 i = 0; i < map->objectLayerCount; i++) {
BzTileObjectLayer *objectLayer = map->objectLayers + i;
for (i32 i = 0; i < map->objectGroupCount; i++) {
BzTileObjectGroup *objectLayer = map->objectGroups + i;
if (!objectLayer->objects) continue;
drawObjectLayer(objectLayer);
}
@@ -324,6 +366,13 @@ void bzTileMapDrawColliders(BzTileMap *map) {
}
}
void bzTileMapUpdateCollider(BzTileMap *map, i32 x, i32 y) {
i32 idx = y * map->width + x;
BZ_ASSERT(idx >= 0 && idx < map->collidersCount);
map->colliderMap[idx] = (BzTileCollider){};
updateColliders(map, x, y, x + 1, y + 1);
}
BzTileCollider bzTileMapGetCollider(BzTileMap *map, i32 x, i32 y) {
i32 idx = y * map->width + x;
if (idx < 0 || idx >= map->collidersCount) {

View File

@@ -8,14 +8,38 @@
#define BZ_MAX_MAP_TILESETS 8
#define BZ_MAP_COLLIDER_DEPTH 2
typedef struct BzTileLayer BzTileLayer;
typedef struct BzTileObject BzTileObject;
typedef struct BzTileObjectGroup BzTileObjectGroup;
typedef void (*BzTileLayerRenderFunc)(BzTileLayer *layer);
typedef void (*BzTileObjectGroupRenderFunc)(BzTileObjectGroup *objectGroup);
typedef struct BzTileLayerDesc {
const char *name; // Matches map layer names
BzTileLayerRenderFunc renderer;
} BzTileLayerDesc;
typedef struct BzTileObjectsDesc {
const char *name; // Matches map layer names
BzTileObjectGroupRenderFunc renderer;
BzStringHashFunc hashFunc;
} BzTileObjectsDesc;
typedef struct BzTileMapDesc {
const char *path;
BzTileset tilesets[BZ_MAX_MAP_TILESETS];
BzTileLayerDesc layers[BZ_MAX_MAP_LAYERS];
BzTileObjectsDesc objectGroups[BZ_MAX_MAP_LAYERS];
} BzTileMapDesc;
typedef struct BzTileLayer {
i32 id;
int16_t *data;
BzTile *data;
i32 dataCount;
i16 minData;
i16 maxData;
BzTile minData;
BzTile maxData;
i32 width;
i32 height;
@@ -26,47 +50,23 @@ typedef struct BzTileLayer {
i32 tilesetIdx;
void *userData;
BzTileLayerDesc desc;
bool hasOwnership;
} BzTileLayer;
typedef struct BzTileObject {
u32 id;
BzTileShape shape;
void *userData;
} BzTileObject;
typedef struct BzTileObjectLayer {
typedef struct BzTileObjectGroup {
BzTileObject *objects;
i32 objectCount;
} BzTileObjectLayer;
// Return true, if you want to keep data allocated
typedef bool BzTileLayerFunc(BzTileLayer *layer);
typedef bool BzTileObjectsFunc(BzTileObjectLayer *objectLayer);
BzTileObjectsDesc desc;
bool hasOwnership;
} BzTileObjectGroup;
typedef void BzTileLayerRenderFunc(BzTileLayer *layer);
typedef void BzTileObjectsRenderFunc(BzTileObjectLayer *objectLayer);
typedef struct BzTileLayerDesc {
const char *name; // Matches map layer names
BzTileLayerFunc *handler;
BzTileLayerRenderFunc *renderer;
} BzTileLayerDesc;
typedef struct BzTileObjectsDesc {
const char *name; // Matches map layer names
BzTileObjectsFunc *handler;
BzTileObjectsRenderFunc *renderer;
BzStringHashFunc *hashFunc;
} BzTileObjectsDesc;
typedef struct BzTileMapDesc {
const char *path;
BzTileset tilesets[BZ_MAX_MAP_TILESETS];
BzTileLayerDesc layers[BZ_MAX_MAP_LAYERS];
BzTileObjectsDesc objectLayers[BZ_MAX_MAP_LAYERS];
} BzTileMapDesc;
typedef struct BzTileCollider {
BzTileShape shapes[BZ_MAP_COLLIDER_DEPTH];
@@ -86,8 +86,8 @@ typedef struct BzTileMap {
BzTileLayer layers[BZ_MAX_MAP_LAYERS];
i32 layerCount;
BzTileObjectLayer objectLayers[BZ_MAX_MAP_LAYERS];
i32 objectLayerCount;
BzTileObjectGroup objectGroups[BZ_MAX_MAP_LAYERS];
i32 objectGroupCount;
BzTileset tilesets[BZ_MAX_MAP_TILESETS];
i32 tilesetCount;
@@ -97,14 +97,25 @@ typedef struct BzTileMap {
extern BzTileMap BZ_TILEMAP_INVALID;
// Return true, if you want to override data (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);
BzTileMap bzTileMapCreate(const BzTileMapDesc *desc);
void bzTileMapDestroy(BzTileMap *tilemap);
void bzTileMapDestroy(BzTileMap *map);
void bzTileMapOverrideLayer(BzTileMap *map, i32 slotID, BzTileLayerFunc func);
void bzTileMapOverrideObjectGroup(BzTileMap *map, i32 slotID, BzTileObjectsFunc func);
void bzTileMapDraw(BzTileMap *map);
void bzTileMapDrawColliders(BzTileMap *map);
BzTileCollider bzTileMapGetCollider(BzTileMap *map, i32 x, i32 y);
void bzTileMapUpdateCollider(BzTileMap *map, i32 x, i32 y);

View File

@@ -78,7 +78,7 @@ BzTileset bzTilesetCreate(const BzTilesetDesc *desc) {
return tileset;
}
Rectangle bzTilesetGetTileRegion(BzTileset *tileset, int tileID) {
Rectangle bzTilesetGetTileRegion(BzTileset *tileset, BzTile tileID) {
tileID = tileID - tileset->startID;
if (tileID < 0 || tileID >= tileset->tileCount) {
return (Rectangle){};
@@ -88,7 +88,7 @@ Rectangle bzTilesetGetTileRegion(BzTileset *tileset, int tileID) {
return (Rectangle) {posX * tileset->tileWidth, posY * tileset->tileHeight,
tileset->tileWidth, tileset->tileHeight};
}
BzTileShape bzTilesetGetTileCollider(BzTileset *tileset, int tileID) {
BzTileShape bzTilesetGetTileCollider(BzTileset *tileset, BzTile tileID) {
tileID = tileID - tileset->startID;
if (tileID < 0 || tileID >= tileset->tileCount) {

View File

@@ -5,6 +5,8 @@
#include <raylib.h>
typedef i16 BzTile;
typedef struct BzTilesetDesc {
const char *path;
const char *texturePath;
@@ -44,8 +46,8 @@ extern BzTileset BZ_TILESET_INVALID;
BzTileset bzTilesetCreate(const BzTilesetDesc *desc);
Rectangle bzTilesetGetTileRegion(BzTileset *tileset, int tileID);
BzTileShape bzTilesetGetTileCollider(BzTileset *tileset, int tileID);
Rectangle bzTilesetGetTileRegion(BzTileset *tileset, BzTile tileID);
BzTileShape bzTilesetGetTileCollider(BzTileset *tileset, BzTile tileID);
void bzTilesetDestroy(BzTileset *tileset);

View File

@@ -3,7 +3,7 @@
#include "../defines.h"
typedef u32 BzStringHashFunc(const char *str);
typedef u32 (*BzStringHashFunc)(const char *str);
// djb2 hash algorithm
// From: https://stackoverflow.com/questions/7666509/hash-function-for-string