当前位置:编程学习 > 网站相关 >>

编程实现连连看机器人外挂

文/图 Zorro [CUST]
连连看是一款非常不错的休闲游戏,相信大家都玩过。本文的连连看是单机版V3.0,网上曾经有过此类外挂,不过只能通过修改内存游戏数值提高生命值和提示数量。显然在自动化日益发达的今天,它不能满足我们完全自动化的要求。于是,机器人玩游戏就提上了我的日程。
 
基本思路分析
我们的目标是外挂能够自动点击成对的棋牌。要实现这个功能有一个关键的地方,就是连连看的F5热键提示功能,按下F5键,会自动提示你一对相同的牌。如图1所示,看那两个不知道小猫还是小狗的动物的牌,它们的底色跟其它的都不一样,取色值得到十六进制值$00808000。
图1
我的基本的思路是这样的,首先找到存放提示和生命值的内存地址,将它们改成无限大小;接着向游戏窗口发送F5模拟键盘按键消息,使游戏窗口出现一对相同棋牌;然后扫描每个棋牌的特殊坐标(坐标算法以下将会介绍),获取颜色值,如果颜色值等于$00808000则模拟鼠标单击,找到另一个再单击,这样就完成了一次游戏过程。流程图如图2所示。
图2
查找游戏数值内存地址并改写
提示的数值在游戏画面中是直接显示出来的,生命值虽然没有显示,但是有一个红色的进度条。在这里可以选用几款不同的内存查找工具,如金山游侠和Cheat Engine,都能够比较容易地找到内存地址。因为它的数值都是直接存放在内存中的,没有变化,方便了我们作弊。下面以金山游侠为例简单介绍一下查找过程。在金山游侠输入数值4,也就是我们初始的提示数目,点击搜索,选择连连看进程,会扫到很多结果,回到游戏中,消耗掉一个提示数目,然后再回到游侠中输入3,点击搜索,就找到提示数值的内存地址了,如图3所示,提示的地址为$0012FEBC,记下这个地址。
图3
生命搜索更为简单,因为它是一直在减少的。在输入框中直接输入一个负号,一直点搜索,直到搜索的数目不再变化为止,此时会有多个地址。随便修改几个地址存放的数值,改成600,看哪个地址的数值改变后生命值回到原来的100%,那个地址就是生命值存放的内存地址了。这里的生命值地址为$0012F4D4。
本文修改过程比较简单,主要用到三个API函数,GetWindowThreadProcessId用于获取主窗体线程ID,OpenProcess用于打开进程,WriteProcessMemory用于写入。
 
扫描游戏窗口颜色值
扫描游戏窗口颜色是整个程序的关键,为了提高扫描效率,要在每张棋牌上选取关键点,如果能够做到一张棋牌只有一个关键点则是最好的。我们先来仔细观察游戏窗口,难度为初级时一共有12×7个棋牌,未按下F5时棋牌的底色都是一样的颜色,每张棋牌的底部空余相对较大。棋牌区域和整个游戏窗体的位置也是相对固定的。扫描点主要确定为12×7个,不同难度时要做相应的调整,为节省篇幅,只对初级难度画面进行分析。我选取的扫描点如图4所示,黑线的交叉点位置,第一行我已标注,以下六行同上。
图4
那么我们如何确定扫描点的坐标呢?在确定扫描点坐标之前,我们要先测量一些主要的数据,比如每个棋牌的长宽(50×40px),游戏主窗口左上角顶点坐标和游戏棋牌区域左上角顶点坐标。这两个顶点的坐标为(154,163)。我们定义(TopX,TopY)为主窗体左上角顶点坐标,共有n行m列,则扫描点的计算公式可为:
x := TopX+154+30+40*(m-1);
y:= TopY+163+45+50*(n-1);
之后我们就可以通过截取颜色实现了。
 
编程实现
界面设计如图5所示,添加两个Timer控件,一个进行实时更改游戏内存,另一个进行点击玩游戏。“启动”选项可以进行手动的点击,“全自动”就什么也不用管了,让它自己玩去吧,呵呵。主要的实现代码如下。
图5

 
unit Unit1;
interface
…………
{省略部分,详见源码}      
implementation
var
hWinMain,pHandle:THandle;
PID:DWORD;
{$R *.dfm}
{过程名:PressF5,功能:模拟快捷键F5}
procedure TForm1.PressF5;
begin
{F5快捷键}
PostMessage(hWinMain,WM_KEYDOWN,VK_F5,0);// hWinMain游戏主窗体句柄
PostMessage(hWinMain,WM_KEYUP,VK_F5,0);
end;
{过程名:cheate,功能:修改游戏内存数值}
procedure TForm1.cheate;
var
pINT,pLife:Integer;
s_cb:DWord;
begin
pINT:=100;
Plife:=600;
GetWindowThreadProcessId(hWinMain,@PID);//获取主窗体线程ID
pHandle:=OpenProcess(PROCESS_ALL_ACCESS,FALSE,PID);//打开进程
IF pHandle <> 0 then
begin
if chk1.Checked then WriteProcessMemory(pHandle,Pointer($12F4D4),@plife,1,s_cb);//写内存
if chk2.Checked then WriteProcessMemory(pHandle,Pointer($12FEBC),@pINT,1,s_cb);
end
else
begin
Application.MessageBox(打开进程失败,错误,0);
tmr1.Enabled :=False;
end;
end;
{函数名:GetTopXY,功能:获取主窗体坐标}
function TForm1.GetTopXY:TRect;
var
cpRect:TRect;
begin
if hWinMain <> 0 then
begin
GetWindowRect(hWinMain,cpRect);
Result := cpRect;
end;
end;
{函数名:getColor,功能:获取坐标点颜色值}
function TForm1.getColor(x,y:Integer):TColor;
var
hDC: THandle;
YourColor: TColor;
begin
hDC := GetDC(0);
with TCanvas.Create do
try
Handle := hDC;
YourColor:= Pixels[x,y];
Result:=YourColor;
finally
Free;
ReleaseDC(0,hDC);
end;
end;
{过程名:AutoRunGame,功能:扫描游戏区域}
procedure TForm1.AutoRunGame;
var
X,Y,m,n:Integer;
TopX,TopY:Integer;
rec:TRect;
begin
rec := GetTopXY;
TopX := rec.Left;
TopY := rec.Top;
PressF5; //按下快捷键F5
for n:=1 to 7 do
begin
y:= TopY+163+45+50*(n-1);
for m:= 1 to 12 do
begin
x := TopX+154+30+40*(m-1);
if getColor(x,y) = 8421376 then //截取坐标点颜色值
begin
setcursorpos(x,y);
mouse_event(MOUSEEVENTF_LEFTDOWN,0,0,0,0);//模拟鼠标按键
end;
end;
end;
end;
{启动按钮单击事件过程}
procedure TForm1.btn1Click(Sender: TObject);
begin
hWinMain:= FindWindow(#32770,连连看);
//查找主窗体句柄
if (chk1.Checked or chk2.Checked) then
begin
if (hWinMain<>0 )then
tmr1.Enabled := True
else
Application.MessageBox(游戏未启动,提示,0);
end
else
Application.MessageBox(请至少选择一个功能,提示,0);
end;
procedure TForm1.tmr1Timer(Sender: TObject);
begin
cheate;//修改游戏内存数值过程
end;
procedure TForm1.btn2Click(Sender: TObject);
begin
tmr1.Enabled :=False;
end;
procedure TForm1.btn3Click(Sender: TObject);
begin
btn1Click(self);
SetForegroundWindow(hWinMain);
if FindWindow(#32770,连连看)=0 then Exit;
//未发现游戏窗体则退出
tmr2.Enabled:=True;
end;
{ tmr2Timer,自动玩游戏过程}
procedure TForm1.tmr2Timer(Sender: TObject);
begin
AutoRunGame;
if FindWindow(#32770,成功)<>0 then tmr2.Enabled:=False;//过关停止
end;
end.
经过测试,机器人顺利地完成了游戏,速度差不多为每秒点击一对,正确率也很高,基本达到了预想的要求。关掉音效的话能够提高点击速度,因为有音效游戏就会变慢,timer的interval属性值也需要多次调整才能更精确。有了上面的基础,之后需要大家做的,就是进一步修改以适应中级和高级难度的游戏了
补充:综合编程 , 其他综合 ,
CopyRight © 2012 站长网 编程知识问答 www.zzzyk.com All Rights Reserved
部份技术文章来自网络,