本文主要是介绍CodeBus投稿落选代码——瓦片地图粗糙版 记录,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
Easyx官网上有个分享代码的网站。
然后心血来潮,想起来之前的瓦片地图编辑器
DevC++ easyx实现视口编辑--像素绘图板与贴图系统-CSDN博客
就去试试投稿。然后收到回复说要改格式,写注释,按帖子要求排版。
然后排版完了,有好心人提示几个地方修改,比如说题目英文中文之间空格隔开。
然后继续改,巧的是改着改着就来消息说代码比较多,建议上传项目文件压缩包。
然后就到 visualstdio 上跑一遍,发现可以。
然后再提交,然后手机响了,审核同志来询问这个软件的“应用”。然后提出来软件的应用性不够。
比如说整个png图像当游戏背景显然是不可能的,像素绘制瓦片就不如到PS上绘制了。
虽然发了一个png当跳一跳游戏背景的截图,然后有人就指出来实际游戏里运行的情况不同,提示说去可以看看官网推荐参考案例——FC红白机坦克大战的代码。
然后就谢谢指点。
总之后续又有几句话,强调了应用性,随即提示说背景是个二维数组里了,坦克到哪个数组,数组序号是1,1是砖头,坦克就不能继续前进。说可以导出二维数组。再然后就没有然后了,理解了整个故事,也翻看了坦克大战的数组地图,打算这个寒假重整一下瓦片地图,导出瓦片地图背后的二维数组。和二维数组对应的数字,数字对应的像素贴图。这样应该就能过审了。也可以产生价值了。
但是旧的代码呢?估计是雪藏了,但是又再网上搜索关键字,发现旧文案被转载了,然后想起来按格式改写的代码,觉得还是先整一篇新的吧,原来的篇目当做历史,记录无中生有的变化。也算是还原一下一个普通程序的发展历程。
完整代码
虽然代码确实和DevC++ easyx实现视口编辑--像素绘图板与贴图系统-CSDN博客一样,
但是一想起来转载到DevC++ easyx实现视口编辑--像素绘图板与贴图系统 - 技术栈 (jishuzhan.net)
没有注释的代码多少确实有点不够意思,或者说现在巧了,有个详细注释版本,就更新一下
记录一下一些原来应被改写的代码的原样。
一键整合版
// 程序:瓦片地图绘图板
// 作者:无脑
// 编译环境:DevC++ easyx4mingw_20220901
// 编写日期:2024-1-2
// main.cpp#include <stdio.h>
#include <graphics.h>// 程序:瓦片地图绘图板
// 作者:无脑
// 编译环境:DevC++ easyx4mingw_20220901
// 编写日期:2024-1-2
// oripic.h
int w = 2600; // 大地图长
int h = 800; // 大地图宽
IMAGE set(w, h); // 大地图struct pixlocal
{short x; // 记录鼠标绘制的坐标,是地图编辑器改线条生长动画时用到。这里只是用于测试鼠标像素short y;
};struct skline
{ // 另一个编辑器按绘制顺序打印线条生长动画,这里是 debug 用int lenth = 0; // 线条长度int setx, sety; // 锚点,线条参考位置,但是这个像素绘图板没有用到这个锚点struct pixlocal a[10000]; // 记录鼠标绘制的坐标,是地图编辑器改线条生长动画时用到。这里只是用于测试鼠标像素
} nf, ndnf;struct drawdesksize
{ // 绿色绘图板的大小设置int x; // 绿色绘图板左上角坐标int y;int a; // 绿色绘图板长宽int h;int sizetile = 8; // 像素大小为 8 正方形大小则是 8*8int smx; // 悬浮窗大小int smy;
} ddm; // 绿色绘图板参数,其设定完成后,用于计算其他配套网格参数IMAGE maptile(ddm.a / ddm.sizetile, ddm.h / ddm.sizetile); // 瓦片、和瓦片大小struct pircle
{ // 拖动悬浮窗IMAGE img2; // 悬浮窗图像IMAGE img3; // 悬浮窗底线盖住的图像,用于恢复原来盖住图像int orilx, orily; // 悬浮窗初始化时的左上角坐标int nowlx, nowly; // 悬浮窗当前位置的左上角坐标int a, h; // 悬浮窗长宽int m1x = 0, m1y = 0; // img3 左上角坐标bool putflag = 0; // 拖动 flag , 用于悬浮窗拖动int drawflag = 0; // 瓦片绘制 flag , 用于实现长按鼠标绘制像素struct skline b; // 线条长度存储,当时用于开发技能动画,但是在这里只是用来测试功能,比如拖动技能图标,实现技能启用关闭,就是这个变量在控制
} save; // 待保存的悬浮窗数据,所以只能有一个struct picsave
{ // 绿色网格插槽,暂存笔刷int lx; // 左上角坐标int ly;int wide; // 宽高int h;int useflag; // 是否被使用struct skline b; // 配套线条暂存
} a[28]; // 暂存上限 28 个瓦片// 初始化绘图窗口
void OriPicDesk(int a, int h)
{initgraph(a, h, EX_SHOWCONSOLE);setbkcolor(WHITE);cleardevice(); // 创制绘图界面,背景色设置,以背景色填充setlinecolor(BLACK);setlinestyle(PS_SOLID, 1); // 不含实线,矩形的面积为 8*8,含实线 9*9rectangle(0, 0, a - 2, h - 1); // 确定工作界面范围setfillcolor(WHITE);
}// 初始化整个软件窗口大小
void OriDrawDeskSize(struct drawdesksize* ddm, int x, int y)
{ddm->x = x;ddm->y = y;ddm->a = 640;ddm->h = 640;ddm->sizetile = 8;ddm->smx = ddm->x - ddm->a / ddm->sizetile;ddm->smy = ddm->y - ddm->h / ddm->sizetile;
}// 初始化整个软件窗口大小
void DrawDesk(struct drawdesksize ddm)
{int i, j;int square = ddm.sizetile;for (i = ddm.x; i <= ddm.x + ddm.a - square; i += square){for (j = ddm.y; j < ddm.y + ddm.h; j += square){fillrectangle(i, j, i + square, j + square);}}rectangle(ddm.smx - 1, ddm.smy - 1, ddm.x, ddm.y);
}// 初始化白色小图
void OriPirCle(struct pircle* save, struct drawdesksize* ddm)
{save->orilx = ddm->smx, save->orily = ddm->smy;save->nowlx = ddm->smx, save->nowly = ddm->smy; // img2 的左上角坐标save->a = ddm->a / ddm->sizetile;save->h = ddm->h / ddm->sizetile;save->m1x = 0, save->m1y = 0; // img3 的左上角坐标save->putflag = 0;save->drawflag = 0;
}// 初始化大地图
void OriSet(IMAGE* set, struct drawdesksize ddm)
{SetWorkingImage(set);setbkcolor(YELLOW); // 背景黄色cleardevice();setlinecolor(BLACK);for (int i = 0; i < w; i += ddm.a / ddm.sizetile){for (int j = 0; j < h; j += ddm.h / ddm.sizetile)rectangle(j + 1, i + 1, j + ddm.a / ddm.sizetile, i + ddm.h / ddm.sizetile); // 网格绘制}line(0, 0, 800, 1400);SetWorkingImage();
}// 程序:瓦片地图绘图板
// 作者:无脑
// 编译环境:DevC++ easyx4mingw_20220901
// 编写日期:2024-1-2
// show.h
extern struct skline nf, ndnf;
extern IMAGE maptile;void DidShow(IMAGE* set, IMAGE maptile, ExMessage m, int show_x, int show_y, int nowlx, int nowly)
{static int flag = 0;static int oldx = -8, oldy = -8;int putx = 0, puty = 0;if (m.message == WM_LBUTTONDOWN){// 左键批量绘制瓦片到大地图SetWorkingImage(set);putx = nowlx + m.x - show_x; // 计算当前在大地图的坐标puty = nowly + m.y - show_y;putx = putx - putx % 80; // 计算所在的网格puty = puty - puty % 80;putimage(putx, puty, &maptile); // 把 maptile 粘贴到大地图中SetWorkingImage();}else{if (putx == oldx && puty == oldy){ // 如果和上次的位置相同,则不贴图,避免了重复贴图}else{SetWorkingImage(set);putx = nowlx + m.x - show_x; // 计算当前在大地图的坐标puty = nowly + m.y - show_y;putx = putx - putx % 80; // 计算所在的网格puty = puty - puty % 80;putimage(putx, puty, &maptile); // 把 maptile 粘贴到大地图中oldx = putx; // 暂存本次绘图左上角坐标oldy = puty;SetWorkingImage();}}
}// 视口函数
void Show(IMAGE* set, ExMessage m, int show_x, int show_y, int show_wideth, int show_height)
{// 视口的图片大小,视口的大小,在窗口的坐标,视口的大小static int nowlx, nowly, pic_wide, pic_heigh;static int m1x, m1y;static bool drawflag, putflag, attachflag;static IMAGE olds(show_wideth, show_height);static IMAGE news(show_wideth, show_height);static int m2x, m2y; // 加速移动设置参数 m2x , m2y , 自动移动设置static int flag = 1; // 视口初始化,要覆盖到窗口上if (flag == 1){pic_wide = show_wideth;pic_heigh = show_height;m1x = 0;m1y = 0;m2x = 0;m2y = 0;drawflag = 0;putflag = 0;attachflag = 0;flag = 0;setlinecolor(BLACK);rectangle(show_x, show_y, show_x + show_wideth, show_y + show_height);SetWorkingImage(set);getimage(&olds, nowlx, nowly, pic_wide, pic_heigh);SetWorkingImage();putimage(show_x, show_y, &olds);}else{if (m.message == WM_LBUTTONDOWN){if (m.ctrl && m.x > show_x && m.x<show_x + show_wideth && m.y>show_y && m.y < show_y + show_height){// ctrl+左键视口,连续移动大地图SetWorkingImage(set); // 获取视口里的图片getimage(&olds, nowlx, nowly, pic_wide, pic_heigh);m1x = m.x; // 长按开始时的坐标m1y = m.y;m2x = m.x;m2y = m.y;SetWorkingImage();putflag = true; // 启动地图移动}else if (m.x > show_x && m.x<show_x + show_wideth && m.y>show_y && m.y < show_y + show_height){// 鼠标左键实现瓦片贴图DidShow(set, maptile, m, show_x, show_y, nowlx, nowly); // 开始把瓦片贴入大地图attachflag = true; // 批量绘制启动}}else if (attachflag == true && m.x > show_x && m.x<show_x + show_wideth && m.y>show_y && m.y < show_y + show_height){// 连续贴图DidShow(set, maptile, m, show_x, show_y, nowlx, nowly);if (m.message == WM_LBUTTONUP){attachflag = false; // 长按结束,笔刷涂贴片停止}SetWorkingImage(set); // 贴片涂完后台的大地图,从大地图拷贝后,立即在桌面更新显示getimage(&olds, nowlx, nowly, pic_wide, pic_heigh);SetWorkingImage();putimage(show_x, show_y, &olds);}else if (putflag == true){// 持续拖动大地图SetWorkingImage(set); // 进行了位移放大nowlx = nowlx - 5 * (m.x - m1x); // 位移同鼠标位移方向相反,长度为五倍关系nowly = nowly - 5 * (m.y - m1y);m1x = m.x; // 不可改动这两行代码位置m1y = m.y;getimage(&olds, nowlx, nowly, pic_wide, pic_heigh);SetWorkingImage();putimage(show_x, show_y, &olds);if (m.message == WM_LBUTTONUP || m.ctrl == 0){putflag = 0; // 长按停止,视口采样停止}}}
}// 程序:瓦片地图绘图板
// 作者:无脑
// 编译环境:DevC++ easyx4mingw_20220901
// 编写日期:2024-1-2
// draw.h
extern IMAGE maptile;// 像素绘图板的小矩形绘制,开发顺序是先有这个 draw.h 代码,然后有 show.h 代码。这两个头文件是继承关系
void Remem(struct ExMessage m, int* lenth, struct drawdesksize ddm)
{int i = *lenth;static int oldx = -ddm.sizetile,oldy = -ddm.sizetile,a = ddm.sizetile,h = ddm.sizetile;if (m.x > oldx && m.x<oldx + a && m.y>oldy && m.y < oldy + h){// 修正可涂色范围,防止溢出。y 不可等于 640+100,x 等于 640+600-1 是边界小方块的最右侧像素// 节约运算,不在相同位置重复绘制}else{int px = 0, py = 0, qx = 0, qy = 0;int mapqx = 0, mapqy = 0;px = m.x - ddm.x; // 修正 600 的偏移,601=600+1;0==1%8,600=600+(601-600)%8py = m.y - ddm.y;qx = px - px % a; // 取整,用于确定黑色像素矩形位置qy = py - py % h;mapqx = qx / a; // 计算对应悬浮窗的像素坐标mapqy = qy / h;px = ddm.x + qx; // 相对与绿色绘图区域左上角的坐标py = ddm.y + qy;setfillcolor(BLACK);fillrectangle(px, py, px + ddm.sizetile, py + ddm.sizetile); // 绘制黑色像素矩形nf.a[i].x = mapqx; // 悬浮窗技能动画数据存储nf.a[i].y = mapqy;i++;*lenth = i;nf.lenth = *lenth;printf("%d %d %d\n", i - 1, nf.a[i - 1].x, nf.a[i - 1].y);putpixel(ddm.smx + nf.a[i - 1].x, ddm.smy + nf.a[i - 1].y, BLACK); // 绘制悬浮窗像素oldx = px;oldy = py;}
}// 绘制函数,悬浮窗绘制与绿色网格绘制像素
void Draw(ExMessage m, int* lenth)
{static int flag = 0;if (m.message == WM_LBUTTONDOWN){Remem(m, lenth, ddm);// printf("draw function is running 222\n"); // 测试flag = 1;}else if (flag == 1){Remem(m, lenth, ddm);if (m.message == WM_LBUTTONUP){flag = 0;}}
}// 绘制像素
void DrawMouseCheck(ExMessage m, int* lenth, struct drawdesksize* ddm)
{if (m.x > ddm->x && m.x<ddm->x + ddm->a && m.y>ddm->y && m.y < ddm->y + ddm->h){Draw(m, lenth);
// printf("333\n");}
}// 程序:瓦片地图绘图板
// 作者:无脑
// 编译环境:DevC++ easyx4mingw_20220901
// 编写日期:2024-1-2
// flowsave.h// 用于保存悬浮窗图案,以及对应线条动画数据
void OriFlowSave(int x, int y, int w, int h)
{setfillcolor(GREEN);int i;int num = 0;for (int j = 0; j < h; j++){for (i = 1; i <= w; i++){a[num].lx = x + 1 + i * 81;a[num].ly = y + 1 + j * 81;a[num].wide = 80;a[num].h = 80;a[num].useflag = 0;fillrectangle(a[num].lx, a[num].ly, a[num].lx + a[num].wide, a[num].ly + a[num].h);num++;}}
}// 选中暂存的瓦片的数据
void ReHave(ExMessage m, int w, int h)
{int i;int num = 0;for (int j = 0; j < w; j++){for (i = 1; i <= h; i++){if (m.x > a[num].lx && m.x<a[num].lx + a[num].wide && m.y>a[num].ly && m.y < a[num].ly + a[num].h){if (a[num].useflag == 1){ndnf = a[num].b; // 读取数据,但是 ndnf 没有用到break;}}num++;}}
}// 选中暂存的瓦片的图案
void PickPen(ExMessage m, int w, int h)
{int i, j;int num = 0;for (j = 0; j < w; j++){for (i = 1; i <= h; i++){if (m.x > a[num].lx && m.x<a[num].lx + a[num].wide && m.y>a[num].ly && m.y < a[num].ly + a[num].h){if (a[num].useflag == 1){getimage(&maptile, a[num].lx, a[num].ly, 80, 80);fillrectangle(20, 80, 100, 160); // 左上角会显示图案,就是选中了putimage(20, 80, &maptile);}}num++;}}
}// 鼠标放置悬浮窗
void FlowSave(ExMessage m, struct pircle* save, int w, int h)
{if (m.message == WM_LBUTTONDOWN){PickPen(m, w, h); // 左键选中画笔}else if (m.message == WM_LBUTTONUP){int i;int num = 0;for (int j = 0; j < w; j++){for (i = 1; i <= h; i++){if (m.x > a[num].lx && m.x<a[num].lx + a[num].wide && m.y>a[num].ly && m.y < a[num].ly + a[num].h){if (a[num].useflag == 0){ // 找到空白的插槽a[num].b = nf;if (save->nowlx != save->orilx && save->nowly != save->orily){putimage(save->nowlx, save->nowly, &save->img3);}else{getimage(&save->img2, save->orilx, save->orily, save->a, save->h);}putimage(a[num].lx, a[num].ly, &save->img2);save->nowlx = save->orilx; // 悬浮窗复位save->nowly = save->orily;save->m1x = 0;save->m1y = 0;
// printf("%d\n", save->m1x); // 测试save->putflag = false; // 悬浮窗拖动停止a[num].useflag = 1;break;}}num++;}}}if (m.message == WM_RBUTTONDOWN){ReHave(m, w, h); // 在瓦片地图这里没有用,但是从这里衍生的其他编辑器用到了}
}// 程序:瓦片地图绘图板
// 作者:无脑
// 编译环境:DevC++ easyx4mingw_20220901
// 编写日期:2024-1-2
// movecheck.h
extern int w2, h2;// 用于检测小地图拖动
void MoveCheck(struct ExMessage m, struct pircle* save)
{if (save->putflag == 0 && m.message == WM_LBUTTONDOWN){if (save->m1x == 0 && save->m1y == 0 && m.x > save->orilx && m.x<save->orilx + save->a && m.y>save->orily && m.y < save->orily + save->h){getimage(&save->img2, save->orilx, save->orily, save->a, save->h); // 获取原图getimage(&save->img3, save->orilx, save->orily, save->a, save->h); // 初始化底图save->m1x = m.x;save->m1y = m.y;save->putflag = true;// printf("movecheck is running 2222\n"); // 测试}else if (m.x > save->nowlx && m.x<save->nowlx + save->a && m.y>save->nowly && m.y < save->nowly + save->h){save->putflag = true;getimage(&save->img2, save->orilx, save->orily, save->a, save->h);save->m1x = m.x;save->m1y = m.y;// printf("movecheck function is running11111\n"); // 测试}}else if (save->putflag == true){BeginBatchDraw();putimage(save->nowlx, save->nowly, &save->img3); // 先恢复原来底图save->nowlx = save->nowlx + m.x - save->m1x; // 鼠标移动的距离变成图片更新的距离save->nowly = save->nowly + m.y - save->m1y;save->m1x = m.x; // 鼠标的坐标被记录下来save->m1y = m.y;getimage(&save->img3, save->nowlx, save->nowly, save->a, save->h); // 再获取新的底图putimage(save->nowlx, save->nowly, &save->img2); // 然后才粘贴新的悬浮窗EndBatchDraw(); // 一次绘图出来,没有屏闪了if (m.message == WM_LBUTTONUP){save->putflag = 0; // 停止移动悬浮窗}}
}// 程序:瓦片地图绘图板
// 作者:无脑
// 编译环境:DevC++ easyx4mingw_20220901
// 编写日期:2024-1-2
// keycheck.h
extern IMAGE set;// 重置绘图版
void Ori(struct drawdesksize ddm)
{int i, j;int square = ddm.sizetile;setfillcolor(WHITE);setlinecolor(GREEN);for (i = ddm.x; i <= ddm.x + ddm.a - square; i += square){for (j = ddm.y; j < ddm.y + ddm.h; j += square){fillrectangle(i, j, i + square, j + square); // 像素网格重置}}for (i = ddm.smx; i < ddm.smx + ddm.a / ddm.sizetile; i++){for (j = ddm.smy; j < ddm.smy + ddm.h / ddm.sizetile; j++){putpixel(i, j, WHITE); // 悬浮窗重置}}
}// 小地图轨迹打印,这个就是所谓的 skline 的作用。另一个编辑器实现了线条导出功能
void Pixnf(int lenth, struct drawdesksize ddm)
{int i = 0;for (i = 0; i < lenth; i++){putpixel(ddm.smx + nf.a[i].x, ddm.smy + nf.a[i].y, WHITE);if (i % 55 == 0)Sleep(1);}for (i = 0; i < lenth; i++){putpixel(ddm.smx + nf.a[i].x, ddm.smy + nf.a[i].y, BLACK);if (i % 55 == 0)Sleep(1);}
}// 按键检测
void KeyCheck(ExMessage m, int* lenth)
{switch (m.vkcode){case VK_F1: // 重置绘图板Ori(ddm);*lenth = 0;break;case VK_F2: // 导出为 gamemap0 的 png 图片saveimage(_T("gamemap.png"), &set);break;case VK_F5: // 播放线条动画static int limf5 = 0;if (limf5 == 0){Pixnf(*lenth, ddm);limf5 = 1;}else{limf5 = 0; // 处理掉的 bug:按 F5 一次,打印两次线条}break;}
}int x2 = 650, y2 = 100; // 深绿色像素板的左上角坐标
int w2 = 3, h2 = 7; // 绿色网格的列数、行数
int showx3 = 101, showy3 = 100; // 黄色网格视口的左上角坐标int main()
{OriPicDesk(1800, 870); // 初始化整个软件窗口大小OriDrawDeskSize(&ddm, 1000, 100); // 初始化整个软件窗口大小OriPirCle(&save, &ddm); // 初始化白色小图OriSet(&set, ddm); // 初始化大地图OriFlowSave(x2, y2, w2, h2); // 初始化暂存瓦片的绿色网格DrawDesk(ddm); // 绘制出像素绘图板ExMessage m;int lenth = 0; // 用于记录绘制长度,在 debug 时看控制台窗口数据while (1){m = getmessage(EX_MOUSE | EX_KEY); // 获取鼠标、按键信息DrawMouseCheck(m, &lenth, &ddm); // 像素绘制检测KeyCheck(m, &lenth); // 按键检测MoveCheck(m, &save); // 拖动检测FlowSave(m, &save, w2, h2); // 暂存检测Show(&set, m, showx3, showy3, 600, 700); // 大地图绘制}closegraph();return 0;
}
分部版本
main.cpp
// 程序:瓦片地图绘图板
// 作者:无脑
// 编译环境:DevC++ easyx4mingw_20220901
// 编写日期:2024-1-2
// main.cpp#include <stdio.h>
#include <graphics.h>#include"oripic.h" // 初始化函数集中在这个头文件里了
#include"show.h" // 视口、粘贴瓦片
#include"draw.h" // 绘制瓦片
#include"flowsave.h" // 瓦片暂存
#include"movecheck.h" // 鼠标点击检测
#include"keycheck.h" // 按键按动检测int x2 = 650, y2 = 100; // 深绿色像素板的左上角坐标
int w2 = 3, h2 = 7; // 绿色网格的列数、行数
int showx3 = 101, showy3 = 100; // 黄色网格视口的左上角坐标int main()
{OriPicDesk(1800, 870); // 初始化整个软件窗口大小OriDrawDeskSize(&ddm, 1000, 100); // 初始化整个软件窗口大小OriPirCle(&save, &ddm); // 初始化白色小图OriSet(&set, ddm); // 初始化大地图OriFlowSave(x2, y2, w2, h2); // 初始化暂存瓦片的绿色网格DrawDesk(ddm); // 绘制出像素绘图板ExMessage m;int lenth = 0; // 用于记录绘制长度,在 debug 时看控制台窗口数据while (1){m = getmessage(EX_MOUSE | EX_KEY); // 获取鼠标、按键信息DrawMouseCheck(m, &lenth, &ddm); // 像素绘制检测KeyCheck(m, &lenth); // 按键检测MoveCheck(m, &save); // 拖动检测FlowSave(m, &save, w2, h2); // 暂存检测Show(&set, m, showx3, showy3, 600, 700); // 大地图绘制}closegraph();return 0;
}
oripic.h
// 程序:瓦片地图绘图板
// 作者:无脑
// 编译环境:DevC++ easyx4mingw_20220901
// 编写日期:2024-1-2
// oripic.h
int w = 2600; // 大地图长
int h = 800; // 大地图宽
IMAGE set(w, h); // 大地图struct pixlocal
{short x; // 记录鼠标绘制的坐标,是地图编辑器改线条生长动画时用到。这里只是用于测试鼠标像素short y;
};struct skline
{ // 另一个编辑器按绘制顺序打印线条生长动画,这里是 debug 用int lenth = 0; // 线条长度int setx, sety; // 锚点,线条参考位置,但是这个像素绘图板没有用到这个锚点struct pixlocal a[10000]; // 记录鼠标绘制的坐标,是地图编辑器改线条生长动画时用到。这里只是用于测试鼠标像素
} nf, ndnf;struct drawdesksize
{ // 绿色绘图板的大小设置int x; // 绿色绘图板左上角坐标int y;int a; // 绿色绘图板长宽int h;int sizetile = 8; // 像素大小为 8 正方形大小则是 8*8int smx; // 悬浮窗大小int smy;
} ddm; // 绿色绘图板参数,其设定完成后,用于计算其他配套网格参数IMAGE maptile(ddm.a / ddm.sizetile, ddm.h / ddm.sizetile); // 瓦片、和瓦片大小struct pircle
{ // 拖动悬浮窗IMAGE img2; // 悬浮窗图像IMAGE img3; // 悬浮窗底线盖住的图像,用于恢复原来盖住图像int orilx, orily; // 悬浮窗初始化时的左上角坐标int nowlx, nowly; // 悬浮窗当前位置的左上角坐标int a, h; // 悬浮窗长宽int m1x = 0, m1y = 0; // img3 左上角坐标bool putflag = 0; // 拖动 flag , 用于悬浮窗拖动int drawflag = 0; // 瓦片绘制 flag , 用于实现长按鼠标绘制像素struct skline b; // 线条长度存储,当时用于开发技能动画,但是在这里只是用来测试功能,比如拖动技能图标,实现技能启用关闭,就是这个变量在控制
} save; // 待保存的悬浮窗数据,所以只能有一个struct picsave
{ // 绿色网格插槽,暂存笔刷int lx; // 左上角坐标int ly;int wide; // 宽高int h;int useflag; // 是否被使用struct skline b; // 配套线条暂存
} a[28]; // 暂存上限 28 个瓦片// 初始化绘图窗口
void OriPicDesk(int a, int h)
{initgraph(a, h, EX_SHOWCONSOLE);setbkcolor(WHITE);cleardevice(); // 创制绘图界面,背景色设置,以背景色填充setlinecolor(BLACK);setlinestyle(PS_SOLID, 1); // 不含实线,矩形的面积为 8*8,含实线 9*9rectangle(0, 0, a - 2, h - 1); // 确定工作界面范围setfillcolor(WHITE);
}// 初始化整个软件窗口大小
void OriDrawDeskSize(struct drawdesksize* ddm, int x, int y)
{ddm->x = x;ddm->y = y;ddm->a = 640;ddm->h = 640;ddm->sizetile = 8;ddm->smx = ddm->x - ddm->a / ddm->sizetile;ddm->smy = ddm->y - ddm->h / ddm->sizetile;
}// 初始化整个软件窗口大小
void DrawDesk(struct drawdesksize ddm)
{int i, j;int square = ddm.sizetile;for (i = ddm.x; i <= ddm.x + ddm.a - square; i += square){for (j = ddm.y; j < ddm.y + ddm.h; j += square){fillrectangle(i, j, i + square, j + square);}}rectangle(ddm.smx - 1, ddm.smy - 1, ddm.x, ddm.y);
}// 初始化白色小图
void OriPirCle(struct pircle* save, struct drawdesksize* ddm)
{save->orilx = ddm->smx, save->orily = ddm->smy;save->nowlx = ddm->smx, save->nowly = ddm->smy; // img2 的左上角坐标save->a = ddm->a / ddm->sizetile;save->h = ddm->h / ddm->sizetile;save->m1x = 0, save->m1y = 0; // img3 的左上角坐标save->putflag = 0;save->drawflag = 0;
}// 初始化大地图
void OriSet(IMAGE* set, struct drawdesksize ddm)
{SetWorkingImage(set);setbkcolor(YELLOW); // 背景黄色cleardevice();setlinecolor(BLACK);for (int i = 0; i < w; i += ddm.a / ddm.sizetile){for (int j = 0; j < h; j += ddm.h / ddm.sizetile)rectangle(j + 1, i + 1, j + ddm.a / ddm.sizetile, i + ddm.h / ddm.sizetile); // 网格绘制}line(0, 0, 800, 1400);SetWorkingImage();
}
show.h
// 程序:瓦片地图绘图板
// 作者:无脑
// 编译环境:DevC++ easyx4mingw_20220901
// 编写日期:2024-1-2
// show.h
extern struct skline nf, ndnf;
extern IMAGE maptile;void DidShow(IMAGE* set, IMAGE maptile, ExMessage m, int show_x, int show_y, int nowlx, int nowly)
{static int flag = 0;static int oldx = -8, oldy = -8;int putx = 0, puty = 0;if (m.message == WM_LBUTTONDOWN){// 左键批量绘制瓦片到大地图SetWorkingImage(set);putx = nowlx + m.x - show_x; // 计算当前在大地图的坐标puty = nowly + m.y - show_y;putx = putx - putx % 80; // 计算所在的网格puty = puty - puty % 80;putimage(putx, puty, &maptile); // 把 maptile 粘贴到大地图中SetWorkingImage();}else{if (putx == oldx && puty == oldy){ // 如果和上次的位置相同,则不贴图,避免了重复贴图}else{SetWorkingImage(set);putx = nowlx + m.x - show_x; // 计算当前在大地图的坐标puty = nowly + m.y - show_y;putx = putx - putx % 80; // 计算所在的网格puty = puty - puty % 80;putimage(putx, puty, &maptile); // 把 maptile 粘贴到大地图中oldx = putx; // 暂存本次绘图左上角坐标oldy = puty;SetWorkingImage();}}
}// 视口函数
void Show(IMAGE* set, ExMessage m, int show_x, int show_y, int show_wideth, int show_height)
{// 视口的图片大小,视口的大小,在窗口的坐标,视口的大小static int nowlx, nowly, pic_wide, pic_heigh;static int m1x, m1y;static bool drawflag, putflag, attachflag;static IMAGE olds(show_wideth, show_height);static IMAGE news(show_wideth, show_height);static int m2x, m2y; // 加速移动设置参数 m2x , m2y , 自动移动设置static int flag = 1; // 视口初始化,要覆盖到窗口上if (flag == 1){pic_wide = show_wideth;pic_heigh = show_height;m1x = 0;m1y = 0;m2x = 0;m2y = 0;drawflag = 0;putflag = 0;attachflag = 0;flag = 0;setlinecolor(BLACK);rectangle(show_x, show_y, show_x + show_wideth, show_y + show_height);SetWorkingImage(set);getimage(&olds, nowlx, nowly, pic_wide, pic_heigh);SetWorkingImage();putimage(show_x, show_y, &olds);}else{if (m.message == WM_LBUTTONDOWN){if (m.ctrl && m.x > show_x && m.x<show_x + show_wideth && m.y>show_y && m.y < show_y + show_height){// ctrl+左键视口,连续移动大地图SetWorkingImage(set); // 获取视口里的图片getimage(&olds, nowlx, nowly, pic_wide, pic_heigh);m1x = m.x; // 长按开始时的坐标m1y = m.y;m2x = m.x;m2y = m.y;SetWorkingImage();putflag = true; // 启动地图移动}else if (m.x > show_x && m.x<show_x + show_wideth && m.y>show_y && m.y < show_y + show_height){// 鼠标左键实现瓦片贴图DidShow(set, maptile, m, show_x, show_y, nowlx, nowly); // 开始把瓦片贴入大地图attachflag = true; // 批量绘制启动}}else if (attachflag == true && m.x > show_x && m.x<show_x + show_wideth && m.y>show_y && m.y < show_y + show_height){// 连续贴图DidShow(set, maptile, m, show_x, show_y, nowlx, nowly);if (m.message == WM_LBUTTONUP){attachflag = false; // 长按结束,笔刷涂贴片停止}SetWorkingImage(set); // 贴片涂完后台的大地图,从大地图拷贝后,立即在桌面更新显示getimage(&olds, nowlx, nowly, pic_wide, pic_heigh);SetWorkingImage();putimage(show_x, show_y, &olds);}else if (putflag == true){// 持续拖动大地图SetWorkingImage(set); // 进行了位移放大nowlx = nowlx - 5 * (m.x - m1x); // 位移同鼠标位移方向相反,长度为五倍关系nowly = nowly - 5 * (m.y - m1y);m1x = m.x; // 不可改动这两行代码位置m1y = m.y;getimage(&olds, nowlx, nowly, pic_wide, pic_heigh);SetWorkingImage();putimage(show_x, show_y, &olds);if (m.message == WM_LBUTTONUP || m.ctrl == 0){putflag = 0; // 长按停止,视口采样停止}}}
}
draw.h
// 程序:瓦片地图绘图板
// 作者:无脑
// 编译环境:DevC++ easyx4mingw_20220901
// 编写日期:2024-1-2
// draw.h
extern IMAGE maptile;// 像素绘图板的小矩形绘制,开发顺序是先有这个 draw.h 代码,然后有 show.h 代码。这两个头文件是继承关系
void Remem(struct ExMessage m, int* lenth, struct drawdesksize ddm)
{int i = *lenth;static int oldx = -ddm.sizetile,oldy = -ddm.sizetile,a = ddm.sizetile,h = ddm.sizetile;if (m.x > oldx && m.x<oldx + a && m.y>oldy && m.y < oldy + h){// 修正可涂色范围,防止溢出。y 不可等于 640+100,x 等于 640+600-1 是边界小方块的最右侧像素// 节约运算,不在相同位置重复绘制}else{int px = 0, py = 0, qx = 0, qy = 0;int mapqx = 0, mapqy = 0;px = m.x - ddm.x; // 修正 600 的偏移,601=600+1;0==1%8,600=600+(601-600)%8py = m.y - ddm.y;qx = px - px % a; // 取整,用于确定黑色像素矩形位置qy = py - py % h;mapqx = qx / a; // 计算对应悬浮窗的像素坐标mapqy = qy / h;px = ddm.x + qx; // 相对与绿色绘图区域左上角的坐标py = ddm.y + qy;setfillcolor(BLACK);fillrectangle(px, py, px + ddm.sizetile, py + ddm.sizetile); // 绘制黑色像素矩形nf.a[i].x = mapqx; // 悬浮窗技能动画数据存储nf.a[i].y = mapqy;i++;*lenth = i;nf.lenth = *lenth;printf("%d %d %d\n", i - 1, nf.a[i - 1].x, nf.a[i - 1].y);putpixel(ddm.smx + nf.a[i - 1].x, ddm.smy + nf.a[i - 1].y, BLACK); // 绘制悬浮窗像素oldx = px;oldy = py;}
}// 绘制函数,悬浮窗绘制与绿色网格绘制像素
void Draw(ExMessage m, int* lenth)
{static int flag = 0;if (m.message == WM_LBUTTONDOWN){Remem(m, lenth, ddm);// printf("draw function is running 222\n"); // 测试flag = 1;}else if (flag == 1){Remem(m, lenth, ddm);if (m.message == WM_LBUTTONUP){flag = 0;}}
}// 绘制像素
void DrawMouseCheck(ExMessage m, int* lenth, struct drawdesksize* ddm)
{if (m.x > ddm->x && m.x<ddm->x + ddm->a && m.y>ddm->y && m.y < ddm->y + ddm->h){Draw(m, lenth);
// printf("333\n");}
}
flowsave.h
// 程序:瓦片地图绘图板
// 作者:无脑
// 编译环境:DevC++ easyx4mingw_20220901
// 编写日期:2024-1-2
// flowsave.h// 用于保存悬浮窗图案,以及对应线条动画数据
void OriFlowSave(int x, int y, int w, int h)
{setfillcolor(GREEN);int i;int num = 0;for (int j = 0; j < h; j++){for (i = 1; i <= w; i++){a[num].lx = x + 1 + i * 81;a[num].ly = y + 1 + j * 81;a[num].wide = 80;a[num].h = 80;a[num].useflag = 0;fillrectangle(a[num].lx, a[num].ly, a[num].lx + a[num].wide, a[num].ly + a[num].h);num++;}}
}// 选中暂存的瓦片的数据
void ReHave(ExMessage m, int w, int h)
{int i;int num = 0;for (int j = 0; j < w; j++){for (i = 1; i <= h; i++){if (m.x > a[num].lx && m.x<a[num].lx + a[num].wide && m.y>a[num].ly && m.y < a[num].ly + a[num].h){if (a[num].useflag == 1){ndnf = a[num].b; // 读取数据,但是 ndnf 没有用到break;}}num++;}}
}// 选中暂存的瓦片的图案
void PickPen(ExMessage m, int w, int h)
{int i, j;int num = 0;for (j = 0; j < w; j++){for (i = 1; i <= h; i++){if (m.x > a[num].lx && m.x<a[num].lx + a[num].wide && m.y>a[num].ly && m.y < a[num].ly + a[num].h){if (a[num].useflag == 1){getimage(&maptile, a[num].lx, a[num].ly, 80, 80);fillrectangle(20, 80, 100, 160); // 左上角会显示图案,就是选中了putimage(20, 80, &maptile);}}num++;}}
}// 鼠标放置悬浮窗
void FlowSave(ExMessage m, struct pircle* save, int w, int h)
{if (m.message == WM_LBUTTONDOWN){PickPen(m, w, h); // 左键选中画笔}else if (m.message == WM_LBUTTONUP){int i;int num = 0;for (int j = 0; j < w; j++){for (i = 1; i <= h; i++){if (m.x > a[num].lx && m.x<a[num].lx + a[num].wide && m.y>a[num].ly && m.y < a[num].ly + a[num].h){if (a[num].useflag == 0){ // 找到空白的插槽a[num].b = nf;if (save->nowlx != save->orilx && save->nowly != save->orily){putimage(save->nowlx, save->nowly, &save->img3);}else{getimage(&save->img2, save->orilx, save->orily, save->a, save->h);}putimage(a[num].lx, a[num].ly, &save->img2);save->nowlx = save->orilx; // 悬浮窗复位save->nowly = save->orily;save->m1x = 0;save->m1y = 0;
// printf("%d\n", save->m1x); // 测试save->putflag = false; // 悬浮窗拖动停止a[num].useflag = 1;break;}}num++;}}}if (m.message == WM_RBUTTONDOWN){ReHave(m, w, h); // 在瓦片地图这里没有用,但是从这里衍生的其他编辑器用到了}
}
movecheck.h
// 程序:瓦片地图绘图板
// 作者:无脑
// 编译环境:DevC++ easyx4mingw_20220901
// 编写日期:2024-1-2
// movecheck.h
extern int w2, h2;// 用于检测小地图拖动
void MoveCheck(struct ExMessage m, struct pircle* save)
{if (save->putflag == 0 && m.message == WM_LBUTTONDOWN){if (save->m1x == 0 && save->m1y == 0 && m.x > save->orilx && m.x<save->orilx + save->a && m.y>save->orily && m.y < save->orily + save->h){getimage(&save->img2, save->orilx, save->orily, save->a, save->h); // 获取原图getimage(&save->img3, save->orilx, save->orily, save->a, save->h); // 初始化底图save->m1x = m.x;save->m1y = m.y;save->putflag = true;// printf("movecheck is running 2222\n"); // 测试}else if (m.x > save->nowlx && m.x<save->nowlx + save->a && m.y>save->nowly && m.y < save->nowly + save->h){save->putflag = true;getimage(&save->img2, save->orilx, save->orily, save->a, save->h);save->m1x = m.x;save->m1y = m.y;// printf("movecheck function is running11111\n"); // 测试}}else if (save->putflag == true){BeginBatchDraw();putimage(save->nowlx, save->nowly, &save->img3); // 先恢复原来底图save->nowlx = save->nowlx + m.x - save->m1x; // 鼠标移动的距离变成图片更新的距离save->nowly = save->nowly + m.y - save->m1y;save->m1x = m.x; // 鼠标的坐标被记录下来save->m1y = m.y;getimage(&save->img3, save->nowlx, save->nowly, save->a, save->h); // 再获取新的底图putimage(save->nowlx, save->nowly, &save->img2); // 然后才粘贴新的悬浮窗EndBatchDraw(); // 一次绘图出来,没有屏闪了if (m.message == WM_LBUTTONUP){save->putflag = 0; // 停止移动悬浮窗}}
}
keycheck.h
// 程序:瓦片地图绘图板
// 作者:无脑
// 编译环境:DevC++ easyx4mingw_20220901
// 编写日期:2024-1-2
// keycheck.h
extern IMAGE set;// 重置绘图版
void Ori(struct drawdesksize ddm)
{int i, j;int square = ddm.sizetile;setfillcolor(WHITE);setlinecolor(GREEN);for (i = ddm.x; i <= ddm.x + ddm.a - square; i += square){for (j = ddm.y; j < ddm.y + ddm.h; j += square){fillrectangle(i, j, i + square, j + square); // 像素网格重置}}for (i = ddm.smx; i < ddm.smx + ddm.a / ddm.sizetile; i++){for (j = ddm.smy; j < ddm.smy + ddm.h / ddm.sizetile; j++){putpixel(i, j, WHITE); // 悬浮窗重置}}
}// 小地图轨迹打印,这个就是所谓的 skline 的作用。另一个编辑器实现了线条导出功能
void Pixnf(int lenth, struct drawdesksize ddm)
{int i = 0;for (i = 0; i < lenth; i++){putpixel(ddm.smx + nf.a[i].x, ddm.smy + nf.a[i].y, WHITE);if (i % 55 == 0)Sleep(1);}for (i = 0; i < lenth; i++){putpixel(ddm.smx + nf.a[i].x, ddm.smy + nf.a[i].y, BLACK);if (i % 55 == 0)Sleep(1);}
}// 按键检测
void KeyCheck(ExMessage m, int* lenth)
{switch (m.vkcode){case VK_F1: // 重置绘图板Ori(ddm);*lenth = 0;break;case VK_F2: // 导出为 gamemap0 的 png 图片saveimage(_T("gamemap.png"), &set);break;case VK_F5: // 播放线条动画static int limf5 = 0;if (limf5 == 0){Pixnf(*lenth, ddm);limf5 = 1;}else{limf5 = 0; // 处理掉的 bug:按 F5 一次,打印两次线条}break;}
}
这篇关于CodeBus投稿落选代码——瓦片地图粗糙版 记录的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!