去年火了一阵子的微信小游戏"跳一跳"相信大家都玩过,要说操作也着实简单,依靠手指按压屏幕让棋子在各种方格间跳跃,所谓老少皆宜的游戏也不外乎这种,没有复杂的操作,而望着大家乐此不疲的一遍遍地刷记录的时候,那是真累啊!所以我第一个想法就是如何自动的让棋子跳呢?
有了上面的想法,说干就干,让棋子自动跳那就是模拟屏幕按压就行了,有了这个思路结合前段时间写完的"pyapp"自动化测试框架,知道可以利用adb命令swipe来实现屏幕按压(大家可以参考我之前写的文章《python自动化测试应用-第10篇(APP测试)之adb命令》),只要掌握好按压的时间就能模拟不同的按压力度,那么接下来这个按压时间该如何确定呢?自然我们是根据两个矩形物体间的距离了,隔得远我们就需要按压时间长,反之离得近,时间就短。所以之后的重点就是如何计算出这个距离呢?我们先看一下下面这张图。
准确的说我们是要得到这两个红点之间的距离,上面这张截图就是我通过程序画出的。那么这两个红点所在位置是如何找出的呢?由于之前研究过一段时间的车牌识别,知道利用opencv可以分析图片,比如将彩色图片转化成灰度图,转化成灰度图后便于我们去识别图片中各种形状,这之间用到的功能函数还有cv2.threshold(二值化),cv2.morphologyEx(图像的开,闭运算)最终我们可以将上图转化为这样。
通过以上的一些逻辑运算,得到的这张图可以清楚的将我们的棋子显示出来,接下来就可以自然的计算出棋子的坐标了。同样的方式我们看下图。
从这张图我们可以看到棋子和左边下一步要跳的矩形格子的边缘,正是利用这种关系我们就可以找到白色边缘,进一步分析出矩形格子的位置。这里着重说明一下下一步所跳矩形格子坐标位置我是如何分析的,同样我们还是按照轮询图片每一处坐标点的颜色,当然我们起始坐标不用从[0,0]开始,也就是可以屏蔽掉分数所在向上的位置,那么这样我们遇到的第一个坐标颜色是白色也就是为0的坐标点必然是在这个矩形范围内,那么找到这个点还没有完,因为我们要尽可能的找到矩形的中心点,因为目前我们只是找到了矩形边缘。向开篇第一张图的红点位置是如何确定到的呢?
这里我分享一下我的方法:既然我们找到了边缘点,之后我们从边缘点向上下左右四个方向继续分别获取颜色值(当然这里我们就要在原图获取颜色了),当某个方向遇到背景色时停止,这样我们就可以分析出我们这个边缘点是在矩形格子的哪个方位(是左边,还是下边,上边或右边),以这张图的情况举例,边缘点是在左边,那么自然我们就要让边缘点向右侧移动,这个偏移量自然就是我们向右找到背景色停止的那个位置的一半,因为我们是要定位中心点。这里再说明一点为什么要确定边缘点是在矩形格子的方位呢?因为跳一跳的格子它的颜色变化很多,且颜色不固定,所以我们通过cv2的函数运算得到图3,矩形格子的边缘不一定是完全的边缘,所以我们要分析边缘与矩形实际的位置关系再确定中心点。
好了,知道了两个坐标点,棋子的和矩形格子的,那么他们之间的距离就可以得到了。这个距离大家就可以理解成按压力度,因为他们是正比关系。比如我们得到的像素距离是600,那么我们的swipe命令最后的参数时间就是乘以2即1200毫秒。
最后我将代码贴出来。
---------------------------------------------------------------注:我这有个学习基地,里面有很多学习资料,感兴趣的+Q群:895817687---------------------------------------------------------------# -*-encoding:utf-8 -*-from __future__ import divisionimport cv2import timeimport subprocessimport hashlibimport os,shutilimport numpy as npfrom PIL import Imageimport pytesseractimport mathfrom wg_main import *loop_count=0while 1:try:loop_count+=1shot()time.sleep(1)img=cv2.imread("d:\\cp\\screenshot.png")img=cv2.resize(img,(720,1280))hsvimg=hsv(img)_colorImage=img_colorImage1=img.copy()(w1,h1,_)=img.shapedis1=ch1(img,w1,h1)dis2=ch11(img,w1,h1,dis1[0])if dis2:if abs(dis1[0]-dis2[0])>100:(color1,_,_)=hsvimg[dis1[1],dis1[0]](color2,_,_)=hsvimg[dis2[1],dis2[0]]if 110<color2<120 and (color1>125 or color1<110):dis1=dis2(color1,_,_)=hsvimg[dis1[1],dis1[0]]if color1>125 or color1<110:dis3=ch111(img,w1,h1)dis1=dis3img=gry(img)#灰度转化img=sb(img)#Sobel算子img=th2(img)#threshold算法img=mo(img)#开闭运算pi,pj=mid_position(img,_colorImage,w1,h1,dis1)middle_pos=last_mid_pos(_colorImage1,pi,pj,h1)cv2.rectangle(_colorImage,(middle_pos[0],middle_pos[1]),(middle_pos[0],middle_pos[1]),(0,0,255),4)cv2.rectangle(_colorImage,(dis1[0],dis1[1]),(dis1[0],dis1[1]),(0,0,255),4)dis=int(math.sqrt(abs(dis1[0]-middle_pos[0])**2+abs(dis1[1]-middle_pos[1])**2))dis=diss(dis)if dis<100:dis=250jump(dis)time.sleep(2)os.remove("d:\\cp\\screenshot.png")except Exception,e:print e
最后,说明一点谨此篇文章请大家以自动化测试的角度去看待,游戏玩多了伤身,用外挂玩则是伤别人的身。