Xiangism

从一个无知角落里开始,蹒跚学步,一个未知到另一个未知,在跌跌撞撞中越走越快,越走越远,最后宇宙也为之开源。对于探索者来说,最后他们的思想总是变得和自己的足迹一样伟大。
  博客园  :: 首页  :: 联系 :: 管理

自动扫雷——游戏框架

Posted on 2012-10-28 11:24  Xiangism  阅读(3595)  评论(2编辑  收藏  举报

要实现一个自动完成windowsXP扫雷游戏(winmine,XP下用这个命令可启动游戏)的程序,需要实现下面三大点:

  • 获取游戏数据,即分析游戏在类型(初级、中级还是高级),每个块是否揭开,如何揭开了上面的数字是多少。
  • 分析数据,即要从上面所得的数据,分析出哪些块是雷,哪些不是雷,哪些还不能确定。
  • 从第二步得到的数据中,操作鼠标去点击那些确定没有雷的块。

下面详细介绍自己如何实现第一步和第三步(分析数据,留到后面的文章中介绍):

一、获取游戏数据

为了简化处理,自己只研究XP系统下自带的扫雷。后来自己的电脑被迫升级到win7后,将XP下的扫雷游戏复制过来,继续实现。

用FindWindow(NULL,_T("扫雷"))查找到扫雷游戏的窗体句柄,用窗体句柄找到窗体所在的区域。再截取到整个屏幕的图像(详见http://www.cnblogs.com/xiangism/archive/2012/06/21/2557901.html),这样即可获取游戏场景的像素信息,接下面的任务即是通过分析像素值完成任务。

游戏场景,如图:

可以发现每个数字的颜色都不一样,故可以通过颜色特征判断出每个块上分别是什么数字。下面分别是从1-8这些数字的颜色RGB值

{255,0,0},
{0,128,0},
{0,0,255},
{128,0,0},
{0,0,128},
{128,128,0},
{0,0,0},
{128,128,128}   RGB从右往左排列。
没有揭开的块,上面和左面会有白色区域,通过这个信息即可判断出块是否被揭开。

而游戏类型的判断,则是通过窗体窗口的大小实现,初级的游戏窗口宽是170,中级为282,高级为506~~

二、操作游戏

如果已经从获取的数据中分析出了哪些块不是雷,那么即可自动点击。这里使用的方法是用控件鼠标的win32API去点击。即

 

//将确定没有雷的方块坐标i,j,转化成鼠标要点击的像素坐标。
//m_gameRect是窗体相对于桌面的坐标,firstClick是第一块相对于窗体的坐标,width是每一个块的宽度
int x= m_gameRect.left + firstClick.first + i*width; 
int y= m_gameRect.top + firstClick.second +j*width;  
SetCursorPos(x,y);
mouse_event(MOUSEEVENTF_LEFTDOWN,x,y,0,0);
mouse_event(MOUSEEVENTF_LEFTUP,x,y,0,0);

还有一种方式,即是向游戏窗体发现鼠标点击的消息,

SendMessage(m_gameHandle,WM_LBUTTONDOWN,1,r);
SendMessage(m_gameHandle,WM_LBUTTONUP,1,r);

不过这种方式,只能在xp下用,在win7下有点问题,为了统一,就都用mouse_event了。

下面是整个程序的UML静态类图

 

从上面的类图可以看出,开始也想支持win7的自带扫雷游戏,可发现win7扫雷太过花哨,数字都是用渐变色显示的,不过开始为了挑战下自己的实力,想用图像处理、模式识别的相关知识来获取游戏信息,可在实现过程中一不小心把win7下的扫雷游戏弄成这样了(好像是在某一个操作鼠标点击游戏界面时弄成这样的)。

奇大无比   并且也没办法还原回去了,于是放弃了对win7扫雷的支持。只专注与实现自己想要实现的东西.对于win7系统,自己的做法是将xp中的那个扫雷程序复制过来,即可。