项目效果
直接使用C语言,实现【连连看】最强辅助
不是逆向,而是图像处理。
图像处理,更高维度的技术手段。
无人机战争-电影-完整版视频在线观看-爱奇艺
美军无人机斩首伊朗2号人物卡西姆·苏莱马尼少将
贵州天网抓捕犯人-仅需7分钟
项目原理:
1)截图游戏画面
2)图形处理
3)路径分析,找到可消除的方块
4)控制鼠标进行点击
使用任意版本的VS, 创建一个空项目。
安装后的目录类似如下:
D:\opencv\build\include
D:\opencv\build\include\opencv
D:\opencv\build\include\opencv2
D:\opencv\build\x86\vc12\lib
注意选择x86或者x64
opencv_core249d.lib
opencv_highgui249d.lib
opencv_imgproc249d.lib
opencv_core249d.dll
opencv_highgui249d.dll
opencv_imgproc249d.dll
找到游戏窗口,将游戏放在左上角
使用spy++工具确定连连看游戏窗口的“窗口标题”
代码实现:
#include
#include
int main(void) {
printf("are you ready?\n");
system("pause");
//找到游戏窗口,将游戏放在左上角方便定位,然后截图
HWND hq = FindWindow(NULL, L"QQ游戏 - 连连看角色版");
RECT rect;
GetWindowRect(hq, &rect);
int w = rect.right - rect.left;
int h = rect.bottom - rect.top;
MoveWindow(hq, 0, 0, w, h, false);
Sleep(2000);
return 0;
}
导入工具库tools.h 和 tools.cpp项目目录下:
使用工具库 中的getScreen()函数,来实现截屏功能。
Mat src = getScreen();
// 测试截图是否正确
namedWindow("Test", CV_WINDOW_AUTOSIZE);//创建窗口
imshow("Test", src);
waitKey(0); //显示图片窗口,直到有按键按下
测试成功后,把以上三行测试代码删除。
定义全局变量 int flagMap[11][19],把游戏区域的各个图片“数字化”。
int flagMap[11][19] = { 0, };
自定义函数,实现图像数字化
//图片左上角坐标
#define left_x 13
#define left_y 180
//每个小方块长宽
#define block_x 31
#define block_y 35
void picture_process(Mat src)
{
Mat vec[11][19];
memset(flagMap, 0, sizeof(flagMap));
int x_pos = left_x;
int y_pos = left_y;
// 切割各个小方块图片
for (int i = 0; i < 11; i++) {
for (int j = 0; j < 19; j++) {
Mat pic = src(Rect(x_pos, y_pos, block_x, block_y));
vec[i][j] = pic(Rect(5, 5, block_x - 7, block_y - 7));
// 测试截取后的小图片是否正确
//char name[32];
//sprintf_s(name, sizeof(name), "%d-%d.png", i, j);
//imwrite(name, vec[i][j]);
x_pos += block_x;
}
x_pos = left_x;
y_pos += block_y;
}
// 把图片数组转换为数字数组,相同的图片对应为一个最早出现这个图片的数组下标(下标加1)
for (int i = 0; i < 11; i++) {
for (int j = 0; j < 19; j++) {
if (flagMap[i][j] != 0) continue;
for (int m = 0; m < 11; m++) {
for (int n = 0; n < 19; n++) {
if (i == m && j == n) continue;
if (flagMap[m][n] == 0 && imgSame(vec[i][j], vec[m][n])){
flagMap[i][j] = i*19+j+1;
flagMap[m][n] = i*19+j+1;
}
}
}
}
}
// 去除空白方块
Mat blankImg = imread("empty.png");
for (int i = 0; i < 11; i++) {
for (int j = 0; j < 19; j++) {
if (imgSame(vec[i][j], blankImg)) {
int val = flagMap[i][j];
for (int m = 0; m < 11; m++) {
for (int n = 0; n < 19; n++) {
if (flagMap[m][n] == val) {
flagMap[m][n] = 0;
}
}
}
return;
}
}
}
}
打印数字化结果,用作调试用
void printMap() {
for (int i = 0; i < 11; i++) {
for (int j = 0; j < 19; j++) {
if (flagMap[i][j] == 0)
printf(" ");
else
printf("%4d", flagMap[i][j]);
}
printf("\n");
}
printf("\n\n\n");
}
调用刚定义的函数,对游戏截图进行处理
Mat src = getScreen();
picture_process(src);
printMap();
分析连连看的消除规则
使用工具库中的接口,提高开发效率:
自定义函数,判断两点是否可以连接
// 判断是否能够连通
bool checkConnect(int row1, int col1, int row2, int col2) {
if (flagMap[row1][col1] == 0 || flagMap[row2][col2] == 0 || // 1. 起点和终点都不能是空白点
row1 == row2 && col1 == col2 || // 2. 起点和终点不能是同一个点
flagMap[row1][col1] != flagMap[row2][col2]) { // 3. 起点和终点必须是相同的图块
return false;
}
if (shuiPingConnect((int*)flagMap, 19, row1, col1, row2, col2) || // Redmi
chuiZhiConnect((int*)flagMap, 19, row1, col1, row2, col2) ||
oneTurnConnect((int*)flagMap, 19, row1, col1, row2, col2) ||
twoTurnConnect((int*)flagMap, 11, 19, row1, col1, row2, col2)) {
return true;
}
return false;
}
定义自动点击的时间间隔(速度)
#define DELAY_TIME 2
int match()
{
int ret = 0; //统计这次遍历消除的对数
for (int i = 0; i < 11; i++) {
for (int j = 0; j < 19; j++) {
if (flagMap[i][j] == 0) continue;
for (int m = 0; m < 11; m++) { //for (int m = i; m < 11; m++)
for (int n = 0; n < 19; n++) {
if (flagMap[m][n] == 0) continue;
if (m == i && n == j) continue;
if (flagMap[i][j] == flagMap[m][n]) {
if (checkConnect(i, j, m, n)) {
printf("消除:[%d][%d] - [%d][%d]\n", i, j, m, n);
printMap();
//system("pause");
ret++;
//鼠标操作 移动光标->暂停->单击左键->暂停->左键抬起->暂停
SetCursorPos((left_x + j * block_x) + 10,
(left_y + i * block_y) + 10);
Sleep(DELAY_TIME + rand() % DELAY_TIME);
mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
Sleep(DELAY_TIME + rand() % DELAY_TIME);
mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
Sleep(DELAY_TIME + rand() % DELAY_TIME);
SetCursorPos((left_x + n * block_x) + 10,
(left_y + m * block_y) + 10);
Sleep(DELAY_TIME + rand() % DELAY_TIME);
mouse_event(MOUSEEVENTF_LEFTDOWN, 0, 0, 0, 0);
Sleep(DELAY_TIME + rand() % DELAY_TIME);
mouse_event(MOUSEEVENTF_LEFTUP, 0, 0, 0, 0);
Sleep(DELAY_TIME + rand() % DELAY_TIME);
//更新数据
flagMap[i][j] = 0;
flagMap[m][n] = 0;
}
}
}
}
}
}
return ret;
}
判断是否已经消除完毕
bool allKilled() { // 方块是否已经全部消除
for (int i = 0; i < 11; i++) {
for (int j = 0; j < 19; j++) {
if (flagMap[i][j])
return false;
}
}
return true;
}
自动开玩
int main(void) {
......
while (1) {
int killCount = match();
if (allKilled()) {
break;
}
}
}
某些情况可能又死局,此时就可以使用道具。
int chongPai = 2;
while (1) {
int killCount = match();
if (allKilled()) {
break;
}
if (killCount == 0 && chongPai > 0) {
SetCursorPos(653, 199); //移动到变形道具位置
mouse_event(MOUSEEVENTF_LEFTDOWN | MOUSEEVENTF_LEFTUP, 0, 0, 0, 0); //使用道具
Sleep(3000);
src = getScreen();
picture_process(src);
chongPai--;
}
}
C++和Python的纠结?
Python也能做图像处理(底层使用C++)
那到底该如何选择?
C/C++ & 算法 & 框架 & 产品级项目 => 大厂
C++为什么被黑?
因为很多人学不会,因为开发难度相对较大
90%的C/C++的自学者,死在指针上!
C++的缺点:
开发效率没有Java, Python高
很多都需要自己设计组件
C++的优点:
今天的分享就到这里了,大家要好好学C语言/C++哟~
写在最后:对于准备学习C/C++编程的小伙伴,如果你想更好的提升你的编程核心能力(内功)不妨从现在开始!
C语言C++编程学习交流圈子,QQ群:763855696【点击进入】
C语言从入门到精通(C语言入门C语言教程C语言零基础C语言基础C语言学习C
整理分享(多年学习的源码、项目实战视频、项目笔记,基础入门教程)
欢迎转行和学习编程的伙伴,利用更多的资料学习成长比自己琢磨更快哦!
编程学习视频分享: