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使用Flask框架获取用户IP地址的方法
Mar 21 Python
Python实现的飞速中文网小说下载脚本
Apr 23 Python
python 创建弹出式菜单的实现代码
Jul 11 Python
Flask数据库迁移简单介绍
Oct 24 Python
Python查找第n个子串的技巧分享
Jun 27 Python
python中的for循环
Sep 28 Python
Django logging配置及使用详解
Jul 23 Python
解决pandas展示数据输出时列名不能对齐的问题
Nov 18 Python
Python中filter与lambda的结合使用详解
Dec 24 Python
pytorch三层全连接层实现手写字母识别方式
Jan 14 Python
python正则表达式实例代码
Mar 03 Python
Python PIL库图片灰化处理
Apr 07 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实现的功能是显示8条基色色带
2006/10/09 PHP
php 引用(&amp;)详解
2009/11/20 PHP
php 获取百度的热词数据的代码
2012/02/18 PHP
PHP中nowdoc和heredoc使用需要注意的一点
2014/03/21 PHP
让CodeIgniter数据库缓存自动过期的处理的方法
2014/06/12 PHP
PHP实现的简单排列组合算法应用示例
2017/06/20 PHP
PHP设计模式之组合模式定义与应用示例
2020/02/01 PHP
php变量与字符串的增删改查操作示例
2020/05/07 PHP
jQuery语法总结和注意事项小结
2012/11/11 Javascript
基于NodeJS的前后端分离的思考与实践(五)多终端适配
2014/09/26 NodeJs
Bootstrap Chart组件使用教程
2016/04/28 Javascript
基于JavaScript实现随机颜色输入框
2016/12/10 Javascript
Node.js Event Loop各阶段讲解
2019/03/08 Javascript
vue基本使用--refs获取组件或元素的实例
2019/11/07 Javascript
js实现聊天对话框
2020/02/08 Javascript
js实现鼠标点击飘爱心效果
2020/08/19 Javascript
[02:17]DOTA2亚洲邀请赛 RAVE战队出场宣传片
2015/02/07 DOTA
[01:19:23]2018DOTA2亚洲邀请赛 4.5 淘汰赛 Mineski vs VG 第二场
2018/04/06 DOTA
在Pycharm中设置默认自动换行的方法
2019/01/16 Python
详解Python正则表达式re模块
2019/03/19 Python
Flask框架中request、请求钩子、上下文用法分析
2019/07/23 Python
Python多线程及其基本使用方法实例分析
2019/10/29 Python
详解Python可视化神器Yellowbrick使用
2019/11/11 Python
使用python远程操作linux过程解析
2019/12/04 Python
Python jieba结巴分词原理及用法解析
2020/11/05 Python
Python通过Schema实现数据验证方式
2020/11/12 Python
python 实现图片裁剪小工具
2021/02/02 Python
html5调用摄像头功能的实现代码
2018/05/07 HTML / CSS
荷兰多品牌网上鞋店:Stoute Schoenen
2017/08/24 全球购物
欧洲品牌瓷器餐具网上商店:Porzellantreff.de
2018/04/04 全球购物
俄罗斯药房连锁店:ASNA
2020/06/20 全球购物
营业经理岗位职责
2013/11/10 职场文书
关于群众路线的心得体会
2014/11/05 职场文书
2015年暑期见闻
2015/07/14 职场文书
磁贴还没死, 微软Win11可修改注册表找回Win10开始菜单
2021/11/21 数码科技
MySQL数据库Innodb 引擎实现mvcc锁
2022/05/06 MySQL