Devc++ Easyx 实现 瓦片地图编辑数据导入游戏

2024-02-23 14:36

本文主要是介绍Devc++ Easyx 实现 瓦片地图编辑数据导入游戏,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

 导出的DLC 直接放入 exe 同文件夹下即可自动读取。


// 程序:DLC 自动读取加载框架示例
// 作者:民用级脑的研发记录
// 邮箱: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++ VS2022 都能跑
#include <graphics.h>
#include <stdio.h>
#include <string.h>
#include <io.h>
#include <direct.h>
// 初始化地图
int** initmap(int wide, int high);
// 从默认文件夹中读取自定义图片
void loadfile(char* DLC, IMAGE*** pentablev2);
// 加载自定义图片
void loadfile_scanf(char* dirname, char* next, char* kind, IMAGE** pentablev2);
// 导入游戏地图贴图数据
void loadgamemap(int** map, int* gamemapi, int* gamemapj, IMAGE* pentable, IMAGE*** pentablev2, int* pixnum, int* imagenum);
// 刷新网格缓冲区
inline void freshmesh(IMAGE* bkmesh, int** map, IMAGE* pentable, IMAGE*** pentablev2, int bkmeshmapi, int bkmeshmapj, int tilenum, int pixnum);
// 在屏幕上显示缓冲区
inline void showbkmesh(IMAGE* bkmesh, int bkmeshdeskx, int bkmeshdesky);
// 在纹理映射函数中产生的图片中截图,但此为演示参数作用,此处并未优化。
inline void freshbk(IMAGE* bk, IMAGE* bkmesh, int gamex, int gamey, int bkmeshmapi, int bkmeshmapj, int tilenum, int pixnum);
// 在屏幕显示截图
inline void showbk(IMAGE* bk, int bkdeskx, int bkdesky);
// 检查边界
inline void checkboundary(int* bkgameleft, int* bkgametop, int gamelimitright, int gamelimitbuttom, int* bkmeshgameleft, int* bkmeshgametop, int* meshlimitright, int* meshlimitbuttom, int move, int size);
// 实时渐变色小动画
inline void animation(int chararcterflag, int bkgameleft, int bkgametop, int bkmeshgameleft, int bkmeshgametop, int bkmeshdeskleft, int bkmeshdesktop);
int main()
{initgraph(1600, 800);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;int imagenum;									// 调色板数量上限,用于文件读取控制循环次数IMAGE* pentable;								// 调色板其实就是贴图数组imagenum = 10;int pentablev2high;								// 自定义贴图的容量大小int pentablev2wide;pentablev2high = 10;pentablev2wide = 4;IMAGE*** pentablev2;map = initmap(mapi, mapj);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 开始绘制,把边框画到外部,不保留边框。}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;loadgamemap(map, &safemapi, &safemapj, pentable, pentablev2, &pixnum, &imagenum);				// 加载游戏freshmesh(bkmesh, map, pentable, pentablev2, bkmeshmapi, bkmeshmapj, 27, pixnum);showbkmesh(bkmesh, bkmeshdeskleft, bkmeshdesktop);freshbk(bk, bkmesh, bkgameleft, bkgametop, bkmeshmapi, bkmeshmapj, 9, pixnum);showbk(bk, bkdeskleft, bkdesktop);int moveflag;															// 是否键盘控制移动int flag_x;																// 记录位移int flag_y;int speed;																// 键盘控制视口的移动速度speed = 5;flag_x = 0;flag_y = 0;moveflag = 0;int oldbkmeshgamex;														// 判断是否需要刷新 bkmesh 网格int oldbkmeshgamey;oldbkmeshgamex = -1;oldbkmeshgamey = -1;int characterflag;														// 用于按键时游戏小人的颜色变化characterflag = 5;ExMessage m;while (1){while (peekmessage(&m, EX_KEY | EX_MOUSE)){switch (m.message){case WM_KEYDOWN:switch (m.vkcode)				// 键盘移动控制{case 0x41:						// Aif (flag_x - speed > -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;}break;case WM_KEYUP:switch (m.vkcode){case 0x41:						// Aflag_x = 0;break;case 0x57:						// Wflag_y = 0;break;case 0x44:						// Dflag_x = 0;break;case 0x53:						// Sflag_y = 0;break;}if (flag_x == 0 && flag_y == 0)characterflag = 5;break;}}if (flag_x != 0 || flag_y != 0){moveflag = 1;bkgameleft += flag_x;bkgametop += flag_y;}else{moveflag = 0;}if (moveflag == 1){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(1);}return 0;
}
// 初始化游戏地图
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;
}
// 读取 DLC 继续开发
void loadgamemap(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) == 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 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);printf("导入 map 部分正常\n");loadfile(dirpath, pentablev2);
}
// 从默认文件夹中读取自定义图片
void loadfile(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";char dirpath[100] = {};strcpy(dirpath, DLC);strcat(dirpath, next);strcat(dirpath, brick);loadfile_scanf(dirpath, next, png, pentablev2[0]);								// 加载用于当砖头类型的图片strcpy(dirpath, DLC);strcat(dirpath, next);strcat(dirpath, ground);loadfile_scanf(dirpath, next, png, pentablev2[1]);strcpy(dirpath, DLC);strcat(dirpath, next);strcat(dirpath, change);loadfile_scanf(dirpath, next, png, pentablev2[2]);strcpy(dirpath, DLC);strcat(dirpath, next);strcat(dirpath, trick);loadfile_scanf(dirpath, 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{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);}
}
// 使用关键字 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);								// 设置绘图目标为游戏背景采样区,刷新采样区,刷新寄存区setbkcolor(RGB(200, 200, 200));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);
}
// 检查边界
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 < 0)												// 网格越界检测并调整*bkgameleft = 0;else if (*bkgameleft > gamelimitright)*bkgameleft = gamelimitright;if (*bkgametop < 0)*bkgametop = 0;else if (*bkgametop > gamelimitbuttom)*bkgametop = gamelimitbuttom;if (*bkgameleft < *bkmeshgameleft)									// 更新游戏采样区坐标,一些简单换算,由于频繁调用函数在这里产生了明显的卡顿影响,所以这里就不再封装成函数{*bkmeshgameleft -= move;*meshlimitright = *bkmeshgameleft + size;}else if (*bkgameleft > *meshlimitright){*meshlimitright += move;*bkmeshgameleft = *meshlimitright - size;}if (*bkgametop < *bkmeshgametop){*bkmeshgametop -= move;*meshlimitbuttom = *bkmeshgametop + size;}else if (*bkgametop > *meshlimitbuttom){*meshlimitbuttom += move;*bkmeshgametop = *meshlimitbuttom - size;}
}
// 实时渐变小动画
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++;
}

