这几天做了个外挂,主要是想学习下相关技术,
参考的是郁金香老师的视频
核心算法是我自己实现的
我在判断3条线路连通性时,用了4个辅助点,纵向pa和pb,横向pc和pd
让其中2个点与我们棋盘上的棋子形成一个矩形,
然后遍历它们组成这个矩形的所有行和所有列
把所有的情况都考虑成3条路径,因为它们都在一个矩形上
其中有的点重合的话那就是2条或1条路径
只要保证2个参考点p1和p2不重叠就行了
纵向时的pa与pb 可以和参考点p1或p2重叠
横向时的pc与pd 可以和参考点p1或p2重叠


xp_sp2
vc6的MFC程序
在框架代码中调用下面的方法就可以了
//llk_wg.h
const PCHAR gameCaption="QQ游戏 - 连连看角色版"; //程序窗口标题
const LPARAM lpStartMenu= (568<<16)+655; //开始按钮坐标
HWND hGame=::FindWindow(NULL,gameCaption); //获取游戏窗口句柄
DWORD dwProcessId; //进程的pid
HANDLE hProcess; //进程句柄
LPCVOID lpBaseAddress; //基地址
byte arrChessData[11][19]; //棋盘数据存放
DWORD rDwLen; //实际读取的字节数
LPDWORD lpNumberOfBytesRead=&rDwLen; //实际读取的字节数指针
BOOL readFlag=false; //读取数据标志失败
BOOL ReadData(LPCVOID lpBaseAddress,LPVOID lpRead,DWORD nsize);//读数据
void LeftClick(POINT pp); //模拟鼠标单击
BOOL ReadChessData(); //读棋盘数组数据
BOOL CheckChess(POINT p1,POINT p2); //检测棋子是否可清除
BOOL CheckLine2p(POINT pi,POINT pj) ; //检测2点是否直通(无障碍)
BOOL Click2p(POINT p1,POINT p2); //模拟点击消息
void ClearPairOfChess(BOOL b) ; //消除棋子主过程
void KillAll(); //秒杀
void AutoStart(); //自动开局
BOOL CheckLine2p(POINT pi,POINT pj)//检测同行或同列的2点是否连通(无障碍)
{ //关键算法之一
POINT pUp;
POINT pDown;
POINT pLeft;
POINT pRight;
if ((pi.x==pj.x)&&(pi.y==pj.y)) //棋子重叠可连通
{
return true;
}
if (pi.x==pj.x) //同列时(x相等,y不等)
{
if (pi.y<pj.y)
{
pUp=pi;
pDown=pj;
}
else
{
pUp=pj;
pDown=pi;
}
if ( 1==(pDown.y-pUp.y) ) //相邻棋子可连通
{
return true;
}
else //不相邻时
{
for (int lineNum=pUp.y+1; lineNum<pDown.y; lineNum++)
{
if (arrChessData[lineNum][pUp.x]!=0)
{
return false; //有障碍
}
}
}
}//
if (pi.y==pj.y) //同行时(x不等,y相等)
{
if (pi.x<pj.x)
{
pLeft=pi;
pRight=pj;
}
else
{
pLeft=pj;
pRight=pi;
}
if ( 1==(pRight.x-pLeft.x) ) //相邻棋子可连通
{
return true;
}
else
{
for (int columnNum=pLeft.x+1; columnNum<pRight.x; columnNum++)
{
if (arrChessData[pLeft.y][columnNum]!=0)
{
return false; //有障碍
}
}
}
}//
return true;
}
BOOL CheckChess(POINT p1,POINT p2) //检测棋子可否消除
{ //关键算法之一
bool checkFlag=false;
POINT pa,pb;//pa的x坐标与p1相等,pb的x坐标与p2相等
pa.x=p1.x;
pb.x=p2.x;
POINT pc,pd;//pc的y坐标与p1相等,pd的y坐标与p2相等
pc.y=p1.y;
pd.y=p2.y;
for (int lineNum=0;lineNum<11;lineNum++)
{
pa.y=lineNum;
pb.y=lineNum;
if( CheckLine2p(p1,pa)&&CheckLine2p(pa,pb)&&CheckLine2p(pb,p2) )
{
//Click2p(p1,p2); //执行消除
checkFlag=true;
}
}
for (int columnNum=0;columnNum<19;columnNum++)
{
pc.x=columnNum;
pd.x=columnNum;
if ( CheckLine2p(p1,pc)&&CheckLine2p(pc,pd)&&CheckLine2p(pd,p2) )
{
//Click2p(p1,p2); //执行消除
checkFlag=true;
}
}
return checkFlag;
}
BOOL Click2p(POINT p1,POINT p2) //模拟单击事件
{ //棋子宽度31,高度35
//int x=25,y=195; //第一个棋子坐标
LeftClick(p1);
LeftClick(p2);
ReadChessData();
if (arrChessData[p1.y][p1.x]==0)
{
return true; //成功消除一对棋子
}
return false;
}
void KillAll() //秒杀
{
for (int a=0;a<10;a++)
{
ClearPairOfChess(true); //一般5次循环内就完成秒杀
}
}
void ClearPairOfChess(BOOL b) //清除一对棋子的主过程
{
ReadChessData(); //更新一下棋盘数据
//遍历棋盘,找出成对的棋子
POINT p1,p2;
int x1,y1;
int x2,y2;
for (y1=0;y1<11;y1++) //遍历行数y
{
for (x1=0;x1<19;x1++) //遍历列数x
{
if (arrChessData[y1][x1]!=0) //不为空子时,此子设为p1
{
for (y2=y1;y2<11;y2++)
{
for (x2=0;x2<19;x2++)
{
if ((arrChessData[y1][x1]==arrChessData[y2][x2])&&
(!((x1==x2)&&(y1==y2)))
)
{ //存在p2时
p1.x=x1;
p1.y=y1;
p2.x=x2;
p2.y=y2;
if (CheckChess(p1,p2)) //检测是否可清除
{
if (Click2p(p1,p2))//消除
{
if (!b) //不秒杀
{
return;
}
}
}
}
}
}
}
}
}
}
void LeftClick(POINT pp) //模拟鼠标单击
{
if (hGame)
{
LPARAM lParam = ((195+pp.y*35)<<16)+(25+pp.x*31);
SendMessage(hGame,WM_LBUTTONDOWN,0,lParam);
SendMessage(hGame,WM_LBUTTONUP,0,lParam);
}
}
void AutoStart() //自动开始按钮
{
hGame=::FindWindow(NULL,gameCaption); //获取游戏窗口句柄
if (hGame)
{
LPARAM lParam = lpStartMenu; //(568<<16)+655
PostMessage(hGame,WM_LBUTTONDOWN,MK_LBUTTON,lParam);
PostMessage(hGame,WM_LBUTTONUP,0,lParam);
}
}
BOOL ReadData(LPCVOID lpBaseAddress,LPVOID lpRead,DWORD nsize) //读数据
{ //3个参数分别是,基址,读取数据存放的缓冲区指针,要读取的数据大小
hGame=::FindWindow(NULL,gameCaption);//获取游戏窗口句柄
if (hGame==NULL)
{
//AfxMessageBox(gameErr);
return readFlag;
}
::GetWindowThreadProcessId(hGame,&dwProcessId); //获取进程id
hProcess=::OpenProcess(PROCESS_ALL_ACCESS,false,dwProcessId); //打开
readFlag=::ReadProcessMemory(hProcess,lpBaseAddress,
lpRead,nsize,lpNumberOfBytesRead); //读一个字节
return readFlag;
}
BOOL ReadChessData() //读棋盘数组数据
{
lpBaseAddress= (LPCVOID)0x0012A480; //棋盘数组基址
ReadData(lpBaseAddress,arrChessData,sizeof(byte)*11*19);
return readFlag;
}

