翻出来之前写的代码,
EasyxDevC++开发地图编辑和游戏编辑代码工程文件附注释_哔哩哔哩_bilibili
每次把代码备份下来,等着有一天能够复用代码,产生新的价值。
结果最近这几天才来回顾记录emm
“这是怎么搓出来的?”从10行代码到400行代码的小工程,无中生有的各版本备份——EasyxDevC++开发地图编辑和游戏编辑代码开发过程代码附注释_哔哩哔哩_bilibili
虽然视频简介里把资源代码网盘链接传了,鄙人的CDSN主页也一块上传了相同的资源。 但是没有讲解,素材硬看也是消耗比较大的,价值再次产生和无中生有价值,这两个讲解方式应该不同。一个是面向穷举,一个是马后炮解释和背景思路介绍。
使用方式如视频“这是怎么搓出来的?”从10行代码到400行代码的小工程,无中生有的各版本备份——EasyxDevC++开发地图编辑和游戏编辑代码开发过程代码附注释_哔哩哔哩_bilibili
视频简介里的各种链接都已经提出相应问题的解决方案。
这次来实现一个悬浮窗,这是在开发绘图板的两周共30小时,解决生成的瓦片图片要拖动指定区域的问题。这就是自热而然的背景。
操作:
长按鼠标左键,点亮黄色的像素点。
按住Ctrl+鼠标左键,长按点击黑色图片就能拖动图片了。
效果如图
原理:放置原像,扫描保存,粘贴新像。
上代码,看注释,具体说明
完整代码,新建项目,复制粘贴直接跑。代码出处是图中序号9.的文件(9.拖动而且能画画)
#include<stdio.h>
#include<conio.h>
#include<graphics.h>
//void draw(struct Exmessage m){
//
//}
void move(struct ExMessage m) {
static IMAGE img2;
// getimage(&img2,100,100,200,200);
// 检测
static IMAGE img3;
static int x=100,y=100;
static int px=0,py=0;
static int flag=0;
if(flag==1) {
BeginBatchDraw();
putimage(x,y,&img3);
// 在原位置恢复底层
getimage(&img3,m.x+px,m.y+py,200,200);
// 获取原位置和将要覆盖区域的底色 px+m.x=100+m.x2-m.x1;=100+kx,相对位移同鼠标
// getimage(m.x,m.y,&img3);
putimage(m.x+px,m.y+py,&img2);
// 覆盖
x=m.x+px;
y=m.y+py;
// 保存这次位置,成为下次的原位置,找到痕迹
EndBatchDraw();
// 一次绘图出来,没有屏闪了
} else if(flag==2)
putpixel(m.x,m.y,RGB(255,155,4));
// 批量绘制,不会闪烁了
// Sleep(1);
switch(m.message) {
case WM_LBUTTONDOWN:
if(m.x>x&&m.x<x+200&&m.y>y&&m.y<y+200&&m.ctrl) {
flag=1;
// 启动批复制粘贴
getimage(&img2,x,y,200,200);
// putimage(200, 200, &img1);
// 按动了就出现白块
px=x-m.x;
py=y-m.y;
// 记录鼠标和图片左上角的差值
} else {
flag=2;
}
break;
case WM_LBUTTONUP:
flag=0;
break;
}
}
int main() {
initgraph(640,640);
setbkcolor(WHITE);
cleardevice();
setfillcolor(BLACK);
setlinecolor(BLACK);
// 这是初始图片左上角位置,以后都是新图片左上角的位置
// 模的增量位移保存
fillrectangle(100,100,300,300);
// 参考按钮
while(1) {
ExMessage m;
m=getmessage(EX_MOUSE|EX_KEY);
move(m);
}
closegraph();
return 0;
}
这是第一代运行的版本,代码方面的别扭就是未来开发,移植函数的时候不好移植,因为画点的函数putpixel()也在这个拖动函数里。于是分离
分离之后的新版本
完整代码,对应序号10.bug分析......文件。主函数里用两个if和标志位实现原函数的功能分离。
#include<stdio.h>
#include<conio.h>
#include<graphics.h>
void draw(struct ExMessage m,int *flag1,int *qx,int *qy) {
int x=*qx,y=*qy;
int flag=*flag1;
if(flag==2)
putpixel(m.x,m.y,RGB(255,155,4));
switch(m.message) {
case WM_LBUTTONDOWN:
if(m.x>x&&m.x<x+200&&m.y>y&&m.y<y+200&&m.ctrl) {
} else {
flag=2;
}
// flag=2;
// bug和移动函数问题
break;
case WM_LBUTTONUP:
flag=0;
break;
}
*flag1=flag;
}
void check(struct ExMessage m,int *flag1,int *qx,int*qy) {
static IMAGE img2;
// getimage(&img2,100,100,200,200);
// 检测
static IMAGE img3;
static int x=*qx,y=*qy;
static int px=0,py=0;
static int flag=*flag1;
if(flag==1) {
BeginBatchDraw();
putimage(x,y,&img3);
// 在原位置恢复底层
getimage(&img3,m.x+px,m.y+py,200,200);
// 获取原位置和将要覆盖区域的底色 px+m.x=100+m.x2-m.x1;=100+kx,相对位移同鼠标
// getimage(m.x,m.y,&img3);
putimage(m.x+px,m.y+py,&img2);
// 覆盖
x=m.x+px;
y=m.y+py;
// 保存这次位置,成为下次的原位置,找到痕迹
EndBatchDraw();
// 一次绘图出来,没有屏闪了
}
switch(m.message) {
case WM_LBUTTONDOWN:
if(m.x>x&&m.x<x+200&&m.y>y&&m.y<y+200&&m.ctrl) {
flag=1;
// 启动批复制粘贴
getimage(&img2,x,y,200,200);
// putimage(200, 200, &img1);
// 按动了就出现白块
px=x-m.x;
py=y-m.y;
// 记录鼠标和图片左上角的差值
}
break;
case WM_LBUTTONUP:
flag=0;
break;
}
*flag1=flag;
*qx=x;
*qy=y;
}
//
//
//void move(struct ExMessage m) {
//
// static IMAGE img2;
getimage(&img2,100,100,200,200);
检测
// static IMAGE img3;
// static int x=100,y=100;
// static int px=0,py=0;
// static int flag=0;
// if(flag==1) {
// BeginBatchDraw();
// putimage(x,y,&img3);
在原位置恢复底层
// getimage(&img3,m.x+px,m.y+py,200,200);
获取原位置和将要覆盖区域的底色 px+m.x=100+m.x2-m.x1;=100+kx,相对位移同鼠标
getimage(m.x,m.y,&img3);
// putimage(m.x+px,m.y+py,&img2);
覆盖
// x=m.x+px;
// y=m.y+py;
// // 保存这次位置,成为下次的原位置,找到痕迹
// EndBatchDraw();
一次绘图出来,没有屏闪了
// } else if(flag==2)
// putpixel(m.x,m.y,RGB(255,155,4));
批量绘制,不会闪烁了
Sleep(1);
//
// switch(m.message) {
//
// case WM_LBUTTONDOWN:
//
// if(m.x>x&&m.x<x+200&&m.y>y&&m.y<y+200&&m.ctrl) {
// flag=1;
启动批复制粘贴
// getimage(&img2,x,y,200,200);
putimage(200, 200, &img1);
按动了就出现白块
// px=x-m.x;
// py=y-m.y;
记录鼠标和图片左上角的差值
// } else {
// flag=2;
//
// }
// break;
// case WM_LBUTTONUP:
// flag=0;
// break;
// }
//}
int main() {
initgraph(640,640);
setbkcolor(WHITE);
cleardevice();
setfillcolor(BLACK);
setlinecolor(BLACK);
// 这是初始图片左上角位置,以后都是新图片左上角的位置
// 模的增量位移保存
fillrectangle(100,100,300,300);
// 参考按钮
// int qx=100;
// int qy=100;
// int flag=0;
while(1) {
ExMessage m;
m=getmessage(EX_MOUSE|EX_KEY);
static int qx=100;
static int qy=100;
static int flag=0;
if(flag==0||flag==2)
draw(m,&flag,&qx,&qy);
if(flag==0||flag==1)
check(m,&flag,&qx,&qy);
// move(m);
}
closegraph();
return 0;
}
后来发现还有个bug,就是原来位置的贴图还在,这样拖动,原来的图片没有受到影响,相当于是复制粘贴了,所以还要想办法把原图清除掉。
后来想当然就想着在第一步移动之前覆盖图片,然后画白色矩形,但是想用原来的函数试试,相当于提前拖动一步。结果代码插入位置错误,甚至拖动也不能拖动,原因是间接使得控制变量共用,导致变量第一步死锁,后续不能修改变量。变量变成常数,失去了变化分类作用,就不能实现由不拖动到拖动的转换。
又
试了试几次,不得不人脑一行一行读check代码,发现一开始的旧图img3是空的。第一步img2读取黑色,第二步img3粘贴空的,第三步img3读取黑色作为下次粘贴,恢复原貌,第四步img2粘贴,完成一次拖动循环。
原来穷举清楚代码步骤就能自然而然地发现问题,黑色旧图没有消失,就是第三步img3读取的是黑色,旧地方应该放上白色,就是这四个阶段里插入一个只执行一次覆盖的代码。然后实际上是img2读取完黑色,图片就存起来了,原来地方的图片就可以不用了,就在img2执行完加上一块画矩形的代码,然后再增加参数,限制只使用一次,以后都不用了。
其实这说明实现拖动功能的函数控制变量的不安全性,函数结束,时,控制变量不一定复位。复位功能和其他参数绑定,导致其他参数没有作用时自己运行导致死锁。想办法增加一个检测if语句,如果有类似这种情况,就进行复位。
这就是矛盾中进步,无中生有bug,无中生有的复位。
后续可能新开发方向:多个悬浮图片。
当然后续发现拖动多个图片,由于函数内部暂存变量,导致多个图片共用同一个函数,变量一对多,导致记录对不上图片。想办法一个图片有自己独有的变量,就是一堆小弟。而这个群体的概念就是结构体,而这些参数可以再次包装,一个函数传入一个结构体,这个结构体包含被拖动图片的全部信息,这样就能实现多个图片拖动。图片的数据归结进各自的结构体。
这里没有封装结构体,因为封装了,面目全非,真正投入使用的成品代码可以详见EasyxDevC++开发地图编辑和游戏编辑代码工程文件附注释_哔哩哔哩_bilibili
本节最终完整代码:不带结构体封装的,原地图片被拖走的代码
效果图:
#include<stdio.h>
#include<conio.h>
#include<graphics.h>
void draw(struct ExMessage m,int *flag1,int *qx,int *qy) {
int x=*qx,y=*qy;
int flag=*flag1;
if(flag==2)
putpixel(m.x,m.y,RGB(255,155,4));
switch(m.message) {
case WM_LBUTTONDOWN:
if(m.x>x&&m.x<x+200&&m.y>y&&m.y<y+200&&m.ctrl) {
} else {
flag=2;
}
// flag=2;
// bug和移动函数问题
break;
case WM_LBUTTONUP:
flag=0;
break;
}
*flag1=flag;
}
void check(struct ExMessage m,int *flag1,int *qx,int*qy) {
static IMAGE img2;
// getimage(&img2,100,100,200,200);
// 检测
static IMAGE img3;
// static int one=1;
// if(one==1) {
// setfillcolor(WHITE);
// fillrectangle(100-1,100-1,300,300);
// one==0;
// }
static int x=*qx,y=*qy;
static int px=0,py=0;
static int flag=*flag1;
if(flag==1) {
BeginBatchDraw();
putimage(x,y,&img3);
// 在原位置恢复底层
getimage(&img3,m.x+px,m.y+py,200,200);
// 获取原位置和将要覆盖区域的底色 px+m.x=100+m.x2-m.x1;=100+kx,相对位移同鼠标
// getimage(m.x,m.y,&img3);
putimage(m.x+px,m.y+py,&img2);
// 覆盖
x=m.x+px;
y=m.y+py;
// 保存这次位置,成为下次的原位置,找到痕迹
EndBatchDraw();
// 一次绘图出来,没有屏闪了
}
switch(m.message) {
case WM_LBUTTONDOWN:
if(m.x>x&&m.x<x+200&&m.y>y&&m.y<y+200&&m.ctrl) {
flag=1;
// 启动批复制粘贴
getimage(&img2,x,y,200,200);
// putimage(200, 200, &img1);
// 按动了就出现白块
// 静态变量只做一次,此后永不执行
static int one=1;
if(one==1) {
setfillcolor(WHITE);
fillrectangle(100-1,100-1,300,300);
one==0;
}
// 这里把之前的图片覆盖,当然由于矩形框的颜色没有设置成白色,于是留出来黑色的矩形框没有覆盖
px=x-m.x;
py=y-m.y;
// 记录鼠标和图片左上角的差值
}
break;
case WM_LBUTTONUP:
flag=0;
break;
}
*flag1=flag;
*qx=x;
*qy=y;
}
//
//
//void move(struct ExMessage m) {
//
// static IMAGE img2;
getimage(&img2,100,100,200,200);
检测
// static IMAGE img3;
// static int x=100,y=100;
// static int px=0,py=0;
// static int flag=0;
// if(flag==1) {
// BeginBatchDraw();
// putimage(x,y,&img3);
在原位置恢复底层
// getimage(&img3,m.x+px,m.y+py,200,200);
获取原位置和将要覆盖区域的底色 px+m.x=100+m.x2-m.x1;=100+kx,相对位移同鼠标
getimage(m.x,m.y,&img3);
// putimage(m.x+px,m.y+py,&img2);
覆盖
// x=m.x+px;
// y=m.y+py;
// // 保存这次位置,成为下次的原位置,找到痕迹
// EndBatchDraw();
一次绘图出来,没有屏闪了
// } else if(flag==2)
// putpixel(m.x,m.y,RGB(255,155,4));
批量绘制,不会闪烁了
Sleep(1);
//
// switch(m.message) {
//
// case WM_LBUTTONDOWN:
//
// if(m.x>x&&m.x<x+200&&m.y>y&&m.y<y+200&&m.ctrl) {
// flag=1;
启动批复制粘贴
// getimage(&img2,x,y,200,200);
putimage(200, 200, &img1);
按动了就出现白块
// px=x-m.x;
// py=y-m.y;
记录鼠标和图片左上角的差值
// } else {
// flag=2;
//
// }
// break;
// case WM_LBUTTONUP:
// flag=0;
// break;
// }
//}
int main() {
initgraph(640,640);
setbkcolor(WHITE);
cleardevice();
setfillcolor(BLACK);
setlinecolor(BLACK);
// 这是初始图片左上角位置,以后都是新图片左上角的位置
// 模的增量位移保存
fillrectangle(100,100,300,300);
// 参考按钮
// int qx=100;
// int qy=100;
// int flag=0;
while(1) {
ExMessage m;
m=getmessage(EX_MOUSE|EX_KEY);
static int qx=100;
static int qy=100;
static int flag=0;
if(flag==0||flag==2)
draw(m,&flag,&qx,&qy);
if(flag==0||flag==1)
check(m,&flag,&qx,&qy);
// move(m);
}
closegraph();
return 0;
}
附带:用.h头文件封装后的完整代码,复制粘贴引用才能跑
.h完整代码如下:
封装结构体:
orilx,orily分别是初始位置左上角位置坐标
a,h分别是图片长度,高度
m1x,m1y分别是上一次粘贴图片的位置左上角坐标
drawflag就是之前的控制从不拖动转换为拖动的转换变量
img2是
struct pircle {
IMAGE img2;
IMAGE img3;
int orilx,orily;
int nowlx,nowly;
int a,h;
// 原有图片的左上角坐标
int m1x=0,m1y=0;
int putflag=0;
int drawflag=0;
struct skline b;
} save;
结构体参数下的拖动函数样子,函数顺序有所调整:
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("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("11111\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;
}
// 一次绘图出来,没有屏闪了
}
putimage(save->nowlx,save->nowly,&save->img2);
}