4 触控
zhbaor edited this page 2024-12-06 19:48:22 +08:00

消除惯性

在一段拖动后,有两种消除惯性的手法:

  • 原地等待
  • 向与原方向垂直的方向拖动(简称“拐弯”)

有些界面只能使用特定的方法,比如生息演算拖动地图只能用原地等待的手法;选关界面和终端主线界面无法用原地等待的手法消除惯性,只能用拐弯的手法。

要消除惯性,必须实现复杂的拖拽动作。目前有两种通用方案:scrcpy和uiautomator2。MuMu的触控API也支持复杂的拖拽动作。

swipe_ext用法介绍

这两种消除惯性的手法可以用统一的方法实现:将“原地等待”看成“起点与终点相同的拖动”,这样两种手法都可以看成在最后附加了一段拖拽动作。

BaseSolver类封装了方法swipe_ext,用来实现复杂的拖动。它的参数up_wait为正时,会在拖拽结束后原地等待。函数返回前会清除截图缓存。例如

solver.swipe_ext([(1700, 500), (1000, 500)], [500], up_wait=300, interval=0.2)

表示花费500ms从 (1700, 500) 处拖拽至 (1000, 500) 处(水平向左拖拽700像素),然后原地等待300ms以消除惯性,抬手之后用0.2秒等待回弹动画消失,最后清除截图缓存。

如果使用拐弯的手法消除惯性,可以这样写:

solver.swipe_ext([(1700, 500), (1000, 500), (1000, 200)], [500, 300], up_wait=0, interval=0.2)

第一段拖拽还是水平向左拖700像素,第二段是花费300ms垂直向上拖拽300像素。

swipe_update用法介绍

消除惯性的滑动,包括以下四步:

  1. 拖动
  2. 等待或拐弯
  3. 抬手
  4. 等待回弹动画

swipe_update在第2步开始后截图。这张截图有两个作用:

判断滑动是否到底

抬手前的截图与回弹动画结束后的截图如果有差异,说明发生了回弹,滑动已经到底了。

如果只在第4步后截图,要判断滑动是否到底,只能比较一次滑动前后的截图是否相同,滑动到底之后会再拖拽一次。使用swipe_update可以省去额外的一次滑动。

加快识别速度

大部分的滑动不会到底,从第2步开始到第4步结束,画面是不变的。如果在等待惯性消失和回弹动画消失的时候,用第2步的截图代替第4步的截图进行识别,让识别时间与等待时间重叠,并在第4步结束后检查截图与第2步是否一样(也就是检查是否发生了回弹),能够降低整体用时。

在滑动结束后识别,整体用时为:\text{拖动时间}+\text{等待时间}+\text{识别用时}

使用swipe_update,没有发生回弹时的整体用时为:\text{拖动时间}+\max(\text{等待时间}, \text{识别用时})+\text{验证用时}

swipe_update节省的时间为:\min(\text{等待时间}, \text{识别用时})-\text{验证用时}

因此使用swipe_update时,验证一定要快于识别,否则swipe_update只会更慢。

API

swipe_updateswipe_ext的大部分参数含义相同。在滑动的最后一段,也就是等待惯性消失的时,运行func函数,swipe_update的返回值就是它的结果。

swipe_update退出后,config.recog.img为等待抬手过程中的截图。运行config.recog.update()后再访问config.recog.im,得到回弹动画结束后的截图。

以基建选人遍历为例:

# 识别第一页的干员
print([i[0] for i in operator_room_select(config.recog.img)])

while True:
    # swipe_update的返回值就是operator_room_select的返回值
    result = solver.swipe_update(
        [(1820, 770), (725, 770)],
        [200],
        up_wait=400,
        interval=0.1,
        func=operator_room_select,
    )
    print([i[0] for i in result])

    # 截图缓存中为等待惯性消失时的截图
    img1 = config.recog.gray

    # 清除缓存后重新截图,为回弹动画结束后的截图
    config.recog.update()
    img2 = config.recog.gray

    # 识别回弹动画
    if diff_ratio(img1, img2, thresh=10):
        break

以上示例中使用了原地等待的手法消除惯性。swipe_update同样也支持拐弯的手法:

result = solver.swipe_update(
    [(1820, 770), (725, 770), (725, 900)],
    [200, 400],
    up_wait=0,
    interval=0.1,
    func=operator_room_select,
)