对"QQGame-大家来找茬"的辅助工具的改进

简介:   【前言】最近在博客园首页上看到有“大家来找茬”这个游戏(此游戏为找出两个相近图片的不同点)外挂的相关帖子,所以这里我也翻看了我之前(2009年5月)的写的一个简单的辅助程序(采用 VC6 开发的)。

  【前言】最近在博客园首页上看到有“大家来找茬”这个游戏(此游戏为找出两个相近图片的不同点)外挂的相关帖子,所以这里我也翻看了我之前(2009年5月)的写的一个简单的辅助程序(采用 VC6 开发的)。我在当时的写法是图快速和简单,代码效率上不是最高的,所以我现在使用更加合理的方法将其改进(采用 VC2005 开发)。因为发表时间临近春节,即将回籍贯老家,所以行文和排版等难免仓促,有待在将来继续改进。

 

  之前我在 2009 年 5 月写的文章为:《快速“美女找茬”(辅助工具)》

 

  解决方案的主要步骤是相同的,找到游戏窗口,然后将游戏窗口的内容截图,然后把不同点用一个透明图层的方式,对齐覆盖到游戏窗口的相应位置。这里并没有继续去帮助用户做点击,因为这一步需要把图像上的差异点集合划分成五个区域,这需要进一步处理(留待将来考虑)。

 

  相比之前的做法,本次改进内容包括:

  (1)增加配置文件记录游戏窗口的布局信息(这些信息为截图后在 Photoshop 中测量得出),这样在游戏布局因为升级等原因发生改变时,程序不需要进行重新编译,普通用户只需要自行修改配置文件即可。

  (2)检测差异像素点时,直接对图像像素数据进行分析,这样的效率会更高。(由于当前的 PC 已经普及多核 CPU,所以这一步也采用了多线程技术。)

  (3)增加全局热键的配置,因为发出一个命令时,键盘操作的速度比鼠标这种定点设备操作 GUI 的速度更快。

 

  在游戏时,效果如下图所示:

 

  

 

  左侧是一个“鼠标穿透”的半透明图层窗口(称之为“提示窗口”),所以用户可以直接在左侧的红色方块内部点击即可。用户可以在程序位于通知栏的图标右键菜单中,选择设置,然后设置全局性热键,提示窗口的不透明度等信息。设置对话框如下图:

 

  

 

  接下来主要分析以上改进(主要是 2 和 3 )的实现。

  改进(1)比较容易,只需要增加一个配置文件即可,其主要内容如下:

; 连连看游戏窗口信息
[GameWnd]
Class=#32770
Text=大家来找茬

;图片 1 的位置(客户区坐标)
[Image1]
Left=10
Top=186
Right=390
Bottom=471

;图片 2 的位置(客户区坐标)
[Image2]
Left=403
Top=186

 

  以上内容主要是用于存储游戏窗口的类名和标题,以及两幅图片在游戏窗口中的客户区坐标,比较直观。很显然,图片2的右下角坐标无需给出,因为两个图片很显然是相同大小的。

 

  对于(2),我首先能想到的是,之前使用了 GetPixel / SetPixel 函数,尽管是对内存 DC 操作,但这样的效率可能仍然是不够高的。所以这一次我改为直接对像素数据块操作。同时,这一次我决定使用对两个图像的相同位置的像素数据直接用异或操作来处理,同时也把对应的指针和数据单位扩展为 4 个字节的 DWORD 类型(而不是单独操作每个像素的 R G B 通道),这样将会加快处理速度。这样做以后,如果我们直接把异或后的结果显示出来,效果如下图(提示窗口已经为完全不透明):

 

  

 

  直接显示异或结果,很显然图像相同的部分会变为全黑色(因为相同的数据的异或结果为零),不同的位置会显示出一些比较鲜艳的色彩。这样的显示效果其实并不太好,不太容易辨别,所以我还是把结果变为红色。这里有两个问题,导致我得出最终的解决方案。

  (2.1)为了让我对两个数据进行异或时,他们的地址能以 DWORD 对齐。所以我对游戏窗口抓图时,把两个图片分别复制到一个上下排列的内存位图(如下,其尺寸为单个图片宽度 * 二倍图片高度),然后对这个内存位图的像素数据进行异或。如果不这样截图,那么直接对游戏窗口原样图片进行操作,由于图片在游戏窗口中的位置对我们来说是“随机”的,那么就无法保证像素数据能正好对齐到 DWORD(这个问题在 24 bpp 位图时存在,但当采用 32 bpp 内存位图时,任何像素都一定会对齐到 DWORD,这个忧虑已经不存在了,但对于提高复制屏幕图像的效率而言,这样截图依然是应该的,因为在两幅图像以外的部分是我们不感兴趣的,也就没必要全部截取)。(注意这里有一个基本可以肯定的前提条件,系统在分配位图时,其像素数据的起始地址一定是对齐到 DWORD 的。)

 

 图片 1
 图片 2

 

 

  (2.2)最开始我创建的内存位图为 24 BPP,这样一个像素占据 3 Bytes,而一个 DWORD 占据 4 Bytes,所以如果是 24 BPP,即使找到一个操作结果不为零,要定位到像素或者对此像素设置为特定颜色(例如红色)也会比较麻烦(需要做换算)。所以这里我创建内存位图时把 BPP 改为 32,这样每个 DWORD 就是一个像素,这样就能对图片上的差异像素很容易的设为特定颜色,例如红色就是 0x00FF0000 (这个数字书写出来的顺序是,0x-AA-RR-GG-BB,与 little - endian 的存储顺序相反)。使用 CreateDIBSection 创建一个内存位图,代码比较简单。

 

  (2.3)执行异或时,采用多线程处理。如果是单个线程执行这个计算,那么对于图像数据的输入来说必然是串行的。为了发挥当前的多核 CPU 的优势,所以这里把此异或计算采用多线程执行,把图片从上到下切分为几个高度较小的横条(横条的宽度等于图片宽度,个数等于要创建的线程数),每个线程分配到图片的其中一个横条。由于几个横条部分的数据彼此独立,不会发生数据相关性,所以可以直接并行处理,只需要等所有线程任务完成后(WaitForMultipleObjects),再把内存位图刷新到窗口上即可。以下是线程过程代码(像素数据的起始地址在创建位图时已经被转换为 LPDWORD):

 

  备注:这里的任务切分,为从上到下把图像进行细分,一是遍历像素的方便,二是同时 CPU 对“数据局部性”的偏好,这样可以保持比较理想的 cache 命中率。在这个问题中,还可以考虑能否利用上 Intel CPU 的 MMX 和 SSE2 特性,进一步提高处理的并行度,以提高处理效率。(2014年5月4日 补充 -- hoodlum1980)

 

