一、概述
“微信跳一跳”小程序出现以来,网上出现了各种各样的“外挂”,从用单片机做的“半自动外挂”到用按键精灵做的“全自动外挂”,各式各样。我觉得做所谓的外挂并不是根本目的,根本目的在于在做外挂的过程中学习各种知识并享受整个过程。寒假在家的几天尝试了一种新的思路,就是用“Cpp+EasyX库+adb命令”的方式实现相关功能。在整个过程中,我在论坛查阅了不少前辈的博文,给予了我很大的启发,因此在这里表示感谢。但是在截图的像素处理、像素的定位方式等方面,我也有些自己的见解与大家分享。
二、所需工具
VS2012编译器、EasyX库(安装到VS2012),adb命令工具(安装至电脑)、手机、数据线
三、基本流程
实现功能的基本思路如下:
四、详细流程
(一)安装所需工具
1.下载并安装adb工具(可自行百度,很简单)
2.在VS2012安装EasyX库(可自行百度,很简单)
(二)测试手机与PC的连接
1.将手机与PC端通过数据线连接,并打开USB调试
2.通过cmd发送adb指令检查连接情况,如果成功连接,会返回一串设备号
adb命令为“adb devices”,效果如下
(三)功能代码
1.头文件、子函数与变量
#include<stdafx.h>
#include<atlimage.h>
#include<graphics.h>
#include<math.h>
#include <conio.h>
/***********************子函数区**************************************/
int ColorFun(COLORREF color1, COLORREF color2, unsigned int diff);//diff为差异值
/***********************全局变量区*************************************/
int xy[800][700];//用来存储切割后截图的像素点
float r1,g1,b1,r2,g2,b2;//用来储存像素点的RGB值
/***********************局部变量区*****************************************/
int i,j;//用于取色中的循环,i代表行,j代表列
float hi,hj,ri,rj;//分别记录盒子顶部坐标与人底部坐标
int x;
double d;
int t;//储存时间
char str[50];//储存模拟触摸命令
2.adb命令进行手机连接、发送截图与传送命令
system("adb devices");//连接移动设备
Sleep(1000);//等待连接
CImage cimage;//进行格式转换
IMAGE image,img;//指向原始截图与切割后的截图
system("adb shell /system/bin/screencap -p /sdcard/screenshot.png");//截屏并命名为screenshot.png
system("adb pull /sdcard/screenshot.png e:/screenshot.png");//把截图screenshot.png发送到e
3.通过CImage类进行截图的图片格式转换
因为截图默认格式为png格式,而EasyX库文件中进行图片操作的函数不支持该格式,因此通过CImage类将截图转化为jpg格式:
cimage.Load("E://screenshot.png");//加载e盘中的截图screenshot.png
cimage.Save("E://screenshot.jpg");//把截screenshot.png转换为screenshot.jpg
4.对图片进行切割并显示:
经过不断尝试,将图片切割为800×700即可:
initgraph(800,700);
loadimage(&image,"E:\\screenshot.jpg",0, 0);//加载转换好的screenshot.jpg
SetWorkingImage(&image); // 把原始截图设定为绘图设备,以便切割
getimage(&img, 150, 600, 800, 700); // 从(150,600)开始切割图片,宽800,高700.并把切割后的图片保存到img
SetWorkingImage(NULL); // 恢复默认工作区(即原始窗口)
putimage(0,0,&img);
5.像素对比子函数
“人”与“新盒子”的位置是通过对比像素的RGB来得到的,我采取对图片像素进行扫描,并对像素的RGB进行对比从而得到人与新盒子的位置。因此,我需要一个能对比像素区别度的子函数:
int ColorFun(COLORREF color1, COLORREF color2, unsigned int diff)
{
//三种基色的颜色差的平方根的值则代表两种颜色的相似度,值越小则越相似
r1 = GetRValue(color1);
g1 = GetGValue(color1);
b1 = GetBValue(color1);
r2 = GetRValue(color2);
g2 = GetGValue(color2);
b2 = GetBValue(color2);
if (sqrt(((r2-r1)*(r2-r1)+(g2-g1)*(g2-g1)+(b2-b1)*(b2-b1)))>diff)
{
return 1;
}
return 0;
}
该子函数能够取出像素点color1与像素点color2的RGB值并进行对比,如果区别度大于diff则认为是两个像素是差别较大的颜色并返回1,反之则返回0。
6.确定新盒子与人的位置
对于“人”:因为人的颜色是不变的,我可以得到其RGB值为(55,60,100)。因此对于人的识别,我们只需要“从下往上、从左往右”对像素进行扫描,并对比当前像素RGB与(55,60,100)的区别度,当区别度小于5.0时即认为扫描到了人的“底”,记录下“人底”的位置。
对于新盒子:因为盒子的颜色是不断变化的,但因为新盒子的颜色与背景色差异较大,因此对于新盒子的识别,我采取“从上往下、从左往右”的方式进行扫描并对比当前像素与前一个像素的RGB值的区别度,当区别度大于50.0时,即认为扫描到了新盒子顶部,记录此时的位置。
/***************************取色对比确定盒顶与人底坐标********************************/
SetWorkingImage(&img);//把切割后的截图设定为绘图设备,以便取色对比
for(j=0;j<700;j++)//取色
{
for(i=0;i<800;i++)
{
xy[i][j] = getpixel(i,j);
}
}
SetWorkingImage(NULL);
for(j=5;j<700;j++)//从上到下横向扫描对比色差,确定盒顶坐标(i变j不变)
{
for(i=5;i<800;i++)
{
x=i-1;
if(ColorFun(xy[i][j],xy[x][j],50.0)==1)//如果色差大于50.0
{
hi=i;//记录坐标
hj=j;
i=800;
j=700;//跳出循环
}
}
}
/*****************************从下到上寻找人的底部坐标********************************************/
for(j=698;j>=0;j--)//对比色差,确定坐标
{
for(i=0;i<800;i++)
{
if(ColorFun(xy[i][j], RGB(55,60,100),5)==0)//色差不大于5
{
ri=i;//记录坐标
rj=j;
i=800;
j=-1;//跳出循环
}
}
}
7.根据两者位置计算距离并乘比例系数得到触屏时间
hi+=10;//根据盒定位置计算出盒子中心的大概位置
hj+=110;
d=sqrt((hi-ri)*(hi-ri)+(hj-rj)*(hj-rj));
d=d*1.35;//距离乘比例系数
t=d;
if(d-t>=0.5)//,因为时间只能为整数,因此对计算到的时间值进行四舍五入
{
t=t+1;
}
else
{
t=t-1;
}
8.通过adb指令向手机发送模拟触屏命令
sprintf_s(str,"adb shell input swipe 800 800 800 100 %d",t);
system(str);
closegraph();
printf("盒顶坐标:%f %f\n人底坐标:%f %f\n模拟触摸时间:%d\n\n",hi-10,hj-110,ri,rj,t);
Sleep(2000);
至此,整个功能已经实现。后期,我们只需将相关步骤放入循环体,即可实现跳一跳的连续自动运行。
五、完整源代码
#include<stdafx.h>
#include<atlimage.h>
#include<graphics.h>
#include<math.h>
#include <conio.h>
/***********************子函数区**************************************/
int ColorFun(COLORREF color1, COLORREF color2, unsigned int diff);//diff为差异值
/***********************全局变量区*************************************/
int xy[800][700];//用来存储切割后截图的像素点
float r1,g1,b1,r2,g2,b2;//用来储存像素点的RGB值
void main()
{
/***********************局部变量区*****************************************/
int i,j;//用于取色中的循环,i代表行,j代表列
float hi,hj,ri,rj;//分别记录盒子顶部坐标与人底部坐标
int x;
double d;
int t;//储存时间
char str[50];//储存模拟触摸命令
/*****************通过adb命令获取截图,传至PC端并转化为jpg格式***********/
system("adb devices");//连接移动设备
Sleep(1000);
while(1)
{
CImage cimage;//进行格式转换
IMAGE image,img;//指向原始截图与切割后的截图
system("adb shell /system/bin/screencap -p /sdcard/screenshot.png");//截屏并命名为screenshot.png
system("adb pull /sdcard/screenshot.png e:/screenshot.png");//把截图screenshot.png发送到e
cimage.Load("E://screenshot.png");//加载e盘中的截图screenshot.png
cimage.Save("E://screenshot.jpg");//把截screenshot.png转换为screenshot.jpg
/**************************切割截图并保存*******************************************/
initgraph(800,700);
loadimage(&image,"E:\\screenshot.jpg",0, 0);//加载转换好的screenshot.jpg
SetWorkingImage(&image); // 把原始截图设定为绘图设备,以便切割
getimage(&img, 150, 600, 800, 700); // 从(150,600)开始切割图片,宽800,高700.并把切割后的图片保存到img
SetWorkingImage(NULL); // 恢复默认工作区(即原始窗口)
putimage(0,0,&img);///
/***************************取色对比确定盒顶与人底坐标********************************/
SetWorkingImage(&img);//把切割后的截图设定为绘图设备,以便取色对比
for(j=0;j<700;j++)//取色
{
for(i=0;i<800;i++)
{
xy[i][j] = getpixel(i,j);
}
}
SetWorkingImage(NULL);
for(j=5;j<700;j++)//从上到下横向扫描对比色差,确定盒顶坐标(i变j不变)
{
for(i=5;i<800;i++)
{
x=i-1;
if(ColorFun(xy[i][j],xy[x][j],50.0)==1)//如果色差大于20
{
hi=i;//记录坐标
hj=j;
i=800;
j=700;//跳出循环
}
}
}
/*****************************从下到上寻找人的底部坐标********************************************/
for(j=698;j>=0;j--)//对比色差,确定坐标
{
for(i=0;i<800;i++)
{
if(ColorFun(xy[i][j], RGB(55,60,100),5)==0)//色差不大于5
{
ri=i;//记录坐标
rj=j;
i=800;
j=-1;//跳出循环
}
}
}
/********************根据坐标计算距离,并根据距离计算时间********************/
hi+=10;
hj+=110;
d=sqrt((hi-ri)*(hi-ri)+(hj-rj)*(hj-rj));
d=d*1.35;//距离乘比例系数
t=d;
if(d-t>=0.5)
{
t=t+1;
}
else
{
t=t-1;
}
/*****************************发送模拟触摸命令**************************************/
sprintf_s(str,"adb shell input swipe 800 800 800 100 %d",t);
system(str);
closegraph();
printf("盒顶坐标:%f %f\n人底坐标:%f %f\n模拟触摸时间:%d\n\n",hi-10,hj-110,ri,rj,t);
Sleep(2000);
}
}
/*************************判断颜色差异*******************************************/
int ColorFun(COLORREF color1, COLORREF color2, unsigned int diff)
{
//三种基色的颜色差的平方根的值则代表两种颜色的相似度,值越小则越相似
r1 = GetRValue(color1);
g1 = GetGValue(color1);
b1 = GetBValue(color1);
r2 = GetRValue(color2);
g2 = GetGValue(color2);
b2 = GetBValue(color2);
if (sqrt(((r2-r1)*(r2-r1)+(g2-g1)*(g2-g1)+(b2-b1)*(b2-b1)))>diff)
{
return 1;
}
return 0;
}
注:实测视频还要传输到一些视频平台才能添加到本文,比较麻烦。有想看的可以留下邮箱或者私聊我,我可以发给大家
左肩理想右肩担当,君子不怨永远不会停下脚步!