100行python代码实现跳一跳辅助程序


Posted in Python onJanuary 15, 2018

写在前面

分享一下今天下午用python写的“跳一跳”小游戏的辅助程序。之前是准备用树莓派操控一个“机械手指”来代替人的触摸操作,但该方案还在酝酿中,实现了再分享。接下来要分享的是用“纯软件”的方法来玩“跳一跳”。

原理

原理其实很简单,按如下步骤操作即可:

  1. 每次跳跃之前,截取一下手机屏幕,并将截图保存到本地电脑中;
  2. 计算截图中人偶的位置与将要跳至的台面中心的距离dd;
  3. 将以上距离dd换算成相应的触摸时间ss;
  4. 发送模拟触摸的命令至手机,触摸时间为以上时间ss;

实现

本人只做过Android开发,因此下面只给出Android平台下的实现方法。

步骤1

可以用Android官方提供的adb工具来完成。首先需要搜索并下载对应操作系统下adb工具。其次需要将手机连接电脑, 并将手机的 设置 > 开发人员选项 > USB调试打开。现在在命令行调用一下adb工具,看是否检查到手机:

adb devices

PS:若将adb路径添加到了PATH环境变量中,则可直接在命令行调用adb;否则以上命令需要输入adb的全路径。

若执行以上命令后,输出了设备相关信息,则说明手机连接成功,可继续以下操作。

用如下命令可截取手机屏幕图片至SD卡保存:

adb shell screencap -p /mnt/sdcard/screencap.png

然后可用如下命令pull图片到电脑:

adb pull /mnt/sdcard/screencap.png C:/screencap.png

步骤2

是整个问题的关键。要计算出人偶与将要跳至的台面中心的距离,需要分别识别出人偶的位置(坐标)和台面中心的位置(坐标)。

我们以人偶最底部的一行的中心作为人偶的位置,如下图所示:

100行python代码实现跳一跳辅助程序

至于怎么识别出人偶的最底部,可以这样来操作。通过观察可发现,人偶底部的颜色的rgb值在(53, 57, 95)到(59, 61, 103)之间,因此我们逐行扫描各个像素点,找到rbg值在该区间的各行,最后一行即为人偶的底部了。得到了最底部的一行,自然就能算出该行的中心坐标。

接下来需要识别人偶将要跳至的平台的中心。要想得到该中心的坐标,我们只需要识别得到下图中的两个顶点vertex1和vertex2的坐标即可:

100行python代码实现跳一跳辅助程序

我们同样用从左往右,从上往下的顺序扫描各个像素点的方法来找出vertex1的坐标。扫描之前先获取整个背景的颜色的rgb值,取任意“空白”处即可(例如本人手机截图大小为1920x1080,可断定坐标为(40, 500)的点一定处于“空白”处。)。在扫描过程中一旦发现某处的颜色与背景色不一致,发生了“突变”,可断定该点即为vertex1。

我们把vertex1点的rgb值记录下来作为台面的背景色。在接下去的扫描过程中,我们开始关心当前扫描的点的rgb值是否和该记录值“相似”。“相似”则说明该点“属于”台面,而通过上图可发现,顶点vertex2是所有“属于”台面的点中,横坐标最小的点,这样vertex2的坐标也找到了。

显然,台面中心的横坐标等于vertex1的横坐标,而纵坐标等于vertex2的纵坐标。

步骤3

通过多次尝试,发现用如下公式转换距离dd(单位:px)为时间ss(单位:毫秒)比较合适:

s=d∗1.35
s=d∗1.35

步骤4

得到了触摸时间,我们还是借助adb工具来模拟触摸屏幕的行为,以下是相关命令:

adb shell input swipe 0 0 0 0 1000

以上命令的最后一个参数即为需要模拟按压屏幕的时长,单位是毫秒。

实现效果

成功连接手机至电脑(手机需开启USB调试),并进入“跳一跳”游戏,然后到电脑上运行该代码即可自动“跳一跳”。

上一张截图:

100行python代码实现跳一跳辅助程序

完整代码

以下是完整代码,在本人手机(1920 * 1080 )下测试发现大多数情况都能正中靶心,少数情况不能命中靶心,极少数情况会跳出台面以外。其他分辨率的手机可能需要适当修改BACKGROUND_POS和DISTANCE_TO_TIME_RATIO参数大小。

import math
import os
import tempfile
import time
from functools import reduce
from PIL import Image
BACKGROUND_POS = (40, 500)
DISTANCE_TO_TIME_RATIO = 1.35
SCREENSHOT_PATH = tempfile.gettempdir() + "/screenshot.png"
def calculate_jump_distance():
 im = Image.open(SCREENSHOT_PATH)
 background_rgb = im.getpixel(BACKGROUND_POS)
 role_pos_list = None
 vertex1_pos = None
 block_background_rgb = None
 vertex2_pos = None
 role_line_flag = True
 for y in range(BACKGROUND_POS[1], im.height):
  if role_pos_list and role_line_flag:
   break
  role_line_flag = True
  vertex2_line_flag = True
  for x in range(BACKGROUND_POS[0], im.width):
   current_rgb = im.getpixel((x, y))
   next_rgb = im.getpixel((x + 1, y)) if x + 1 < im.width else (0, 0, 0)
   # 识别顶点1
   if x > BACKGROUND_POS[0] and y > BACKGROUND_POS[1] and not vertex1_pos \
     and not is_similar(background_rgb, current_rgb) and is_similar(current_rgb, next_rgb):
    vertex1_pos = (x, y)
    block_background_rgb = current_rgb
   # 识别顶点2
   if block_background_rgb and vertex2_line_flag and is_similar(current_rgb, block_background_rgb, 5):
    vertex2_line_flag = False
    if vertex2_pos:
     if x < vertex2_pos[0] and vertex2_pos[0] - x < 20 and y - vertex2_pos[1] < 20:
      vertex2_pos = (x, y)
    else:
     vertex2_pos = (x, y)
   # 识别小人
   if is_part_of_role(current_rgb):
    if role_line_flag:
     role_pos_list = []
     role_line_flag = False
    role_pos_list.append((x, y))
 if len(role_pos_list) == 0:
  raise Exception('无法识别小人位置!!!')
 pos_sum = reduce((lambda o1, o2: (o1[0] + o2[0], o1[1] + o2[1])), role_pos_list)
 role_pos = (int(pos_sum[0] / len(role_pos_list)), int(pos_sum[1] / len(role_pos_list)))
 destination_pos = (vertex1_pos[0], vertex2_pos[1])
 return int(linear_distance(role_pos, destination_pos))
def is_part_of_role(rgb):
 return 53 < rgb[0] < 59 and 57 < rgb[1] < 61 and 95 < rgb[2] < 103
def linear_distance(xy1, xy2):
 return math.sqrt(pow(xy1[0] - xy2[0], 2) + pow(xy1[1] - xy2[1], 2))
def is_similar(rgb1, rgb2, degree=10):
 return abs(rgb1[0] - rgb2[0]) <= degree and abs(rgb1[1] - rgb2[1]) <= degree and abs(rgb1[2] - rgb2[2]) <= degree
def screenshot():
 os.system("adb shell screencap -p /mnt/sdcard/screencap.png")
 os.system("adb pull /mnt/sdcard/screencap.png {} >> {}/jump.out".format(SCREENSHOT_PATH, tempfile.gettempdir()))
def jump(touch_time):
 os.system("adb shell input swipe 0 0 0 0 {}".format(touch_time))
def distance2time(distance):
 return int(distance * DISTANCE_TO_TIME_RATIO)
if __name__ == '__main__':
 count = 1
 while True:
  screenshot()
  distance = calculate_jump_distance()
  touch_time = distance2time(distance)
  jump(touch_time)
  print("#{}: distance={}, time={}".format(count, distance, touch_time))
  count += 1
  time.sleep(1)

总结

以上所述是小编给大家介绍的100行python代码实现跳一跳辅助程序,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对三水点靠木网站的支持!

Python 相关文章推荐
深入讨论Python函数的参数的默认值所引发的问题的原因
Mar 30 Python
Python使用正则匹配实现抓图代码分享
Apr 02 Python
Python的Django框架中forms表单类的使用方法详解
Jun 21 Python
python 打印出所有的对象/模块的属性(实例代码)
Sep 11 Python
Python中functools模块函数解析
Mar 12 Python
Python实现计算圆周率π的值到任意位的方法示例
May 08 Python
python将一个英文语句以单词为单位逆序排放的方法
Dec 20 Python
Django 开发环境与生产环境的区分详解
Jul 26 Python
ORM Django 终端打印 SQL 语句实现解析
Aug 09 Python
Python爬虫库BeautifulSoup获取对象(标签)名,属性,内容,注释
Jan 25 Python
python 数据分析实现长宽格式的转换
May 18 Python
python基于win32api实现键盘输入
Dec 09 Python
tornado 多进程模式解析
Jan 15 #Python
200 行python 代码实现 2048 游戏
Jan 12 #Python
一篇文章快速了解Python的GIL
Jan 12 #Python
Python获取当前公网ip并自动断开宽带连接实例代码
Jan 12 #Python
python SSH模块登录,远程机执行shell命令实例解析
Jan 12 #Python
python opencv实现任意角度的透视变换实例代码
Jan 12 #Python
Python数字图像处理之霍夫线变换实现详解
Jan 12 #Python
You might like
PHP中的串行化变量和序列化对象
2006/09/05 PHP
php 记录进行累加并显示总时长为秒的结果
2011/11/04 PHP
AJAX的跨域访问-两种有效的解决方法介绍
2013/06/22 PHP
php可应用于面包屑导航的迭代寻找家谱树实现方法
2015/02/02 PHP
php示例详解Constructor Prototype Pattern 原型模式
2015/10/15 PHP
Symfony的安装和配置方法
2016/03/17 PHP
php for 循环使用的简单实例
2016/06/02 PHP
动态刷新 dorado树的js代码
2009/06/12 Javascript
ExtJS4中的requires使用方法示例介绍
2013/12/03 Javascript
JS将制定内容复制到剪切板示例代码
2014/02/11 Javascript
file控件选择上传文件确定后触发的js事件是哪个
2014/03/17 Javascript
JS基于Ajax实现的网页Loading效果代码
2015/10/27 Javascript
原生javascript实现的一个简单动画效果
2016/03/30 Javascript
微信小程序左右滑动切换页面详解及实例代码
2017/02/28 Javascript
JS实现读取xml内容并输出到div中的方法示例
2018/04/19 Javascript
vue+express 构建后台管理系统的示例代码
2018/07/19 Javascript
VUE在for循环里面根据内容值动态的加入class值的方法
2018/08/12 Javascript
35个最好用的Vue开源库(史上最全)
2019/01/03 Javascript
JavaScript中的null和undefined用法解析
2019/09/30 Javascript
vue实现编辑器键盘抬起时内容跟随光标距顶位置向上滚动效果
2020/05/28 Javascript
vue 数据遍历筛选 过滤 排序的应用操作
2020/11/17 Javascript
Python操作CouchDB数据库简单示例
2015/03/10 Python
Python中用Spark模块的使用教程
2015/04/13 Python
Python操作SQLite数据库的方法详解【导入,创建,游标,增删改查等】
2017/07/11 Python
Python3.X 线程中信号量的使用方法示例
2017/07/24 Python
在Python中增加和插入元素的示例
2018/11/01 Python
基于python调用psutil模块过程解析
2019/12/20 Python
天美时手表加拿大官网:Timex加拿大
2016/09/01 全球购物
Farfetch巴西官网:奢侈品牌时尚购物平台
2020/10/19 全球购物
介绍一下javax.servlet.Servlet接口及其主要方法
2015/11/30 面试题
人力资源经理的岗位职责
2014/03/02 职场文书
2014五一国际劳动节活动总结范文
2014/04/14 职场文书
实验心得体会
2014/09/05 职场文书
幼儿教师师德师风自我评价
2015/03/05 职场文书
Python机器学习之基础概述
2021/05/19 Python
Redis+AOP+自定义注解实现限流
2022/06/28 Redis