网站源码哪个好,专业团队图片张伟原图,oa企业办公系统,广告设计公司服务承诺1.在 drawflag控制检测上#xff0c;加入 drawsmallflag 进行 选择性再调控。
2.mousex mousey 更新来源变为 MOUSEMOVE LBUTTONDOWN RBUTTONDOWN 三个情况。
3. 记录旧瓦片的绘制#xff0c;减少一次长按绘制时#xff0c;同一瓦片被绘制次数。
使用easyx 开发 devc 开发…1.在 drawflag控制检测上加入 drawsmallflag 进行 选择性再调控。
2.mousex mousey 更新来源变为 MOUSEMOVE LBUTTONDOWN RBUTTONDOWN 三个情况。
3. 记录旧瓦片的绘制减少一次长按绘制时同一瓦片被绘制次数。
使用easyx 开发 devc 开发。
使用标志位一个是用于判断执行哪些模块另一方面是通过不同标志位的合并拆分实现条理运行代码。正如一个是 flag-x 和flag_y这两个参数同时为零和moveflag0;而moveflag成为控制后续选择渲染步骤的控制变量。
以及想象中的模块代码是什么样子的比仅仅是表面的标志位区分但是由于标志位局限于所属模块不能确定此模块运行时其他模块的作用而且有时标志位无法设置导致没有标志位就需要按情况不断拆分合并代码最后发现按三个条件的8种情况满足情况。实际上是功能的实现如是否绘制和是否按键移动导致的如下四个排列组合 绘制而键盘控制画布不移动 绘制而健康控制画布移动 不绘制而键盘控制画布不移动 不绘制而键盘控制画布移动
而这四种组合对应的坐标数据运算和贴图都有各自不同的优化这也是在把得到的功能重新拆分在把多个if if if 的判断中多次修改发现可以按找如上的排列组合全部变成 if else if else这样的形式而这就是主函数里三组 选择 分支产生的由来。也只找出必须的运算来理顺各个层次之间的联系实现精确优化。
考虑到拖拽时鼠标和画布同时移动导致无法绘制于是就可以单独处理鼠标拖拽解决键盘控制画布移动和鼠标拖拽移动这里是鼠标拖拽优先级高在实现原理上其实是由于鼠标拖拽需要暂存鼠标坐标和画布原坐标而键盘控制改变当前原坐标不会改变拖拽时暂存的数据而鼠标拖拽计算出的数据是在键盘影响完重新写入数据所以键盘不会对鼠标移动产生影响。因为标志位的检测 因为拖拽的检测放在最后所以只有四种情况都检测完毕才会执行拖拽检测 而控制位导致绘制时不能拖拽绘制时鼠标坐标和画布坐标同时移动也会导致绘制失败所以四种情况里穷举一下有绘制不能拖拽有键盘移动不能拖拽。绘制的两种情况不行不绘制而键盘移动也不行只能不绘制不拖拽。 而且由于一开始的stitch 分支的拖拽标志位拖拽不会被键盘打断而moveflag标准位键盘不会被拖拽打断。 在数据计算拖拽是第一位的在贴图层面绘制和键盘移动是第一位的这样可以实现优先级随指变化而变化。
#include graphics.h
// 使用关键字 inline 声明为内联函数减少贴图函数频繁调用的开销导致的卡顿。
// 缓冲区纹理映射函数bkmesh 映射目标map 映射总网格pentable纹理集bkmeshmapibkmeshmapj映射起始点tilenum:横纵映射的数量pixnum:一个映射块的边长单位像素。
inline void freshmesh(IMAGE* bkmesh, int** map, IMAGE* pentable, int bkmeshmapi, int bkmeshmapj, int tilenum, int pixnum)
{int pennumber 0; // 暂存每一次循环的映射代号IMAGE pen NULL; // 所找到的纹理int left 0; // 这是每次循环所找到的纹理对应映射地址int top 0;SetWorkingImage(bkmesh); // 设置绘图目标为游戏背景采样区刷新采样区刷新寄存区for (int i bkmeshmapi; i bkmeshmapi tilenum; i){left 0;for (int j bkmeshmapj; j bkmeshmapj tilenum; j){pennumber map[i][j]; // 读取游戏大地图数组序号pen pentable[pennumber]; // 根据序号查找对应贴图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] j % 9; // 初始化游戏大地图 map 的参数参数范围 0-9}}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; // 背景图片寄存区左上角坐标是在游戏里的像素坐标。00可以理解为游戏大地图的左上角顶点。int bkgametop;int bkmeshgameleft; // 背景图片采样区左上角坐标是在游戏里的像素坐标。int bkmeshgametop;int bkmeshmapi; // 背景图片采样区左上角所对应的 map 数组序号。从 map[0][0]开始按照 map[i][j]其中 bkmeshmapibkmeshtop/pixnumint bkmeshmapj;int bkdeskleft; // 规定在屏幕上显示游戏背景寄存区此处记录其左上角在屏幕上的像素坐标int bkdesktop;int bkmeshdeskleft; // 规定在屏幕上显示游戏背景采样区此处记录其左上角在屏幕上的像素坐标int bkmeshdesktop;pixnum 30; // 进行初始化规定各位置具体数字bkdeskleft 200; // 游戏背景左上角将会在屏幕的200200) 处bkdesktop 200;bkgameleft 0;bkgametop 0;bkmeshdeskleft 700; // 游戏背景缓冲区左上角将会在屏幕的7000处bkmeshdesktop 0;bkmeshgameleft 0;bkmeshgametop 0;bkmeshmapi bkmeshgametop / pixnum;bkmeshmapj bkmeshgameleft / pixnum;mapinitmap(1000,1000);int pentableleft; // 忘了初始化调色盘了这里设置调色盘左上角在屏幕的坐标int pentabletop;IMAGE* pentable; // 调色板其实就是贴图数组pentableleft 0; // 调色盘左上角将会在屏幕的00处pentabletop 0;pentable new IMAGE[10];for (int i 0; i 10; i){pentable[i] IMAGE(30, 30);SetWorkingImage(pentable[i]); // 给调色板绘制颜色setfillcolor(RGB(i * 20, i * 20, i * 20)); // 这里初始化调色盘的颜色fillrectangle(0, 0, pixnum, pixnum); // 在调色板上绘制颜色纹理}int left; // 初始化绘制采样区所需的坐标相对于采样区00就是采样区左上角顶点坐标int top;left 0;top 0;// 往缓冲区刷入贴图SetWorkingImage(bkmesh); // 设置绘图目标为游戏背景采样区,刷新采样区刷新寄存区for (int i bkmeshmapi; i bkmeshmapi 30; i){left 0;for (int j bkmeshmapj; j bkmeshmapj 30; j){int pennumber map[i][j]; // 读取游戏大地图数组序号IMAGE pen pentable[pennumber]; // 根据序号查找对应贴图putimage(left, top, pen); // 把贴图画到采样区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]); // 绘制绘图板}putimage(bkdeskleft, bkdesktop, bk); // 绘制游戏背景putimage(bkmeshdeskleft, bkmeshdesktop, bkmesh); // 显示游戏背景缓冲区// 此时绘制完成以上 刷贴图采样粘贴就是实现 RPG 游戏大地图的压缩// 开始检测鼠标键盘功能int drawflag; // 设置长按 flagint drawoldmx; // 记录上一次绘制时的鼠标坐标用于检测是否重复点击相同像素来减少重复绘制int drawoldmy;int drawx; // 画笔在游戏里的位置单位像素int drawy;int olddrawi; // 记录上一次绘制的瓦片int olddrawj;int drawsmallflag; // 在 drawflag1 时检测是否刷新drawsmallflag0;olddrawi0;olddrawj0;drawx 0;drawy 0;drawflag 0;drawoldmx 0;drawoldmy 0;int pentake; // 设置不绘制时贴图代号为 -1pentake 0; // 默认黑色笔刷int draftoldmx; // 记录刚刚拖拽时的鼠标的位置int draftoldmy;int draftoldgamex; // 记录刚刚拖拽时的游戏地图位置int draftoldgamey;int draftflag; // 设置拖拽 flagdraftoldmx 0;draftoldmy 0;draftoldgamex 0;draftoldgamey 0;draftflag 0;int moveflag; // 是否键盘控制移动int flag_x; // 记录位移int flag_y;int speed;speed5;flag_x0;flag_y0;moveflag0;int mousex; // 记录鼠标位置int mousey;mousex0;mousey0;int oldbkmeshgamex; // 判断是否需要刷新int oldbkmeshgamey;ExMessage m;while (1){while (peekmessage(m, EX_KEY | EX_MOUSE)) // 一次性处理完鼠标消息参考自 https://codebus.cn/zhaoh/handle-mouse-messages-correctly{switch (m.message){case WM_LBUTTONDOWN: // 鼠标左键按下有两种情况一是选择贴图另外就是绘制贴图if (drawflag0m.x bkdeskleft m.y bkdesktop m.x bkdeskleft 300 m.y bkdesktop 300) // 如果之前不是长按状态 且按下左键时鼠标在游戏背景区域内{drawflag 1; // 才记录为正在绘制的状态mousexm.x;mouseym.y;}else if (drawflag0draftflag0m.x 0 m.y 0 m.x 30 m.y 300)pentake m.y / 30; // 选择贴图对应的代号break;case WM_LBUTTONUP:drawflag 0;drawsmallflag0;olddrawi0;olddrawj0;break;case WM_RBUTTONDOWN: // 鼠标右键拖动if (draftflag0m.x bkdeskleft m.y bkdesktop m.x bkdeskleft 270 m.y bkdesktop 270){draftflag 1;draftoldmx m.x; // 记录鼠标坐标draftoldmy m.y;mousexm.x;mouseym.y;draftoldgamex bkgameleft; // 记录游戏背景寄存区左上角坐标draftoldgamey bkgametop;}break;case WM_RBUTTONUP:draftflag 0;bkgameleft draftoldgamex - (m.x - draftoldmx); // bkgameleft - draftoldgamex - (m.x - draftoldmx)bkgametop draftoldgamey - (m.y - draftoldmy); // bkgametop - draftoldgamey - (m.y - draftoldmy)break;case WM_KEYDOWN:switch (m.vkcode) // 键盘移动控制{case 0x41: // Aflag_x-speed;moveflag1;break;case 0x57: // Wflag_y-speed;break;case 0x44: // Dflag_xspeed;break;case 0x53: // Sflag_yspeed;break;}break;case WM_KEYUP:switch(m.vkcode){case 0x41: // Aflag_x0;break;case 0x57: // Wflag_y0;break;case 0x44: // Dflag_x0;break;case 0x53: // Sflag_y0;break;}break;case WM_MOUSEMOVE:if(mousex!m.x||mousey!m.y){mousexm.x;mouseym.y;}break;}}
// 开始根据指令运行坐标变化if (draftflag 1){bkgameleft draftoldgamex - (mousex - draftoldmx); // bkgameleft-draftoldgamex-(mousex-draftoldmx)bkgametop draftoldgamey - (mousey - draftoldmy); // bkgametop-draftoldgamey-(mousey - draftoldmy)}else if (drawflag 1flag_x0flag_y0 (drawoldmx!mousex||drawoldmy!mousey) mousex bkdeskleft mousey bkdesktop mousex bkdeskleft 300 mousey bkdesktop 300){// 注意不要越界否则 gamex 为负数导致数组越界闪退。// 通过实现坐标变换与赋值达到修改游戏大地图数组moveflag0;drawoldmx mousex;drawoldmy mousey;drawx bkgameleft (mousex - bkdeskleft); // drawx-bkgameleftmousex-bkdeskleft 横坐标方向移动距离相同drawy bkgametop (mousey - bkdesktop); // drawy-bkgametopmousey-bkdesktop 纵坐标方向移动距离相同if(olddrawi!drawy/pixnum||olddrawj!drawx/pixnum){drawsmallflag1;olddrawidrawy / pixnum;olddrawjdrawx / pixnum;map[olddrawi][olddrawj] pentake; // 注意 map[y][x]而不是 map[x][y]因为判断第几行是通过 y 来控制上下移动的判断第几列是通过 x 左右移动的。}else{drawsmallflag0; // 检测到是上一次绘制的瓦片则不再刷新贴图与缓冲区。}} // 对绘制进行分类计算数据剥离特殊情况的重复绘制,仅仅是 flag_x,或者flag_y不为零时取消重复绘制判断。else if(drawflag 1 mousex bkdeskleft mousey bkdesktop mousex bkdeskleft 300 mousey bkdesktop 300){moveflag1;while(flag_x-10) // 限制在合适速度范围flag_x10;while(flag_x10)flag_x-10;while(flag_y-10)flag_y10;while(flag_y10)flag_y-10;bkgameleftflag_x; // 更新游戏背景寄存区左上角坐标bkgametopflag_y;drawx bkgameleft (mousex - bkdeskleft); // drawx-bkgameleftm.x-bkdeskleft 横坐标方向移动距离相同drawy bkgametop (mousey - bkdesktop); // drawy-bkgametopm.y-bkdesktop 纵坐标方向移动距离相同if(olddrawi!drawy/pixnum||olddrawj!drawx/pixnum){drawsmallflag1;olddrawidrawy / pixnum;olddrawjdrawx / pixnum;map[olddrawi][olddrawj] pentake; // 注意 map[y][x]而不是 map[x][y]因为判断第几行是通过 y 来控制上下移动的判断第几列是通过 x 左右移动的。}else{drawsmallflag0; // 检测到是上一次绘制的瓦片则不再刷新贴图与缓冲区。}}else if(drawflag0flag_x!0||flag_y!0){moveflag1;while(flag_x-10) // 限制在合适速度范围flag_x10;while(flag_x10)flag_x-10;while(flag_y-10)flag_y10;while(flag_y10)flag_y-10;bkgameleftflag_x;bkgametopflag_y;}else{// 既不绘制也不移动也不拖拽}// 根据计算出的坐标数据进行绘制分多种情况分别绘制减少函数重复调用与无效调用if(drawsmallflag1moveflag0){freshmesh(bkmesh, map, pentable, bkmeshmapi, bkmeshmapj, 27, 30); // 刷新重新映射其实就是开头初始化的代码这里是给了一个封装示例但未进行性能优化freshbk(bk, bkmesh, bkgameleft, bkgametop, bkmeshmapi, bkmeshmapj, 9, 30);showbk(bk, bkdeskleft, bkdesktop);showbkmesh(bkmesh, bkmeshdeskleft, bkmeshdesktop);}else if(moveflag1drawsmallflag1){if(bkgameleft0) // 网格越界检测并调整bkgameleft0;if(bkgametop0)bkgametop0;if(bkgameleft30*300)bkgameleft30*300;if(bkgametop30*300)bkgametop30*300;while (bkgameleft bkmeshgameleft) // 更新游戏采样区坐标一些简单换算bkmeshgameleft -270;while (bkgametop bkmeshgametop )bkmeshgametop - 270;while(bkgameleftbkmeshgameleft270270)bkmeshgameleft 270;while(bkgametopbkmeshgametop270270)bkmeshgametop 270;bkmeshmapi bkmeshgametop / pixnum;bkmeshmapj bkmeshgameleft / pixnum;freshmesh(bkmesh, map, pentable, bkmeshmapi, bkmeshmapj, 27, 30);freshbk(bk, bkmesh, bkgameleft, bkgametop, bkmeshmapi, bkmeshmapj, 9, 30);showbkmesh(bkmesh, bkmeshdeskleft, bkmeshdesktop);showbk(bk, bkdeskleft, bkdesktop);}else if(moveflag1) // 分类渲染, drawflag0 时再选择性刷新缓冲区{if(bkgameleft0) // 网格越界检测并调整bkgameleft0;if(bkgametop0)bkgametop0;if(bkgameleft30*300)bkgameleft30*300;if(bkgametop30*300)bkgametop30*300;while (bkgameleft bkmeshgameleft) // 更新游戏采样区坐标一些简单换算由于频繁调用函数在这里产生了明显的卡顿影响所以这里就不再封装成函数bkmeshgameleft -270;while (bkgametop bkmeshgametop )bkmeshgametop - 270;while(bkgameleftbkmeshgameleft270270)bkmeshgameleft 270;while(bkgametopbkmeshgametop270270)bkmeshgametop 270;bkmeshmapi bkmeshgametop / pixnum;bkmeshmapj bkmeshgameleft / pixnum;if(oldbkmeshgamex!bkmeshgameleft||oldbkmeshgamey!bkmeshgametop) // 判断是否更新采样区{freshmesh(bkmesh, map, pentable, bkmeshmapi, bkmeshmapj, 27, 30);oldbkmeshgamexbkmeshgameleft;oldbkmeshgameybkmeshgametop;showbkmesh(bkmesh, bkmeshdeskleft, bkmeshdesktop);}freshbk(bk, bkmesh, bkgameleft, bkgametop, bkmeshmapi, bkmeshmapj, 9, 30);showbk(bk, bkdeskleft, bkdesktop);}else if(draftflag) // 分类渲染-只拖拽{if(bkgameleft0) // 网格越界检测并调整bkgameleft0;if(bkgametop0)bkgametop0;if(bkgameleft30*300)bkgameleft30*300;if(bkgametop30*300)bkgametop30*300;while (bkgameleft bkmeshgameleft) // 更新游戏采样区坐标一些简单换算bkmeshgameleft -270;while (bkgametop bkmeshgametop )bkmeshgametop - 270;while(bkgameleftbkmeshgameleft270270)bkmeshgameleft 270;while(bkgametopbkmeshgametop270270)bkmeshgametop 270;bkmeshmapi bkmeshgametop / pixnum;bkmeshmapj bkmeshgameleft / pixnum;if(oldbkmeshgamex!bkmeshgameleft||oldbkmeshgamey!bkmeshgametop) // 判断是否更新采样区{freshmesh(bkmesh, map, pentable, bkmeshmapi, bkmeshmapj, 27, 30);oldbkmeshgamexbkmeshgameleft;oldbkmeshgameybkmeshgametop;showbkmesh(bkmesh, bkmeshdeskleft, bkmeshdesktop);}freshbk(bk, bkmesh, bkgameleft, bkgametop, bkmeshmapi, bkmeshmapj, 9, 30);showbk(bk, bkdeskleft, bkdesktop);}Sleep(20); // 休眠 20 毫秒减少 CPU 占用}return 0;
}
// 边绘制边移动最大边界 2.30GHz 3%占用内部 2.25Ghz。仅绘制:1.8GHz, 拖拽:0.99GHz旧瓦片绘制检测又减少重复绘制显著平稳峰值降低