跳一跳实训
Posted zjinwei
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了跳一跳实训相关的知识,希望对你有一定的参考价值。
1 手机和电脑用数据线连接
在电脑上下载360手机助手,并通过数据线连接手机。首次连接需要安装对应的手机驱动程序。(手机最好也下一个连接助理以保证连接的通畅),进入到保存微信跳一跳资源包的路径并复制下来
进入cmd命令窗口
输入adb命令
adb devices |
可以查看连接的android设备的信息
运行结果:
2 获取手机相关的信息
通过如下命令可以查看连接电脑的Android手机相关的信息
adb shell dumpsys window displays |
|
运行结果:
在第3行可以看到手机的分辨率(自己加个红框框)
获取屏幕密度
|
运行结果:
获取手机型号
adb shell getprop ro.product.device |
运行结果:
获取Android系统的版本
adb shell getprop ro.build.version.release |
运行结果:
3 截屏
输入如下命令:
adb shell screencap -p /sdcard/auto.png |
此时,截屏的图片就保存到 /sdcard/auto.png文件中。
注意:/sdcard/和/data/目录是可以写入的。
一般手机是内置了sdcard的,而且data是没有权限的(反正我的没有),所以大胆写进sdcard
可以通过命令
adb shell ls /sdcard/ -l |
查看sdcard目录下所有的文件。
通过如下命令把手机上的文件拷贝到电脑上
adb pull /sdcard/auto.png d: |
此时,图片就会被拷贝到d:根目录下了。打开即可看到当前手机的屏幕信息。
注意:这时候手机最好是调到跳一跳游戏开始的界面,下一步模拟微信跳一跳的时候才有效果。
4 屏幕点击事件
通过如下命令模拟点击手机屏幕的事件
adb shell input swipe x1 x2 y1 y2 duration |
通过adb shell input swipe命令进行滑动
X1、x1:滑动开始的点
Y1、y2:滑动结束的点
Duration:持续的时间(单位ms)
特殊情况:如果不写duration参数,就理解为点击事件。如果写duration,然后x1x2和y1y2是相同的点,就表示长按
跳一跳的关键是:duration的计算
尝试:
adb shell input swipe 100 100 100 700 |
这个700是改变的值,(跳一跳的第一步),改变700这个参数值试出得2分的范围
注意一个问题: 手机要进入usb调试,将usb模拟点击的按钮打开,不然会不成功
值 |
得分 |
716 |
2 |
710 |
2 |
700 |
1 |
705 |
1 |
708 |
2 |
720 |
2 |
724 |
2 |
728 |
2 |
730 |
2 |
742 |
1 |
741 |
2 |
最大范围是 [708,741] 最中间值为:724.5
5 duration值的计算
假设我们截屏的效果是如下:
从图中可以看到,时间的值跟开始位置到结束位置的距离有关。
假设时间是t,距离是s。公式应该是s = at
基本思路:两点之间的距离乘以一个时间系数。
所以要从截图上识别出起跳位置的坐标(x1,y1)和目标位置的坐标(x2,y2)。
起跳位置的坐标:小人的底座中心点
目标位置的坐标:目标菱形的中心点
然后计算这两点之间的距离(欧氏距离):sqrt((x1-x2)2+(y1-y2)2)
6 截屏的代码
创建img目录,后面把所有截屏的图片都放到该目录下(原则上每跳一步都需要截屏一次)
operation.py
import os
|
main.py
from .operation import * |
# 测试截屏
|
运行结果:
7 显示图片的代码
需要安装matplotlib库
pip install matplotlib |
draw.py
import matplotlib.pyplot as plt # 绘图
|
main.py
# 测试显示图片
|
运行结果:
8 计算两点间的欧氏距离
Algorithm.py
#-*- coding:utf-8 -*-
|
测试偶是欧氏距离main.py
测试欧式距离
|
运行结果:
9 寻找关键坐标——框架
在alogrithm.py加入方法fine_point()
def fine_point(self):
|
测试关键坐标
Main.py
#测试寻找关键坐标
|
运行结果:
10 获取每一个点的RGB值
# 寻找关键坐标 # 返回值1,2 piece_x, piece_y 起跳点的坐标 170,555 # 返回值3,4 board_x, board_y 目标点的坐标 395,425 def find_point(self,im): piece_x = piece_y = 0 board_x = board_y = 0
# 图像的大小 w,h = im.size # (540, 960) # 加载图像 im_pixel = im.load()
# 遍历图像中的每一个点 # 遍历每一行 for i in range(h): # 遍历每一列 for j in range(w):
pixel = im_pixel[j,i] print("i = ", i, ",j = ", j, "pixel = ", pixel)
|
测试代码如下:
# 测试寻找关键坐标 def test_find_point(): op = Operation() im = op.screen_cap() algorithm = Algorithm() start_x, start_y, end_x, end_y = algorithm.find_point(im) print("start_point:", start_x, start_y) print("end_point:", end_x, end_y)
|
11 寻找关键坐标——起跳坐标
算法策略:获取小人的底座中心点的值作为起跳点。
1 获取小人的所有像素点中y坐标的最大值
2 在小人y坐标的最大值那些像素点中,计算出x的平均值,作为小人底座的x的值。
3 y坐标的最大值减去一个偏移值,就作为小人底座的y值。(注意:该偏移值不同的设备是不同的,同一台设备不同场景下是一样的)
比如教师机的设备中最低点的值是(168,565),中心值是 (168,555),从而计算出偏移值为565-555=10
11.1 获取小人y坐标的最大值
需要从上往下一行行扫描像素点,直到找到小人位置。
# 寻找关键坐标 # 返回值1,2 piece_x, piece_y 起跳点的坐标 170,555 # 返回值3,4 board_x, board_y 目标点的坐标 395,425 def find_point(self,im): piece_x = piece_y = 0 board_x = board_y = 0
# 图像的大小 w,h = im.size # (540, 960) # 加载图像 im_pixel = im.load()
# 记录y的最大值 piece_y_max = 0
# 1 计算出起跳点 就是小人底座的中心点 # 1.1 获取小人的所有像素点中y坐标的最大值 # 遍历图像中的每一个点 # 遍历每一行 for i in range(h): # 遍历每一列 for j in range(w):
pixel = im_pixel[j,i] #print("i = ", i, ",j = ", j, "pixel = ", pixel)
# 判断pixel是否小人所在的位置 # 当该点的RGB值约为55,59,102的时候就可以认为是小人所在的像素点了 if(50 < pixel[0] < 60 and 53 < pixel[1] < 63 and 95 < pixel[2] < 110): # 记录下y的值 if i > piece_y_max: piece_y_max = i
print("piece_y_max = %d" % (piece_y_max,))
# 1.2 在小人y坐标的最大值那些像素点中,计算出x的平均值,作为小人底座的x的值。
# 1.3 y坐标的最大值减去一个偏移值,就作为小人底座的y值。(注意:该偏移值不同的设备是不同的,同一台设备不同场景下是一样的)
return piece_x, piece_y, board_x, board_y
|
11.2 获取小人底座的x坐标
记录下小人所有的点。
# 寻找关键坐标 # 返回值1,2 piece_x, piece_y 起跳点的坐标 170,555 # 返回值3,4 board_x, board_y 目标点的坐标 395,425 def find_point(self,im): piece_x = piece_y = 0 board_x = board_y = 0
# 图像的大小 w,h = im.size # (540, 960) # 加载图像 im_pixel = im.load() # 记录小人所有的点 points = []
# 记录y的最大值 piece_y_max = 0
# 1 计算出起跳点 就是小人底座的中心点 # 1.1 获取小人的所有像素点中y坐标的最大值 # 遍历图像中的每一个点 # 遍历每一行 for i in range(h): # 遍历每一列 for j in range(w):
pixel = im_pixel[j,i] #print("i = ", i, ",j = ", j, "pixel = ", pixel)
# 判断pixel是否小人所在的位置 # 当该点的RGB值约为55,59,102的时候就可以认为是小人所在的像素点了 if(50 < pixel[0] < 60 and 53 < pixel[1] < 63 and 95 < pixel[2] < 110): # 把当前的点添加到points数组中 points.append((j,i)) # (x,y) # 记录下y的值 if i > piece_y_max: piece_y_max = i
print("piece_y_max = %d" % (piece_y_max,))
# 1.2 在小人y坐标的最大值那些像素点中,计算出x的平均值,作为小人底座的x的值。 bottom_x = [] for x,y in points: if y == piece_y_max: bottom_x.append(x)
piece_x = sum(bottom_x) // len(bottom_x) print("piece_x = %d" % (piece_x,))
piece_y=piece_y_max-self.piece_base_height
# 1.3 y坐标的最大值减去一个偏移值,就作为小人底座的y值。(注意:该偏移值不同的设备是不同的,同一台设备不同场景下是一样的)
return piece_x, piece_y, board_x, board_y
|
|
运行结果:
12 优化程序
无论是起跳位置,还有目标位置。都只取垂直的中间的1/3样式进行扫描。
13 寻找关键坐标——目标坐标
#-*-
coding:utf-8 -*-
|
运行结果:
13. 1 获取目标坐标的y值
取屏幕宽和高的一半(x=560和y=960)
我们会发现,目标格子的边沿(x=568,y=980)和这个是差不多的(y的偏差是20,x的偏差是8)
以后每次跳动的时候,假如已经知道目标格子的边沿,和目标坐标的x值,就可以很轻松计算出目标坐标的y值。
注意:每个格子的宽和高的比例是相同的。
左:(568,850)
右:(1243,850)
上:(1023,715)
下:(1023,980)
中:(1023,850)
高和宽的比例:(980-715)/(1243-568) =265/675=53/135。假设该值为p
已经知道目标坐标的x值,求目标坐标的y值
# 2.2计算目标格式子y值 # 屏幕中心的值 center_x = w / 2 + 8 # x的偏差是8 center_y = h / 2 + 20 # y的偏差是20 # 格子高和宽的比例 height_per_width = 265 / 675 # 计算出目标格子的y值(需要转换成整数) board_y = int(center_y - height_per_width * (board_x - center_x)) print("board_y = %d" % (board_y,))
|
运行结果:
13.3 区分从左往右跳和从右往左跳
Algorithm.py 方法:find_point
def fine_point(self,img): … … …
|
14 初步估算距离与时间的比例
algorithm.py
# 距离与时间的转换 def distance_to_time(self, distance): # 当0分的时候 距离为 261.222128 时间为730 p = 730 / 261.222128 # 该算法后面待优化 press_time = distance * p return press_time
|
15 控制屏幕进行跳动
operation.py
# 控制屏幕进行跳动 def jump(self, src, dst, press_time): press_time = int(press_time) cmd = "adb shell input swipe %d %d %d %d %d" % ( int(src[0]), int(src[1]), int(dst[0]), int(dst[1]), press_time ) print(cmd) os.system(cmd)
|
main.py
def test_jump(): algorithm = Algorithm() op = Operation() im = op.screen_cap() start_x, start_y, end_x, end_y = algorithm.find_point(im) start_point = (start_x, start_y) end_point = (end_x, end_y) distance = algorithm.euclidean_distance(start_point, end_point) press_time = algorithm.distance_to_time(distance) op.jump(start_point, end_point, press_time) |
END
遇到的问题
问题1:pychram运行main.py时出现“adb的乱码”
解决:将adb的目录添加到电脑的系统环境变量中,之后重启pycharm
问题2:运行是operation时候img目录没有图像生成
解决:
def screen_cap(self):
filename = time = datetime.datetime.now().strftime("%H%M%S") + ".png"
# 截屏并保存到手机的目录上
cmd = "adb shell screencap -p /sdcard/" + filename
os.system(cmd)
# 把手机目录上的文件拷贝到PC上
cmd = "adb pull /sdcard/" + filename + "img/" + filename
os.system(cmd)
#打开图像
return
Image.open(‘img/‘+filename)
在cmd = "adb pull /sdcard/" + filename + "img/" + filename中 img前面没有添加空格
更改如下:cmd = "adb
pull /sdcard/" +
filename + " img/"
+ filename
以上是关于跳一跳实训的主要内容,如果未能解决你的问题,请参考以下文章