原理说明- 将手机点击到《跳一跳》小程序界面;
- 用 ADB 工具获取当前手机截图,并用 ADB 将截图 pull 上来
adb shell screencap -p /sdcard/autojump.png adb pull /sdcard/autojump.png .
- 手动版:用 Matplotlib 显示截图,用鼠标点击起始点和目标位置,计算像素距离;
- 自动版:靠棋子的颜色来识别棋子,靠底色和方块的色差来识别棋盘;
adb shell input swipe x y x y time(ms)
安卓手机操作步骤- 安卓手机打开 USB 调试,设置》开发者选项》USB 调试
- 电脑与手机 USB 线连接,确保执行adb devices可以找到设备 ID
- 界面转至微信跳一跳游戏,点击开始游戏
- 运行python wechat_jump_auto.py,如果手机界面显示 USB 授权,请点击确认
- 请按照你的手机分辨率从./config/文件夹找到相应的配置,拷贝到 *.py 同级目录./config.json(如果屏幕分辨率能成功探测,会直接调用 config 目录的配置,不需要复制)
iOS 手机操作步骤- 运行安装好的 WebDriverAgentRunner
- 将手机点击到《跳一跳》小程序界面
- 运行脚本。有两种模式可供选择:手动辅助跳 和 自动连续跳
- 手动辅助跳
- 命令行运行python3 wechat_jump_iOS_py3.py
- 依次点击弹出的窗口中的起始位置和目标位置,会自动计算距离后起跳
- 根据起跳的精准情况更改python3 wechat_jump_iOS_py3.py中的time_coefficient参数,直到获得佳取值
- 自动连续跳
- 拷贝./config/iPhone目录下对应的设备配置文件,重命名并替换到./config.json
- 命令行运行python3 wechat_jump_auto_iOS.py
- 会自动计算坐标并连续起跳,根据起跳的精准情况更改./config.json 中的press_coefficient参数,直到获得佳取值
下面我们来看下这款辅助的制作原理及代码分析:
部分代码如下:
def pull_screenshot(): os.system('del autojump.png') os.system('adb shell screencap -p /sdcard/autojump.png') os.system('adb pull /sdcard/autojump.png .')
2. 查找棋子的坐标
# 以50px步长,尝试探测scan_start_yfor i in range(under_game_score_y, h, 50):last_pixel = im_pixel[0, i]for j in range(1, w):pixel = im_pixel[j, i]# 不是纯色的线,则记录scan_start_y的值,准备跳出循环if pixel[0] != last_pixel[0] or pixel[1] != last_pixel[1] or pixel[2] != last_pixel[2]:scan_start_y = i - 50break if scan_start_y:breakprint("scan_start_y: ", scan_start_y)# 从scan_start_y开始往下扫描,棋子应位于屏幕上半部分,这里暂定不超过2/3for i in range(scan_start_y, int(h * 2 / 3)):for j in range(scan_x_border, w - scan_x_border): # 横坐标方面也减少了一部分扫描开销pixel = im_pixel[j, i]# 根据棋子的低行的颜色判断,找后一行那些点的平均值,这个颜色这样应该 OK,暂时不提出来if (50 < pixel[0] < 60) and (53 < pixel[1] < 63) and (95 < pixel[2] < 110):piece_x_sum += jpiece_x_c += 1piece_y_max = max(i, piece_y_max)if not all((piece_x_sum, piece_x_c)):return 0, 0, 0, 0piece_x = piece_x_sum / piece_x_cpiece_y = piece_y_max - piece_base_height_1_2 # 上移棋子底盘高度的一半3. 查找下一跳地盘的坐标 for i in range (int (h / 3), int (h * 2 / 3)):last_pixel = im_pixel[0, i]if board_x or board_y:breakboard_x_sum = 0board_x_c = 0for j in range(w):pixel = im_pixel[j, i]# 修掉脑袋比下一个小格子还高的情况的 bugif abs(j - piece_x) < piece_body_width:continue# 修掉圆的时候一条线导致的小 bug,这个颜色判断应该 OK,暂时不提出来if abs(pixel[0] - last_pixel[0]) + abs(pixel[1] - last_pixel[1]) + abs(pixel[2] - last_pixel[2]) > 10:board_x_sum += jboard_x_c += 1if board_x_sum:board_x = board_x_sum / board_x_c# 按实际的角度来算,找到接近下一个 board 中心的坐标 这里的角度应该是30°,值应该是tan 30°, math.sqrt(3) / 3board_y = piece_y - abs(board_x - piece_x) * math.sqrt(3) / 3if not all((board_x, board_y)):return 0, 0, 0, 04. 利用勾股定理计算两点之间的距离
math.sqrt((board_x - piece_x) ** 2 + (board_y - piece_y) ** 2)
5. 根据长度计算出按压时间
def jump(distance):press_time = distance * 1.35press_time = int(press_time)cmd = 'adb shell input swipe 320 410 320 410 ' + str(press_time)print(cmd)os.system(cmd)
|