DWORD WINAPI ThreadEntry(LPVOID lpParameter)
{
    int count, i, lineSize;
    LPTASK pTask = (LPTASK)lpParameter;

    //DWORD Per Line;
    lineSize = g_AppData.nStrideLayer / sizeof(DWORD);

    //Total Count of DWORDS;
    count = (pTask->nEnd - pTask->nStart) * lineSize;

    //[End, Start); p1 - Image1; p2 - Image2
    LPDWORD p1 = g_AppData.lpBitsLayer
        + (g_Layout.nImageHeight * 2 - 1 - pTask->nEnd) * lineSize;

    LPDWORD p2 = g_AppData.lpBitsLayer
        + (g_Layout.nImageHeight - 1 - pTask->nEnd) * lineSize;

    for(i = 0; i < count; i++)
    {
        *p1 = *p1 ^ *p2;

        //0xAARRGGBB
        if(*p1) *p1 = 0x00FF0000;
        ++p1;
        ++p2;
    }
    return 0;
}

 

  采用以上方法之后,执行速度有明显提高,在我的台式机,CPU 为 I7, 16GB 内存,操作系统为 WIN7,之前的程序检测一次的执行速度为 260 ms 左右,改进后的程序的执行速度为 15 ~ 16 ms(而且经常为 0 ms,让我觉得不可思议,这里我采用的只是 GetTickCount 相减得到的粗略估算,没有考虑 CPU 调度的影响,并且这个函数本身就对精确性的要求不是很高),速度上改进前大约为改进后的 16 倍。从用户体验角度看,改进前求解有少许延迟感,改进后速度太快感受不到延迟。由于速度太快,所以我放弃了原本想在检测过程中切换通知栏图标的想法。

 

  最后是两个程序的可执行文件的下载链接(采用 VS2005 ,  C++ 开发):

  http://files.cnblogs.com/hoodlum1980/FindItEx_Bin.zip

 

  之后的工作则是模拟点击功能。根据判断结果把差异像素分解成 5 个集合,然后在这些集合所在位置单击一次。这将会进一步加快游戏完成速度。这一步属于相对简单的图像分析处理任务,留待将来考虑。

 

目录
相关文章
|
6月前
盘点效率工具RunFlow那些容易被忽略的功能
RunFlow隐藏实用功能一览:固定工作窗口、预览菜单、浏览器直接打开剪贴板URL、多行输入(Ctrl+Enter换行)、固定结果展示。提升效率,从发现这些小窍门开始。
46 4
盘点效率工具RunFlow那些容易被忽略的功能
|
5月前
|
前端开发 Oracle Java
编程开发软件工具下载
编程开发软件工具下载
33 0
|
SQL 前端开发 程序员
推荐一款在线工具-程序员的工具箱
推荐一款在线工具-程序员的工具箱
97 0
|
数据库连接 测试技术 开发工具
猿创征文|工具百宝箱-编辑器-笔记工具-日常小工具-原型设计工具
猿创征文|工具百宝箱-编辑器-笔记工具-日常小工具-原型设计工具
|
数据采集 测试技术 Windows
软件测试|自动化界面操作神器pywinauto教程(一)
软件测试|自动化界面操作神器pywinauto教程(一)
516 0
|
Web App开发 存储 IDE
5分钟学会制作自动化脚本——自动化脚本辅助开发IDE——Selenium IDE介绍(测试工程师必备)
本文介绍了自动化测试的辅助工具,Selenium IDE的基本使用,有助于自动化工程师辅助编辑自动化脚本,初步建立简单自动化脚本。
431 0
5分钟学会制作自动化脚本——自动化脚本辅助开发IDE——Selenium IDE介绍(测试工程师必备)
|
Web App开发 前端开发 JavaScript
角落的开发工具集之Vs(Visual Studio)2017插件推荐
因为最近录制视频的缘故,很多朋友都在QQ群留言,或者微信公众号私信我,问我一些工具和一些插件啊,怎么使用的啊?那么今天我忙里偷闲整理一下清单,然后在这里面公布出来。
1369 0