diff options
| author | Leander Scherer <leander@schererleander.de> | 2026-03-11 23:16:32 +0100 |
|---|---|---|
| committer | Leander Scherer <leander@schererleander.de> | 2026-03-11 23:16:32 +0100 |
| commit | 9fb384552cb0a036a5978dfc40cddbbe2d29727c (patch) | |
| tree | 4814b228a5b94fee3d300221531d466bf5c0990d | |
| parent | e32c1eeed3427832b40d1e9f43a17dbec8cb56ae (diff) | |
refactor(map): replace MapManager with typed Map and object-layer loading
| -rw-r--r-- | include/map.h | 23 | ||||
| -rw-r--r-- | include/map_manager.h | 18 | ||||
| -rw-r--r-- | src/map.c | 197 | ||||
| -rw-r--r-- | src/map_manager.c | 115 |
4 files changed, 220 insertions, 133 deletions
diff --git a/include/map.h b/include/map.h new file mode 100644 index 0000000..6106dc1 --- /dev/null +++ b/include/map.h @@ -0,0 +1,23 @@ +#pragma once + +#include "raylib.h" +#include "raytmx.h" + +typedef struct { + TmxMap *map; + TmxLayer *wallLayer; + TmxLayer *groundLayer; + TmxLayer *decorLayer; +} Map; + +typedef struct Entities Entities; + +Map *LoadMap(const char *filename, Entities *entities); + +bool isCollision(Map *map, Rectangle bounds); + +void DrawMap(Map *map); +void DrawPickups(Entities *entities, Map *map); +void DrawKeys(Entities *entities, Map *map); + +void UnloadMap(Map *map); diff --git a/include/map_manager.h b/include/map_manager.h deleted file mode 100644 index 46ec63e..0000000 --- a/include/map_manager.h +++ /dev/null @@ -1,18 +0,0 @@ -#ifndef MAP_MANAGER_H -#define MAP_MANAGER_H - -#include "raytmx.h" - -typedef struct MapManager { - TmxMap *map; - TmxLayer *wallLayer; - TmxLayer *solidLayer; - TmxLayer *pickupLayer; -} MapManager; - -MapManager LoadGameMap(const char *fileName); -void UnloadGameMap(MapManager *mgr); -bool IsWallCollision(MapManager *mgr, Rectangle rect); -void DrawMap(MapManager *mgr); - -#endif diff --git a/src/map.c b/src/map.c new file mode 100644 index 0000000..398b721 --- /dev/null +++ b/src/map.c @@ -0,0 +1,197 @@ +#include "map.h" +#include "entities.h" +#include "raylib.h" + +#define RAYTMX_IMPLEMENTATION +#include "raytmx.h" + +#include <assert.h> +#include <stdlib.h> +#include <string.h> + +static TmxLayer *FindLayerByName(TmxMap *map, const char *name) { + for (uint32_t i = 0; i < map->layersLength; i++) { + if (strcmp(map->layers[i].name, name) == 0) + return &map->layers[i]; + } + return NULL; +} + +static TmxTileset *FindTileSetByGid(TmxMap *map, int gid) { + for (uint32_t i = 0; i < map->tilesetsLength; i++) { + if (map->tilesets[i].firstGid <= (uint32_t)gid && + (uint32_t)gid <= map->tilesets[i].lastGid) + return &map->tilesets[i]; + } + return NULL; +} + +static PickupType GetPickupTypeByTileId(int tileId) { + int count = sizeof(PICKUP_TILE_ID) / sizeof(PICKUP_TILE_ID[0]); + for (int i = 0; i < count; i++) { + if (PICKUP_TILE_ID[i] == tileId) + return (PickupType)i; + } + return PICKUP_COIN; +} + +static Rectangle GetTileBounds(TmxTileset *tileset, uint32_t tileId, float worldX, + float worldY) { + for (uint32_t i = 0; i < tileset->tilesLength; i++) { + if (tileset->tiles[i].id == tileId) { + TmxObjectGroup *og = &tileset->tiles[i].objectGroup; + if (og->objectsLength > 0) { + TmxObject *obj = &og->objects[0]; + return (Rectangle){ + worldX + (float)obj->x, + worldY + (float)obj->y, + (float)obj->width, + (float)obj->height, + }; + } + } + } + return (Rectangle){worldX, worldY, (float)tileset->tileWidth, + (float)tileset->tileHeight}; +} + +static void LoadPickups(TmxMap *tmxMap, TmxLayer *layer, Entities *entities) { + TmxObjectGroup *group = &layer->exact.objectGroup; + for (uint32_t i = 0; i < group->objectsLength; i++) { + TmxObject *object = &group->objects[i]; + if (object->type != OBJECT_TYPE_TILE || + entities->pickupsCount >= MAX_ENTITIES) + continue; + + TmxTileset *tileset = FindTileSetByGid(tmxMap, object->gid); + assert(tileset); + + uint32_t tileId = object->gid - tileset->firstGid; + float x = (float)object->x; + float y = (float)object->y - (float)tileset->tileHeight; + + Pickup *p = &entities->pickups[entities->pickupsCount++]; + p->type = GetPickupTypeByTileId((int)tileId); + p->position = (Vector2){x, y}; + p->bounds = GetTileBounds(tileset, tileId, x, y); + p->value = 1; + p->active = true; + p->gid = (uint32_t)object->gid; + } +} + +static void LoadKeys(TmxMap *tmxMap, TmxLayer *layer, Entities *entities) { + TmxObjectGroup *group = &layer->exact.objectGroup; + for (uint32_t i = 0; i < group->objectsLength; i++) { + TmxObject *object = &group->objects[i]; + if (object->type != OBJECT_TYPE_TILE || entities->keysCount >= MAX_ENTITIES) + continue; + + TmxTileset *tileset = FindTileSetByGid(tmxMap, object->gid); + assert(tileset); + + uint32_t tileId = object->gid - tileset->firstGid; + float x = (float)object->x; + float y = (float)object->y - (float)tileset->tileHeight; + + Key *k = &entities->keys[entities->keysCount++]; + k->position = (Vector2){x, y}; + k->bounds = GetTileBounds(tileset, tileId, x, y); + k->uniqueId = (int)object->id; + k->active = true; + k->gid = (uint32_t)object->gid; + } +} + +Map *LoadMap(const char *filename, Entities *entities) { + Map *map = (Map *)malloc(sizeof(Map)); + if (!map) + return NULL; + + map->map = LoadTMX(filename); + if (!map->map) { + free(map); + return NULL; + } + + map->wallLayer = FindLayerByName(map->map, "Walls"); + map->groundLayer = FindLayerByName(map->map, "Ground"); + map->decorLayer = FindLayerByName(map->map, "Decor"); + + if (entities) { + TmxLayer *pickupsLayer = FindLayerByName(map->map, "Pickups"); + if (pickupsLayer) + LoadPickups(map->map, pickupsLayer, entities); + + TmxLayer *itemsLayer = FindLayerByName(map->map, "Items"); + if (itemsLayer) + LoadKeys(map->map, itemsLayer, entities); + } + + return map; +} + +bool isCollision(Map *map, Rectangle bounds) { + if (!map || !map->wallLayer || !map->decorLayer) + return false; + return CheckCollisionTMXTileLayersRec(map->map, map->wallLayer, 1, bounds, + NULL) || + CheckCollisionTMXTileLayersRec(map->map, map->decorLayer, 1, bounds, + NULL); +} + +void DrawMap(Map *map) { + if (!map) + return; + AnimateTMX(map->map); + + TmxLayer layers[3]; + uint32_t count = 0; + if (map->groundLayer) layers[count++] = *map->groundLayer; + if (map->wallLayer) layers[count++] = *map->wallLayer; + if (map->decorLayer) layers[count++] = *map->decorLayer; + DrawTMXLayers(map->map, NULL, NULL, layers, count, 0, 0, WHITE); +} + +static void DrawTileByGid(TmxMap *tmxMap, uint32_t gid, float x, float y) { + if (gid == 0 || gid >= tmxMap->gidsToTilesLength) + return; + TmxTile tile = tmxMap->gidsToTiles[gid]; + if (tile.gid == 0) + return; + if (tile.hasAnimation && tile.frameIndex < tile.animation.framesLength) { + uint32_t frameGid = tile.animation.frames[tile.frameIndex].gid; + if (frameGid < tmxMap->gidsToTilesLength) + tile = tmxMap->gidsToTiles[frameGid]; + } + DrawTextureRec(tile.texture, tile.sourceRect, (Vector2){x, y}, WHITE); +} + +void DrawPickups(Entities *entities, Map *map) { + if (!entities || !map) + return; + for (int i = 0; i < entities->pickupsCount; i++) { + Pickup *p = &entities->pickups[i]; + if (!p->active) + continue; + DrawTileByGid(map->map, p->gid, p->position.x, p->position.y); + } +} + +void DrawKeys(Entities *entities, Map *map) { + if (!entities || !map) + return; + for (int i = 0; i < entities->keysCount; i++) { + Key *k = &entities->keys[i]; + if (!k->active) + continue; + DrawTileByGid(map->map, k->gid, k->position.x, k->position.y); + } +} + +void UnloadMap(Map *map) { + if (!map) + return; + UnloadTMX(map->map); + free(map); +} diff --git a/src/map_manager.c b/src/map_manager.c deleted file mode 100644 index bcb9063..0000000 --- a/src/map_manager.c +++ /dev/null @@ -1,115 +0,0 @@ -#include "map_manager.h" -#include "entity.h" -#include "raytmx.h" -#include "globals.h" - -// Forward declaration of internal raytmx function -void DrawTMXLayerTile(const TmxMap* map, Rectangle viewport, uint32_t rawGid, Rectangle destRect, Color tint); - -MapManager LoadGameMap(const char *fileName) { - MapManager mgr = {0}; - mgr.map = LoadTMX(fileName); - - // Cache layers for faster access - if (mgr.map) { - for (uint32_t i = 0; i < mgr.map->layersLength; i++) { - if (strcmp(mgr.map->layers[i].name, "Walls") == 0 && - mgr.map->layers[i].type == LAYER_TYPE_TILE_LAYER) { - mgr.wallLayer = &mgr.map->layers[i]; - } - if (strcmp(mgr.map->layers[i].name, "Solid") == 0 && - mgr.map->layers[i].type == LAYER_TYPE_TILE_LAYER) { - mgr.solidLayer = &mgr.map->layers[i]; - } - if (strcmp(mgr.map->layers[i].name, "Collectible") == 0 || - strcmp(mgr.map->layers[i].name, "Pickups") == 0) - mgr.pickupLayer = &mgr.map->layers[i]; - } - } - return mgr; -} - -void UnloadGameMap(MapManager *mgr) { - if (mgr->map) { - UnloadTMX(mgr->map); - mgr->map = NULL; - } -} - -bool IsWallCollision(MapManager *mgr, Rectangle rect) { - // Check main walls - if (mgr->wallLayer && CheckCollisionTMXTileLayersRec(mgr->map, mgr->wallLayer, 1, rect, NULL)) - return true; - - // Check additional solid layer (props, etc) - if (mgr->solidLayer && CheckCollisionTMXTileLayersRec(mgr->map, mgr->solidLayer, 1, rect, NULL)) - return true; - - return false; -} - -// Internal helper for debug rendering -static void DrawDebugTileCollision(TmxMap *map, TmxLayer *layer, Color color) { - if (!layer || layer->type != LAYER_TYPE_TILE_LAYER) return; - - TmxTileLayer *tileLayer = &layer->exact.tileLayer; - for (uint32_t y = 0; y < tileLayer->height; y++) { - for (uint32_t x = 0; x < tileLayer->width; x++) { - uint32_t gid = tileLayer->tiles[y * tileLayer->width + x]; - if (gid != 0 && gid < map->gidsToTilesLength) { - TmxTile tileData = map->gidsToTiles[gid]; - for (uint32_t objIdx = 0; objIdx < tileData.objectGroup.objectsLength; objIdx++) { - TmxObject obj = tileData.objectGroup.objects[objIdx]; - DrawRectangleLinesEx((Rectangle){ - (float)x * TILE_SIZE + (float)obj.x, - (float)y * TILE_SIZE + (float)obj.y, - (float)obj.width, - (float)obj.height - }, 0.5f, color); - } - } - } - } -} - -void DrawMap(MapManager *mgr) { - AnimateTMX(mgr->map); - DrawTMX(mgr->map, NULL, NULL, 0, 0, WHITE); - - if (debugMode) { - DrawDebugTileCollision(mgr->map, mgr->wallLayer, RED); - DrawDebugTileCollision(mgr->map, mgr->solidLayer, RED); - } -} - -void DrawEntities(EntityManager *mgr, TmxMap *map) { - Rectangle drawViewport = {-1000, -1000, 5000, 5000}; - - for (int i = 0; i < mgr->collectiblesCount; i++) { - if (mgr->collectibles[i].active) { - // Pickups are drawn by the map renderer (DrawTMX). - // We only draw the debug hitbox here. - if (debugMode) { - DrawRectangleLinesEx(mgr->collectibles[i].bounds, 0.5f, GREEN); - } - } - } - - for (int i = 0; i < mgr->movablesCount; i++) { - DrawTMXLayerTile(map, drawViewport, mgr->movables[i].gid, - mgr->movables[i].bounds, WHITE); - if (debugMode) { - DrawRectangleLinesEx(mgr->movables[i].bounds, 0.5f, GREEN); - } - } - - for (int i = 0; i < mgr->enemiesCount; i++) { - if (mgr->enemies[i].active) { - DrawTMXLayerTile(map, drawViewport, mgr->enemies[i].gid, - mgr->enemies[i].bounds, WHITE); - if (debugMode) { - DrawRectangleLinesEx(mgr->enemies[i].bounds, 0.5f, RED); - } - } - } -} |
