zoukankan      html  css  js  c++  java
  • 跳一跳实训

      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
    import datetime

    from PIL import Image
    # 实现控制Android设备等相关的操作

    class Operation:
        # 构造方法
       
    def __init__(self):
            pass

       
    # 截屏
       
    def screen_cap(self):
            filename = time = datetime.datetime.now().strftime("%H%M%S") + ".png"
           
    # 截屏并保存到手机的目录上
           
    cmd = "adb shell screencap -p /sdcard/auto.png"
           
    os.system(cmd)
            # 把手机目录上的文件拷贝到PC上
           
    cmd = "adb pull /sdcard/auto.png" + " img/" + filename
            os.system(cmd)

            # 打开图像文件
           
    return Image.open(filename)

    main.py

    from  .operation import *
    # 测试截屏
    def test_screen_cap():
        op = Operation()
        im = op.screen_cap()

    运行结果:

     

    7 显示图片的代码

    需要安装matplotlib库

    pip install matplotlib

    draw.py

    import matplotlib.pyplot as plt # 绘图
    import cv2 # 读取图片文件

    # 实现显示图片 绘制图片等功能
    class Draw:
        # 构造器
       
    def __init__(self):
            # 初始化图像plt对象
           
    self.fig = plt.figure()

        # 显示图片
       
    def show_pic(self, filename,scale=1):
            # 读取图像
           
    img = cv2.imread(filename)
            # 调整显示的比例
           
    img = cv2.resize(img, (0,0), fx=scale, fy=scale)
            # 显示图像
           
    plt.imshow(img)
            plt.show()

    main.py

    # 测试显示图片
    def test_show_pic():
        draw = Draw()
        draw.show_pic("img/155900.png")

    运行结果:

     

    8 计算两点间的欧氏距离

    Algorithm.py

    #-*- coding:utf-8 -*-
    #author:zhengjinwei
    #data: 2018.6.28
    #
    计算两点之间的欧式距离
    import math

    class Algorithm:
        def __init__(self):
            pass

        def
    calculate_distance(self,p1,p2):
            #计算欧式距离,用两点p1,p2表示距离
           
    return ((p2[0]-p1[0])**2+(p2[1]-p1[1])**2)*0.5

        def fine_point(self):
            """
            #
    寻找关键坐标
            # 返回值1,2 start_x, start_y 起跳点的坐标 170,555
            # 返回值3,4 end_x, end_y 目标点的坐标 395,425
           
    :return:
            """
           
    start_x=170
            start_y=555
            end_x=395
            end_y=425
            return start_x,start_y,end_x,end_y

    测试偶是欧氏距离main.py

    测试欧式距离
     algorithm = Algorithm()
     p1 = (3, 4)
     p2 = (6, 8)
     d = algorithm.calculate_distance(p1, p2)
     print(d)

    运行结果:

     

    9 寻找关键坐标——框架

    在alogrithm.py加入方法fine_point()

    def fine_point(self):
        """
        #
    寻找关键坐标
        # 返回值1,2 start_x, start_y 起跳点的坐标 170,555
        # 返回值3,4 end_x, end_y 目标点的坐标 395,425
       
    :return:
        """
       
    start_x=170
        start_y=555
        end_x=395
        end_y=425
        return start_x,start_y,end_x,end_y

    测试关键坐标

    Main.py

    #测试寻找关键坐标
    def text_find_point():
        algorithm=Algorithm()
        start_x,start_y,end_x,end_y=algorithm.fine_point()
        print('{0} {1} {2} {3}'.format(start_x,start_y,end_x,end_y))

    运行结果:

     

    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
    print("piece_y = %d" % (piece_y,))

     

            # 1.3 y坐标的最大值减去一个偏移值,就作为小人底座的y值。(注意:该偏移值不同的设备是不同的,同一台设备不同场景下是一样的)

     

            return piece_x, piece_y, board_x, board_y

     

    运行结果:

     

    12 优化程序

    无论是起跳位置,还有目标位置。都只取垂直的中间的1/3样式进行扫描。

    13 寻找关键坐标——目标坐标

    #-*- coding:utf-8 -*-
    #author:zhengjinwei
    #data: 2018.6.28
    #
    计算两点之间的欧式距离

    class Algorithm:
        #底座中心与小人最低点的偏移值
       
    piece_base_height=10
        def __init__(self):
            pass

        def
    calculate_distance(self,p1,p2):
            #计算欧式距离,用两点p1,p2表示距离
           
    return ((p2[0]-p1[0])**2+(p2[1]-p1[1])**2)*0.5

        def fine_point(self,img):
            """
            #
    寻找关键坐标
            # 返回值1,2 piece_x, piece_y 起跳点的坐标 170,555
            # 返回值3,4 board_x, board_y 目标点的坐标 395,425
           
    :return:
            """
           
    piece_x=0
            piece_y=0
            board_x=0
            board_y=0
            # 图像的大小
           
    w,h=img.size#(1080,1920)
            #
    加载图形
           
    img_pixel=img.load()
            # print(w,h,img_pixel)
            #
    记录小人所有的点
           
    points = []

            # 记录y的最大值
           
    piece_y_max = 0

            # 1 计算出起跳点 就是小人底座的中心点
            # 1.1 获取小人的所有像素点中y坐标的最大值
            # 遍历图像中的每一个点
            # 遍历每一行
           
    for i in range(h // 3, h * 2 // 3):
                #遍历每一列
               
    for j in range(w):
                    pixel=img_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
            print("piece_y = %d" % (piece_y,))
             # 1.3 y坐标的最大值减去一个偏移值,就作为小人底座的y值。(注意:该偏移值不同的设备是不同的,同一台设备不同场景下是一样的)


           
    """
           
    取目标点的位置
            """
           
    points = []
            # 只取中间1/3进行扫描
           
    for i in range(h // 3, h * 2 // 3):
                if len(points) > 0:
                    break
               
    # 取坐标的一个点作为背景的参照物
               
    last_pixel = img_pixel[0, i]
                # 逐个扫描右边的点
               
    for j in range(w):
                    pixel = img_pixel[j, i]
                    # 把当前点与最左边的点比较 如果RGB差异比较大 则认为是目标点
                   
    if (abs(pixel[0] - last_pixel[0])
                            + abs(pixel[1] - last_pixel[1])
                            + abs(pixel[2] - last_pixel[2]) > 10):
                        points.append((j, i))

            top_x = []
            for x, y in points:
                top_x.append(x)

            board_x = sum(top_x) // len(top_x)
            print("board_x = %d" % (board_x,))


            return piece_x,piece_y,board_x,board_y

    运行结果:

     

    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):
        ..


        # 2.2计算目标格式子y值

        # 屏幕中心的值
       
    center_x = w / 2 + 8 # x的偏差是8
       
    center_y = h / 2 + 20  # y的偏差是20

        # 格子高和宽的比例
       
    height_per_width = 265 / 675

        # 计算出目标格子的y值(需要转换成整数)
        # 计算出目标格子的y值(需要转换成整数)
        # 从piece_x调到board_x 如果piece_x < board_x则表示从左往右跳
        # 如果piece_x > board_x 则表示从右往左跳
       
    if piece_x < board_x:
            board_y = int(center_y - height_per_width * (board_x - center_x))
        else# 从右往左跳
           
    board_y = int(center_y + height_per_width * (board_x - center_x))

        print("board_y = %d" % (board_y,))

        return piece_x,piece_y,board_x,board_y

     

    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

  • 相关阅读:
    可以foreach的 必须继承IEnumable 接口才行
    .net 委托的用法
    匿名类的使用
    检测到有潜在危险的 Request.Form 值——ValidateRequest的使用
    IsPostBack用法
    Ajax 与 jquery
    好用的模板引擎NVelocity
    题解【AcWing275】[NOIP2008]传纸条
    题解【AcWing274】移动服务
    题解【AcWing271】杨老师的照相排列
  • 原文地址:https://www.cnblogs.com/zjinwei/p/9245831.html
Copyright © 2011-2022 走看看