- 大小: 28.5 KB

- 大小: 36 KB
分享到:
相关推荐
易语言QQ连连看辅助源码! 原创 要的速度了
连连看是一款广受欢迎的休闲益智游戏,其FLEX版本是使用Adobe的Flex技术进行开发的。Flex是一种基于...通过深入理解这些技术,开发者不仅可以制作连连看游戏,还可以进一步开发其他类型的富互联网应用程序。
"实现单消的QQ连连看挂"是针对流行休闲游戏QQ连连看的一款辅助工具,其核心功能在于帮助玩家自动完成单个棋子的消除操作。这个项目可能涉及到的知识点包括: 1. **连连看游戏机制**:连连看是一款基于图形配对的...
以《QQ连连看为例》 1.1、一个最简单的外挂 1.1.1、游戏数据分析(SPY++) 1.1.1、游戏窗口数据分析(SPY++) a、取得窗口相对坐标 b、读出游戏窗口信息GetWindowRect c、移动鼠标指针SetCursorPos 1.1.2 用VC++写个最...
以《QQ连连看为例》 1.1、一个最简单的外挂 1.1.1、游戏数据分析(SPY++) 1.1.1、游戏窗口数据分析(SPY++) a、取得窗口相对坐标 b、读出游戏窗口信息GetWindowRect c、移动鼠标指针SetCursorPos 1.1.2 用VC++写个最...
以《QQ连连看为例》 1.1、一个最简单的外挂 1.1.1、游戏数据分析(SPY++) 1.1.1、游戏窗口数据分析(SPY++) a、取得窗口相对坐标 b、读出游戏窗口信息GetWindowRect c、移动鼠标指针SetCursorPos 1.1.2 用VC++写个最...
在【QQ连连看外挂GUI】的实现过程中,自动化测试的原理得到了巧妙的应用。这个外挂的制作实际上是对游戏进行自动化操作的过程。首先,通过调用Win32 API函数,如`FindWindow`,获取游戏窗口的句柄,这一步骤类似于...