这篇关于Devc++ Easyx 实现 瓦片地图编辑数据导入游戏的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/738966

相关文章

大模型研发全揭秘:客服工单数据标注的完整攻略

在人工智能(AI)领域,数据标注是模型训练过程中至关重要的一步。无论你是新手还是有经验的从业者,掌握数据标注的技术细节和常见问题的解决方案都能为你的AI项目增添不少价值。在电信运营商的客服系统中,工单数据是客户问题和解决方案的重要记录。通过对这些工单数据进行有效标注,不仅能够帮助提升客服自动化系统的智能化水平,还能优化客户服务流程,提高客户满意度。本文将详细介绍如何在电信运营商客服工单的背景下进行

基于MySQL Binlog的Elasticsearch数据同步实践

一、为什么要做 随着马蜂窝的逐渐发展,我们的业务数据越来越多,单纯使用 MySQL 已经不能满足我们的数据查询需求,例如对于商品、订单等数据的多维度检索。 使用 Elasticsearch 存储业务数据可以很好的解决我们业务中的搜索需求。而数据进行异构存储后,随之而来的就是数据同步的问题。 二、现有方法及问题 对于数据同步,我们目前的解决方案是建立数据中间表。把需要检索的业务数据,统一放到一张M

关于数据埋点,你需要了解这些基本知识

产品汪每天都在和数据打交道,你知道数据来自哪里吗? 移动app端内的用户行为数据大多来自埋点,了解一些埋点知识,能和数据分析师、技术侃大山,参与到前期的数据采集,更重要是让最终的埋点数据能为我所用,否则可怜巴巴等上几个月是常有的事。   埋点类型 根据埋点方式,可以区分为: 手动埋点半自动埋点全自动埋点 秉承“任何事物都有两面性”的道理:自动程度高的,能解决通用统计,便于统一化管理,但个性化定

python: 多模块(.py)中全局变量的导入

文章目录 global关键字可变类型和不可变类型数据的内存地址单模块(单个py文件)的全局变量示例总结 多模块(多个py文件)的全局变量from x import x导入全局变量示例 import x导入全局变量示例 总结 global关键字 global 的作用范围是模块(.py)级别: 当你在一个模块(文件)中使用 global 声明变量时,这个变量只在该模块的全局命名空

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

异构存储(冷热数据分离)

异构存储主要解决不同的数据,存储在不同类型的硬盘中,达到最佳性能的问题。 异构存储Shell操作 (1)查看当前有哪些存储策略可以用 [lytfly@hadoop102 hadoop-3.1.4]$ hdfs storagepolicies -listPolicies (2)为指定路径(数据存储目录)设置指定的存储策略 hdfs storagepolicies -setStoragePo

Hadoop集群数据均衡之磁盘间数据均衡

生产环境,由于硬盘空间不足,往往需要增加一块硬盘。刚加载的硬盘没有数据时,可以执行磁盘数据均衡命令。(Hadoop3.x新特性) plan后面带的节点的名字必须是已经存在的,并且是需要均衡的节点。 如果节点不存在,会报如下错误: 如果节点只有一个硬盘的话,不会创建均衡计划: (1)生成均衡计划 hdfs diskbalancer -plan hadoop102 (2)执行均衡计划 hd

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

【C++ Primer Plus习题】13.4

大家好,这里是国中之林! ❥前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。有兴趣的可以点点进去看看← 问题: 解答: main.cpp #include <iostream>#include "port.h"int main() {Port p1;Port p2("Abc", "Bcc", 30);std::cout <<

C++包装器

包装器 在 C++ 中,“包装器”通常指的是一种设计模式或编程技巧,用于封装其他代码或对象,使其更易于使用、管理或扩展。包装器的概念在编程中非常普遍,可以用于函数、类、库等多个方面。下面是几个常见的 “包装器” 类型: 1. 函数包装器 函数包装器用于封装一个或多个函数,使其接口更统一或更便于调用。例如,std::function 是一个通用的函数包装器,它可以存储任意可调用对象(函数、函数