使用python编写微信跳一跳的自动脚本
实现思路:
- 调用adb命令,截图
- 寻找小小人的底部中心点role(从下到上扫描,直到找到小小人相同像素的点,至于小小人像素点rgb是什么,可以使用photoshop查看)
- 寻找棋盘最高点top,然后寻找棋盘最右点。根据最高点与最右点,确定棋盘中心点border
- 计算role与border之间的直线距离,然后设置按压时间=距离*按压系数
- 调用adb 命令,按压屏幕
完整代码,测试机Oppo r11
#!/usr/bin/env python # -*- coding: utf-8 -*- from PIL import Image, ImageDraw import math import os import time import subprocess # 小小人底部RGB role_bottom_rgb = (58, 58, 102) # 小小人头部RGB role_top_rgb = (65, 65, 90) # 白色中心点 RGB white_point = (245, 245, 245) # 按压系数 press_coefficient = 1.35 def get_screenshot(): """ 获取截图信息 :return: """ process = subprocess.Popen('adb shell screencap -p', shell=True, stdout=subprocess.PIPE) binary_screenshot = process.stdout.read() binary_screenshot = binary_screenshot.replace(b'\r\r\n', b'\n') with open('autojump.png', 'wb') as f: f.write(binary_screenshot) time.sleep(1) img = Image.open('autojump.png') return img def is_similar(rgb1, rgb2, degree=20): """ 判断颜色是否相近 :param rgb1: :param rgb2: :param degree: :return: """ return abs(rgb1[0] - rgb2[0]) <= degree and abs( rgb1[1] - rgb2[1]) <= degree and abs(rgb1[2] - rgb2[2]) <= degree def calculate_jump_distance(img): """ 计算跳一跳的距离 :param image: :return: """ draw = ImageDraw.Draw(img) im_pixel = img.load() w, h = img.size # 设置有效扫描区域 min_x = 100 max_x = w - 10 min_y = 400 max_y = h - 100 # step1:寻找小小人底座位置 role_start_x = 0 role_end_x = 0 role_y = 0 find_role = False # y轴从下往上扫描 for y in range(max_y, min_y, -1): # 找到小小人最低部一行,退出y轴循环 if find_role: break # y轴未找到最低一行,则继续遍历x轴元素点 # x轴从左到右扫描 for x in range(min_x, max_x): current_rgb = im_pixel[x, y] # 当前像素RGB值 # 寻找到小人底座首位像素点 if is_similar(current_rgb, role_bottom_rgb, 5): if not find_role: # 找到首位像素点 find_role = True role_start_x = x role_y = y # 小人底座中心点的y轴坐标已确定 # 小人底座最右侧像素点定位,条件:首位像素点已找到,在当前y轴上继续遍历x轴,当当前像素不在小小人中时,前一个像素点为底座最右点 if find_role and not is_similar(current_rgb, role_bottom_rgb, 5): role_end_x = x - 1 break # 小小人底座中心点 role_x = (role_start_x + role_end_x) / 2 role = (role_x, role_y) draw.point([role], fill=(255, 0, 0)) # step2:寻找棋盘顶点:从上往下,从左到右扫描,寻找首位与初始点不一样的像素 # 解决小小人头部出现在最顶部时的BUG,在x轴扫描时,跳过小小人位置[role_start_x,role_end_x] top_x = 0 top_y = 0 top_rgb = None role_top_flag = False for y in range(min_y, max_y): for x in range(min_x, max_x): current_rgb = im_pixel[x, y] # 首先出现小小人的头部 if not role_top_flag: if is_similar(current_rgb, role_top_rgb, 40): print("首先出现小小人头部!") role_top_flag = True continue # 当小小人头部在最顶部时,从上到下扫描时,当x处于小小人位置中时,跳过本次循环 if (role_start_x - 50 <= x <= role_end_x + 50) and role_top_flag: # 当x轴坐标在小小人位置时 continue # 顶部既不是小小人,又与初始像素点不一样,则定位为棋盘顶部,退出x轴扫描 if not is_similar(current_rgb, im_pixel[min_x, min_y], 20): # 与背景像素点不一样 top_x = x # 解决棋盘边上出现一条乱七八糟颜色点将棋盘围起来时的BUG,找到第一个差异点后y轴继续往下5个像素点作为顶点 top_y = y + 4 top_rgb = im_pixel[top_x, top_y] break if top_rgb: # 找到与初始点不一样的像素点,退出y轴循环 break top = (top_x, top_y) draw.point([top], fill=(255, 0, 0)) # step3:寻找棋盘最右侧点,条件:从top_x 向右,top_y 向下扫描,当与棋盘顶部像素点相似,x轴最大时,所在点为最右点 right_x = top_x right_y = top_y find_border = False check_rgb = top_rgb for x in range(top_x, max_x): for y in range(top_y, max_y): current_rgb = im_pixel[x, y] # 找到相邻的相似元素点,定位条件:30个像素内,颜色相似 if is_similar(current_rgb, check_rgb, 20) and abs( x - right_x) <= 5 and abs(y - right_y) <= 5: check_rgb = current_rgb find_border = True right_x = x right_y = y break else: # 如果当前y轴扫描完毕都没有遇到棋盘相似点(即没有遇到break),说明已经超出了最右侧棋盘点,退出x轴循环 if find_border: break right = (right_x, right_y) draw.point([right], fill=(255, 0, 0)) # step4:定位棋盘中心:扫描棋盘,判断是否存在中心白点,否则初略可认为棋盘中心点位置是顶点和右侧点交叉位置 border = (top_x, right_y) # 先排除初略中心点位置与白色中心点相似的情况,否则遇到白色版面会定位错误 if not is_similar(im_pixel[top_x, right_y], white_point, 4): find_white_point = False for y in range(top_y + 5, right_y + 5): for x in range(top_x * 2 - right_x + 5, right_x - 5): if is_similar(im_pixel[x, y], white_point, 2): # 寻找到白色中心点 find_white_point = True border = (x, y + 10) print("寻找到白色中心点!") break # 寻找到白色中心点,退出y轴循环 if find_white_point: break draw.point([border], fill=(255, 0, 0)) # draw.line([top, right], fill=(255, 0, 0), width=10) draw.line([role, top, right, border], fill=(255, 0, 0), width=10) # img.show() img.save("debug.png") return math.sqrt((role[0] - border[0]) ** 2 + (role[1] - border[1]) ** 2) def jump(distance): press_time = distance * press_coefficient press_time = max(press_time, 200) # 设置 200ms 是最小的按压时间 press_time = int(press_time) cmd = 'adb shell input swipe 400 400 400 400 {duration}'.format( duration=press_time) print(cmd) os.system(cmd) return press_time if __name__ == '__main__': i = 1 # img = get_screenshot() # img=Image.open('autojump.png') # distance = calculate_jump_distance(img) # img.close() # jump(distance) while True: img = get_screenshot() distance = calculate_jump_distance(img) jump(distance) img.close() i += 1 if i == 10: time.sleep(2) time.sleep(2) print("*" * 100)