如何用C语言结合raylib加载并渲染Tiled导出的JSON格式2D瓦片地图
用C+raylib加载并渲染Tiled JSON瓦片地图
前置准备
- 安装raylib库
- 引入cJSON库(轻量C语言JSON解析库,直接把
cJSON.c和cJSON.h加到项目目录即可) - Tiled导出的JSON地图(导出时选择"JSON"格式,瓦片集使用单张图片)
步骤1:加载JSON文件
先把JSON文件读取到内存,再传给cJSON解析:
#include <stdio.h> #include <stdlib.h> #include "raylib.h" #include "cJSON.h" // 读取文件到内存的辅助函数 char* LoadFileToString(const char* filePath) { FILE* file = fopen(filePath, "rb"); if (!file) return NULL; // 获取文件大小 fseek(file, 0, SEEK_END); long fileSize = ftell(file); fseek(file, 0, SEEK_SET); // 分配内存(额外加1字节存字符串终止符) char* buffer = (char*)malloc(fileSize + 1); if (!buffer) { fclose(file); return NULL; } // 读取文件内容 fread(buffer, 1, fileSize, file); buffer[fileSize] = '\0'; fclose(file); return buffer; }
调用函数加载并解析地图文件:
// 加载JSON文件到内存 char* mapJsonStr = LoadFileToString("assets/map.json"); if (!mapJsonStr) { TraceLog(LOG_ERROR, "Failed to load map JSON file"); return 1; } // 解析JSON字符串 cJSON* mapJson = cJSON_Parse(mapJsonStr); if (!mapJson) { TraceLog(LOG_ERROR, "Failed to parse JSON: %s", cJSON_GetErrorPtr()); free(mapJsonStr); return 1; }
步骤2:解析提取瓦片地图关键信息
从JSON结构中提取地图尺寸、瓦片尺寸、瓦片集路径、图层数据等核心内容:
// 提取地图基础参数 int mapWidth = cJSON_GetObjectItem(mapJson, "width")->valueint; int mapHeight = cJSON_GetObjectItem(mapJson, "height")->valueint; int tileWidth = cJSON_GetObjectItem(mapJson, "tilewidth")->valueint; int tileHeight = cJSON_GetObjectItem(mapJson, "tileheight")->valueint; // 提取瓦片集信息(假设地图只有一个瓦片集) cJSON* tilesets = cJSON_GetObjectItem(mapJson, "tilesets"); cJSON* firstTileset = cJSON_GetArrayItem(tilesets, 0); const char* tilesetPath = cJSON_GetObjectItem(firstTileset, "image")->valuestring; int firstGid = cJSON_GetObjectItem(firstTileset, "firstgid")->valueint; // 提取图层数据(假设地图只有一个可见图层) cJSON* layers = cJSON_GetObjectItem(mapJson, "layers"); cJSON* firstLayer = cJSON_GetArrayItem(layers, 0); cJSON* layerData = cJSON_GetObjectItem(firstLayer, "data");
注意:Tiled的
firstgid是瓦片集第一个瓦片的ID,图层中的瓦片ID需要减去这个值,才能对应到瓦片集里的实际索引。
步骤3:用raylib渲染瓦片地图
加载瓦片集纹理,遍历图层数据逐个绘制瓦片:
int main() { // 初始化raylib窗口 InitWindow(mapWidth * tileWidth, mapHeight * tileHeight, "Tiled Map Demo"); SetTargetFPS(60); // 加载瓦片集纹理 Texture2D tileset = LoadTexture(tilesetPath); if (!tileset.id) { TraceLog(LOG_ERROR, "Failed to load tileset image"); // 提前清理资源 cJSON_Delete(mapJson); free(mapJsonStr); return 1; } // 计算瓦片集每行的瓦片数量 int tilesetCols = tileset.width / tileWidth; while (!WindowShouldClose()) { BeginDrawing(); ClearBackground(RAYWHITE); // 遍历地图的每个瓦片位置 for (int y = 0; y < mapHeight; y++) { for (int x = 0; x < mapWidth; x++) { // 获取当前位置的瓦片ID(数组索引为 y*mapWidth + x) int tileId = cJSON_GetArrayItem(layerData, y*mapWidth + x)->valueint; // 跳过空瓦片(Tiled中空瓦片ID为0) if (tileId == 0) continue; // 计算瓦片在瓦片集中的索引 int tileIndex = tileId - firstGid; // 计算瓦片在瓦片集中的坐标 int tilesetX = (tileIndex % tilesetCols) * tileWidth; int tilesetY = (tileIndex / tilesetCols) * tileHeight; // 绘制瓦片到屏幕对应位置 DrawTextureRec(tileset, (Rectangle){(float)tilesetX, (float)tilesetY, (float)tileWidth, (float)tileHeight}, (Vector2){(float)(x*tileWidth), (float)(y*tileHeight)}, WHITE); } } EndDrawing(); } // 清理所有资源 UnloadTexture(tileset); cJSON_Delete(mapJson); free(mapJsonStr); CloseWindow(); return 0; }
关键注意事项
- 资源清理:必须释放JSON解析内存、文件缓冲区和raylib纹理,避免内存泄漏。
- 多图层/多瓦片集扩展:如果地图有多个图层或瓦片集,只需循环遍历
layers和tilesets数组,逻辑与单图层/单瓦片集一致。 - 空瓦片处理:Tiled中空瓦片ID为0,绘制时必须跳过,否则会错误渲染瓦片集的第一个瓦片。
内容的提问来源于stack exchange,提问作者Proyash Ck
相关产品推荐
相关产品推荐

