多种类型图片模块读取-CSDN博客

Editing While Playing 使用 Easyx 开发的 RPG 地图编辑器 tilemap eaitor-CSDN博客

整合实现平面贴图纹理自定义

操作同上

导入步骤:

先运行程序,然后关闭,同目录下有四个文件夹,

把自己准备的 30*30 像素的 png 格式的图片粘贴进去。无需改名。

或者随便粘贴图片,不过加载的时候只会加载左上角 30*30 的部分

然后启动程序,发现会有自定义贴图加载出来。

绘制完

F1 还可以导出为 DLC,DLC 内自动复制粘贴并按程序内的顺序重命名了

// 程序:2D RPG 地图编辑器// 作者:民用级脑的研发记录// 邮箱:1309602336@qq.com// 编译环境:Devc++/VC 2010/Visual Studio 2022,EasyX_20220901/Easyx_2023 大暑版// 编写日期:2024-2-22//#undef UNICODE#undef _UNICODE#pragma warning(disable : 4996)// VS2022 对某些函数警告,但是为了方便移植,就无视这些警告 这样 Devc++ VC2010 VS2022 都能跑#include #include #include #include #include // 从默认文件夹中读取自定义图片void loadfile(IMAGE*** bentablev2);// 加载自定义图片void loadfile_scanf(char* dirname, char* next, char* kind, IMAGE** pentablev2);// 保存自定义文件void savepersonalfile(char* DLC, IMAGE*** pentablev2);// 保存自定义瓦片贴图void savelocal(char* DLC, char* dirname, char* next, char* kind, char* sign, IMAGE** files);// 实时渐变色小动画inline void animation(int chararcterflag, int bkgameleft, int bkgametop, int bkmeshgameleft, int bkmeshgametop, int bkmeshdeskleft, int bkmeshdesktop);// 边界检查,move 是平移大小,单位:像素,若使得寄存区在九宫格中心,move 的大小就是寄存区的边长,相应的 size 的大小是 move 的两倍。这样无论长宽都是 3 倍。size 是大小区域,代表不会触发缓冲区更新的范围,单位:像素inline void checkboundary(int* bkgameleft, int* bkgametop, int gamelimitright, int gamelimitbuttom, int* bkmeshleft, int* bkmeshtop, int* meshlimit, int* meshlimitbutton, int move, int size);// 保存游戏地图贴图数据void savegamemap(int** map, int gamemapi, int gamemapj, IMAGE* pentable, IMAGE*** pentablev2, int pixnum, int imagenum);// 导入游戏地图贴图数据void loadgamemap(int** map, int* gamemapi, int* gamemapj, IMAGE* pentable, int* pixnum, int* imagenum);// 使用关键字 inline 声明为内联函数,减少贴图函数频繁调用的开销导致的卡顿。// 缓冲区纹理映射函数:bkmesh 映射目标,map 映射总网格,pentable:纹理集,bkmeshmapi,bkmeshmapj:映射起始点,tilenum:横,纵映射的数量,pixnum:一个映射块的边长,单位:像素。inline void freshmesh(IMAGE* bkmesh, int** map, IMAGE* pentable, IMAGE*** pentablev2, int bkmeshmapi, int bkmeshmapj, int tilenum, int pixnum){int kind = 0;// 存储代号第一位:类型int number = 0;// 存储代号第二位:序列号int pennumber = -1;// 暂存每一次循环的映射代号IMAGE* pen = NULL;// 所找到的纹理int left = 0;// 这是每次循环所找到的纹理对应映射地址int top = 0;SetWorkingImage(bkmesh);// 设置绘图目标为游戏背景采样区,刷新采样区,刷新寄存区cleardevice();for (int i = bkmeshmapi; i < bkmeshmapi + tilenum; i++){left = 0;for (int j = bkmeshmapj; j < bkmeshmapj + tilenum; j++){pennumber = map[i][j];// 读取游戏大地图数组序号if (pennumber == -1){rectangle(left, top, left + pixnum, top + pixnum);}else{kind = pennumber / 10 - 6;// 剥离第一位number = pennumber % 10;// 剥离最后一位if (pennumber < 10)pen = &pentable[pennumber];elsepen = pentablev2[kind][number];// 根据序号查找对应贴图putimage(left, top, pen);// 把贴图画到采样区}left += pixnum;// 往右移动,准备下一次绘制位置,此处贴图就会覆盖白色边框。为保证坐标变换和网格对应,算上网格宽度,也在贴图矩形内}top += pixnum;// 往下移动,准备下一次绘制位置,此处就会覆盖白色边框,方便定位}SetWorkingImage();}// 在纹理映射函数中产生的图片中截图,但此为演示参数作用,此处并未优化。inline void freshbk(IMAGE* bk, IMAGE* bkmesh, int gamex, int gamey, int bkmeshmapi, int bkmeshmapj, int tilenum, int pixnum){SetWorkingImage(bkmesh);getimage(bk, gamex - bkmeshmapj * pixnum, gamey - bkmeshmapi * pixnum, tilenum * pixnum, tilenum * pixnum);SetWorkingImage();}// 在屏幕显示截图inline void showbk(IMAGE* bk, int bkdeskx, int bkdesky){SetWorkingImage();putimage(bkdeskx, bkdesky, bk);}// 在屏幕上显示缓冲区inline void showbkmesh(IMAGE* bkmesh, int bkmeshdeskx, int bkmeshdesky){SetWorkingImage();putimage(bkmeshdeskx, bkmeshdesky, bkmesh);}// 初始化游戏地图int** initmap(int wide, int high){int** map = new int* [high];// 二维数组动态初始化,先给二级指针挂上一个长度为 10 的指针数组for (int i = 0; i < high; i++){map[i] = new int[wide];// 然后数组里的每个指针都挂上一个长度为 10 的 int 类型数组}for (int i = 0; i < high; i++){for (int j = 0; j < wide; j++){map[i][j] = -1;// 初始化游戏大地图 map 的参数,参数 1 默认黑色}}return map;}int main(){initgraph(1640, 980, 1);setbkcolor(GREEN);cleardevice();IMAGE* bk;// 背景图片寄存区bk = new IMAGE(270, 270);IMAGE* bkmesh;// 背景图片采样区bkmesh = new IMAGE(270 * 3, 270 * 3);int** map;// 游戏大地图数组,记录着整个游戏背景的贴图信息,而在运行过程中,选取部分区域的数字,对照序号与贴图,实现游戏背景绘制。其余没有选中的区域就是压缩的空间。int pixnum;// 一个正方形瓦片的边长。单位:像素int bkgameleft;// 背景图片寄存区左上角坐标,是在游戏里的像素坐标。(0,0)可以理解为游戏大地图的左上角顶点。int bkgametop;int bkmeshgameleft;// 背景图片采样区左上角坐标,是在游戏里的像素坐标。int bkmeshgametop;int bkmeshmapi;// 背景图片采样区左上角所对应的 map 数组序号。从 map[0][0]开始,按照 map[i][j],其中 bkmeshmapi=bkmeshtop/pixnumint bkmeshmapj;int bkdeskleft;// 规定在屏幕上显示游戏背景寄存区,此处记录其左上角在屏幕上的像素坐标int bkdesktop;int bkmeshdeskleft;// 规定在屏幕上显示游戏背景采样区,此处记录其左上角在屏幕上的像素坐标int bkmeshdesktop;pixnum = 30;// 进行初始化,规定各位置具体数字bkdeskleft = 200;// 游戏背景左上角将会在屏幕的(200,200) 处bkdesktop = 200;bkgameleft = 0;// 由于 bkgame 控制 mesh 坐标移动,(0,0)则游戏背景完全在当前采样区移动bkgametop = 0;bkmeshdeskleft = 700;// 游戏背景缓冲区左上角将会在屏幕的(700,0)处bkmeshdesktop = 0;bkmeshgameleft = 0;bkmeshgametop = 0;int meshlimitright;// 使用变量暂存边界,不用每次来回计算边界int meshlimitbuttom;meshlimitright = 270;// 和寄存区一样大,把寄存区限制在一个九宫格中心,如果越出九宫格,九宫格整体平移meshlimitbuttom = 270;bkmeshmapi = bkmeshgametop / pixnum;bkmeshmapj = bkmeshgameleft / pixnum;int mapi;// 读取 DLC 文件,需要变量记录循环次数,单位 瓦片贴图个数int mapj;int safemapi;// 一个安全的贴图范围,避免阅读超过 10000 导致的越界闪退问题。int safemapj;int gamelimitright;// 用于减少比较时的计算,存储边界范围int gamelimitbuttom;safemapi = 70;// 注意导出的是左上角开始的 100*100 部分,如果绘制出界,保存不了,需要改这一行和下一行的数字safemapj = 70;gamelimitright = pixnum * safemapi;gamelimitbuttom = pixnum * safemapj;mapi = 300;mapj = 300;map = initmap(mapi, mapj);// 初始化一个有 10000*10000 个贴图的地图int pentableleft;// 忘了初始化调色盘了,这里设置调色盘左上角在屏幕的坐标int pentabletop;int imagenum;// 调色板数量上限,用于文件读取控制循环次数IMAGE* pentable;// 调色板其实就是贴图数组pentableleft = 0;// 调色盘左上角将会在屏幕的(0,0)处pentabletop = 0;imagenum = 10;int pentablev2left;// 自定义贴图插槽int pentablev2top;int pentablev2high;// 自定义贴图的容量大小int pentablev2wide;pentablev2left = 10;pentablev2top = 300;pentablev2high = 10;pentablev2wide = 4;IMAGE*** pentablev2;pentablev2 = new IMAGE * *[pentablev2wide];for (int i = 0; i < pentablev2wide; i++)pentablev2[i] = new IMAGE * [pentablev2high];for (int i = 0; i < pentablev2wide; i++)for (int j = 0; j < pentablev2high; j++)pentablev2[i][j] = NULL;loadfile(pentablev2);// 加载本地图片pentable = new IMAGE[imagenum];for (int i = 0; i < imagenum; i++){pentable[i] = IMAGE(30, 30);SetWorkingImage(&pentable[i]);// 给调色板绘制颜色setfillcolor(RGB(i * 20, i * 20, i * 20));// 这里初始化调色盘的颜色fillrectangle(-1, -1, pixnum, pixnum);// 在调色板上绘制颜色(纹理)要从 -1,-1 开始绘制,把边框画到外部,不保留边框。}int left;// 初始化绘制采样区所需的坐标,相对于采样区,(0,0)就是采样区左上角顶点坐标int top;left = 0;top = 0;//往缓冲区刷入贴图SetWorkingImage(bkmesh);// 设置绘图目标为游戏背景采样区,刷新采样区,刷新寄存区setbkcolor(RGB(200, 200, 200));// 设置瓦片边线颜色,图片没有覆盖的背景就是边线cleardevice();for (int i = bkmeshmapi; i < bkmeshmapi + 30; i++){left = 0;for (int j = bkmeshmapj; j < bkmeshmapj + 30; j++){int pennumber = map[i][j];// 读取游戏大地图数组序号if (pennumber == -1){rectangle(left, top, left + pixnum, top + pixnum);}left += pixnum;// 往右移动,准备下一次绘制位置,}top += pixnum;// 往下移动,准备下一次绘制位置}getimage(bk, bkgameleft, bkgametop, 270, 270);// 从刚刚绘制好的采样区取样,刷新游戏背景寄存区。//开始往屏幕上绘图SetWorkingImage();// 设置电脑屏幕为绘制对象for (int j = 0; j < 10; j++){putimage(pentableleft + 10, pentabletop + j * 30, &pentable[j]); // 绘制绘图板}for (int i = 0; i < pentablev2wide; i++)// 绘制自定义贴图,印自定义笔刷for (int j = 0; j  bkdeskleft && m.y > bkdesktop && m.x < bkdeskleft + 300 && m.y  0 && m.y > 10 && m.x < 40 && m.y  10 && m.y > 300 && m.x < 10 + pentablev2wide * 30 && m.y  bkdeskleft && m.y > bkdesktop && m.x < bkdeskleft + 270 && m.y  -10)// 限制范围,减少内存读写flag_x -= speed;characterflag = 1;break;case 0x57:// Wif (flag_y - speed > -10)flag_y -= speed;characterflag = 2;break;case 0x44:// Dif (flag_x + speed < 10)flag_x += speed;characterflag = 3;break;case 0x53:// Smoveflag = 1;if (flag_y + speed < 10)flag_y += speed;characterflag = 4;break;case VK_F1:savegamemap(map, mapi, mapj, pentable, pentablev2, pixnum, imagenum);break;case VK_F2:loadgamemap(map, &mapi, &mapj, pentable, &pixnum, &imagenum);gamelimitright = pixnum * safemapi;gamelimitbuttom = pixnum * safemapj;for (int i = 0; i  bkdeskleft && mousey > bkdesktop && mousex < bkdeskleft + 300 && mousey  safemapi)// map 数组越界检测i = safemapi;else if (i  safemapj)j = safemapj;else if (j  bkdeskleft && mousey > bkdesktop && mousex < bkdeskleft + 300 && mousey  bkdeskleft && mousey > bkdesktop && mousex < bkdeskleft + 300 && mousey < bkdesktop + 300){moveflag = 1;bkgameleft += flag_x;// 更新游戏背景寄存区左上角坐标bkgametop += flag_y;drawx = bkgameleft + (mousex - bkdeskleft);// drawx-bkgameleft=m.x-bkdeskleft横坐标方向移动距离相同drawy = bkgametop + (mousey - bkdesktop);// drawy-bkgametop=m.y-bkdesktop纵坐标方向移动距离相同i = drawy / pixnum;j = drawx / pixnum;if (olddrawi != i || olddrawj != j){drawsmallflag = 1;map[i][j] = pentake;// 注意 map[y][x],而不是 map[x][y],因为判断第几行,是通过 y 来控制上下移动的,判断第几列,是通过 x 左右移动的。olddrawi = i;olddrawj = j;}else{drawsmallflag = 0;// 检测到是上一次绘制的瓦片,则不再刷新贴图与缓冲区。}}else if (drawflag == 0 && flag_x != 0 || flag_y != 0){moveflag = 1;bkgameleft += flag_x;bkgametop += flag_y;}else{// 既不绘制也不移动也不拖拽}// 根据计算出的坐标数据进行绘制,分多种情况分别绘制,减少函数重复调用与无效调用if (drawsmallflag == 1 && moveflag == 0){freshmesh(bkmesh, map, pentable, pentablev2, bkmeshmapi, bkmeshmapj, 27, 30);// 刷新,重新映射,其实就是开头初始化的代码,这里是给了一个封装示例,但未进行性能优化freshbk(bk, bkmesh, bkgameleft, bkgametop, bkmeshmapi, bkmeshmapj, 9, 30);showbk(bk, bkdeskleft, bkdesktop);showbkmesh(bkmesh, bkmeshdeskleft, bkmeshdesktop);}else if (moveflag == 1 && drawsmallflag == 1){checkboundary(&bkgameleft, &bkgametop, gamelimitright, gamelimitbuttom, &bkmeshgameleft, &bkmeshgametop, &meshlimitright, &meshlimitbuttom, 270, 540);bkmeshmapi = bkmeshgametop / pixnum;bkmeshmapj = bkmeshgameleft / pixnum;freshmesh(bkmesh, map, pentable, pentablev2, bkmeshmapi, bkmeshmapj, 27, 30);freshbk(bk, bkmesh, bkgameleft, bkgametop, bkmeshmapi, bkmeshmapj, 9, 30);showbkmesh(bkmesh, bkmeshdeskleft, bkmeshdesktop);showbk(bk, bkdeskleft, bkdesktop);}else if (moveflag == 1 || draftflag)// 分类渲染, drawflag==0 时,再选择性刷新缓冲区{checkboundary(&bkgameleft, &bkgametop, gamelimitright, gamelimitbuttom, &bkmeshgameleft, &bkmeshgametop, &meshlimitright, &meshlimitbuttom, 270, 540);bkmeshmapi = bkmeshgametop / pixnum;bkmeshmapj = bkmeshgameleft / pixnum;if (oldbkmeshgamex != bkmeshgameleft || oldbkmeshgamey != bkmeshgametop)// 判断是否更新采样区{freshmesh(bkmesh, map, pentable, pentablev2, bkmeshmapi, bkmeshmapj, 27, 30);oldbkmeshgamex = bkmeshgameleft;oldbkmeshgamey = bkmeshgametop;showbkmesh(bkmesh, bkmeshdeskleft, bkmeshdesktop);}freshbk(bk, bkmesh, bkgameleft, bkgametop, bkmeshmapi, bkmeshmapj, 9, 30);showbk(bk, bkdeskleft, bkdesktop);}animation(characterflag, bkgameleft, bkgametop, bkmeshgameleft, bkmeshgametop, bkmeshdeskleft, bkmeshdesktop);Sleep(2);// 休眠 20 毫秒,减少 CPU 占用}return 0;}// 保存游戏地图的全部数据void savegamemap(int** map, int gamemapi, int gamemapj, IMAGE* pentable, IMAGE*** pentablev2, int pixnum, int imagenum){FILE* fp;int i = 0;int j = 0;char dirpath[400] = { '\0' };char filepath[400] = { '\0' };for (i = 0; i < 100; i++){sprintf(dirpath, "DLC%d", i);if (access(dirpath, 0) == -1) // 检查 DLC 是否存在,不存在为 -1{break;}}mkdir(dirpath);// 创建文件夹char filename[400] = "gamemap.txt";const char* next = "./";strcat(filepath, dirpath);strcat(filepath, next);strcat(filepath, filename);fp = fopen(filepath, "w+");// 创建 .txt 文件fprintf(fp, "注意此导出的游戏文件为按键 F1 后自动生成 修改汉语字符或者英文字符 或导致该 .txt 文件不可读取\n");fprintf(fp, "warning this saved gamefile is automatically create after F1 pressed change Chinesse character or English character lead to read failed");fprintf(fp, "pixnum %d\n", pixnum);// 正方形瓦片贴图边长信息:单位:像素fprintf(fp, "imagenum %d\n", imagenum);// 瓦片个数char imageindix[400] = { '\0' };for (i = 0; i < imagenum; i++){sprintf(imageindix, "tile_%d.png", i);fprintf(fp, "%s\n", imageindix);}fprintf(fp, "gamemapi %d gamemapj %d\n", gamemapi, gamemapj);for (i = 0; i < gamemapi; i++){fprintf(fp, "%d", map[i][j]);for (j = 0; j < gamemapj; j++){fprintf(fp, " %d", map[i][j]);}fprintf(fp, "\n");}fclose(fp);char imagename[400] = { '\0' };char imagepath[400] = { '\0' };for (i = 0; i < imagenum; i++){sprintf(imagename, "tile_%d.png", i);// 数字转字符串strcpy(imagepath, dirpath);// 函数直接从头开始粘贴,自动清除开头的字符strcat(imagepath, next);strcat(imagepath, imagename);saveimage(imagepath, &pentable[i]);// 批量导出贴图}savepersonalfile(dirpath, pentablev2);// 创建默认文件夹并保存自定义贴图}// 读取 DLC 继续开发void loadgamemap(int** map, int* gamemapi, int* gamemapj, IMAGE* pentable, int* pixnum, int* imagenum){FILE* fp;int i = 0;int j = 0;char dirpath[400] = { '\0' };char filepath[400] = { '\0' };for (i = 0; i < 100; i++){sprintf(dirpath, "DLC%d", i);if (access(dirpath, 0) == 0) // 检查 DLC 是否存在,存在为 0{break;}}if (i == 100)// 100 次查找失败,则返回,不再读取return;char filename[400] = "gamemap.txt";const char* next = "./";strcat(filepath, dirpath);strcat(filepath, next);strcat(filepath, filename);fp = fopen(filepath, "r");// 读取 .txt 文件fscanf(fp, "注意此导出的游戏文件为按键 F1 后自动生成 修改汉语字符或者英文字符 或导致该 .txt 文件不可读取\n");fscanf(fp, "warning this saved gamefile is automatically create after F1 pressed change Chinesse character or English character lead to read failed");fscanf(fp, "pixnum %d\n", pixnum);// 正方形瓦片贴图边长信息:单位:像素fscanf(fp, "imagenum %d\n", imagenum);// 瓦片个数char imageindix[400] = { '\0' };char imagename[400] = { '\0' };char imagepath[400] = { '\0' };for (i = 0; i < *imagenum; i++){fscanf(fp, "%s\n", imageindix);strcpy(imagepath, dirpath);strcat(imagepath, next);strcat(imagepath, imageindix);loadimage(&pentable[i], imagepath, *pixnum, *pixnum, false);// 批量导入贴图}fscanf(fp, "gamemapi %d gamemapj %d\n", gamemapi, gamemapj);for (i = 0; i < *gamemapi; i++){fscanf(fp, "%d", &map[i][j]);for (j = 0; j < *gamemapj; j++){fscanf(fp, " %d", &map[i][j]);}fscanf(fp, "\n");}fclose(fp);}// 检查边界inline void checkboundary(int* bkgameleft, int* bkgametop, int gamelimitright, int gamelimitbuttom, int* bkmeshgameleft, int* bkmeshgametop, int* meshlimitright, int* meshlimitbuttom, int move, int size){if (*bkgameleft  gamelimitright)*bkgameleft = gamelimitright;if (*bkgametop  gamelimitbuttom)*bkgametop = gamelimitbuttom;if (*bkgameleft  *meshlimitright){*meshlimitright += move;*bkmeshgameleft = *meshlimitright - size;}if (*bkgametop  *meshlimitbuttom){*meshlimitbuttom += move;*bkmeshgametop = *meshlimitbuttom - size;}}// 性能:CPU 2% 占有率,峰值 1.20GHz,核显 GPU 10% 使用率inline void animation(int characterflag, int bkgameleft, int bkgametop, int bkmeshgameleft, int bkmeshgametop, int bkmeshdeskleft, int bkmeshdesktop){static int i = 1;static int x = 10;static int y = 10;if (i % 3 == 0){x = bkmeshdeskleft + bkgameleft - bkmeshgameleft;y = bkmeshdesktop + bkgametop - bkmeshgametop;i %= 125;// i 的上限 * 放大倍数 不超过 255switch (characterflag)// 选取颜色{case 1:setfillcolor(RGB(i * 2, i * 2, 0));break;case 2:setfillcolor(RGB(i * 2, 0, i * 2));break;case 3:setfillcolor(RGB(i * 2, 0, 0));break;case 4:setfillcolor(RGB(0, i * 2, 0));break;case 5:// 如果没有按键,则使用默认颜色setfillcolor(RGB(0, 0, i * 2));break;}fillrectangle(x, y, x + 30, y + 30);}i++;}// 从默认文件夹中读取自定义图片void loadfile(IMAGE*** pentablev2){char brick[100] = "aa_birck_6_family";char ground[100] = "ab_ground_7_family";char change[100] = "ac_change_8_family";char trick[100] = "ad_trick_9_family";char next[100] = "./";char png[100] = "*.png";loadfile_scanf(brick, next, png, pentablev2[0]);// 加载用于当砖头类型的图片loadfile_scanf(ground, next, png, pentablev2[1]);loadfile_scanf(change, next, png, pentablev2[2]);loadfile_scanf(trick, next, png, pentablev2[3]);}// 加载自定义图片void loadfile_scanf(char* dirname, char* next, char* kind, IMAGE** pentablev2){// 文件存储信息结构体struct _finddata_t fileinfo;// 保存文件句柄long fHandle;// 文件数记录器char dirpath[100];strcpy(dirpath, dirname);if (access(dirpath, 0) == -1)// 检查文件夹是否存在,不存在为 -1{mkdir(dirpath);return;}else{int i = -1;// 记录文件数量char kindpath[100];strcpy(kindpath, dirpath);strcat(kindpath, next);strcat(kindpath, kind);if ((fHandle = _findfirst(kindpath, &fileinfo)) == -1L) // *是通配符,默认在当前文件夹内查找文件,这里查找 .png 文件{printf("当前目录: %s 下没有所需文件\n", dirname);return;}else{char path[100];do{i++;printf("在%s 下找到文件:%s,文件大小:%d bit\n", dirname, fileinfo.name, fileinfo.size);strcpy(path, dirname);strcat(path, next);strcat(path, fileinfo.name);while (pentablev2[i] != NULL){i++;}pentablev2[i] = new IMAGE(30, 30);loadimage(pentablev2[i], path, 30, 30);// 根据名称读取文件} while (_findnext(fHandle, &fileinfo) == 0);}// 关闭文件_findclose(fHandle);printf("文件数量:%d\n", i + 1);}}// 在目标 DLC 里创建四个文件夹并保存void savepersonalfile(char* DLC, IMAGE*** pentablev2){char brick[100] = "aa_birck_6_family";char ground[100] = "ab_ground_7_family";char change[100] = "ac_change_8_family";char trick[100] = "ad_trick_9_family";char next[100] = "./";char png[100] = ".png";if (access(DLC, 0) == -1)// 检查文件夹是否存在,不存在为 -1{mkdir(DLC);}char sign[10] = {};strcpy(sign, "6");savelocal(DLC, brick, next, png, sign, pentablev2[0]);strcpy(sign, "7");savelocal(DLC, ground, next, png, sign, pentablev2[1]);strcpy(sign, "8");savelocal(DLC, change, next, png, sign, pentablev2[2]);strcpy(sign, "9");savelocal(DLC, trick, next, png, sign, pentablev2[3]);}// 保存自定义文件void savelocal(char* DLC, char* dirname, char* next, char* kind, char* sign, IMAGE** files){char dirpath[100] = "";strcpy(dirpath, DLC);// 字符串拼接出相对路径strcat(dirpath, next);strcat(dirpath, dirname);if (access(dirpath, 0) == -1)// 检查 DLC 内的指定文件夹是否存在,不存在为 -1{mkdir(dirpath);}char filepath[100];char filepa[100];char num[10];strcpy(filepath, dirpath);// 字符串拼接出文件名前缀strcat(filepath, next);strcat(filepath, sign);for (int i = 0; i < 10; i++){sprintf(num, "%d", i);strcpy(filepa, filepath);// 从头粘贴,可以覆盖之前的信息,不受上一次保存的影响strcat(filepa, num);strcat(filepa, kind);if (files[i] != NULL){saveimage(filepa, files[i]);printf("file save %s\n", filepa);}}}