一、目的
《Python从入门到实践》第14章拉拉杂杂“抄”完,急于练手,便捡起以前一直想写却没写完的“鼠标键盘模拟”程序。
二、思考
图1.0 auto_game思考方向
如图1.0,思考了两种实现方法。
第一种方法是在电脑层面模拟电脑鼠标点击。使用pyautogui库实现之后,MUMU模拟器内运行游戏并未做出相应反应。更换20180111版本MUMU,仍然不成功。如果仍想采用这种思路,就需要更换模拟器软件,或者采用驱动级鼠标键盘模拟。
第二种方法通过adb(Android Debug Bridge)操作管理andriod设备。下面对第二种方法予以讨论。
(一)模拟过程
如图1.1所示,明日方舟1-7刷图可以分为三个部分:开始(①、②)、等待(③)、结束(④)。
图1.1 1-7刷图过程
1.开始阶段(①、②)
需要在两个特定位置(“开始行动”)点击两次。
2.等待阶段(③)
需要等待一段时间。
3.结束阶段(④)
需要在除“获得物品”之外的其他地方点击一次。
(二)实现思路
1.判断当前游戏阶段
使用adb命令截图,cv2判断特定图形出现在截图中的可能性,超过阈值,即为出现特定场景。
2.特定场景时发出点击命令
3.点击位置伪随机
4.点击时间间隔伪随机
5.特殊情况
开始阶段的①、②两图需要点击的按钮范围存在重合部分。可以将两次独立的判断后点击合并为:判断出现场景①后,点击两次。
结束阶段的④图,只需要在屏幕的上半部分点击一次即可。
三、实现过程
(一)安装cv2
图2.0 opencv-python安装过程
安装cv2实际上是安装opencv-python。不推荐使用pip指令安装,因为那样下载速度感人。建议图2.0所示,先去下好whl包,本地安装。
(下载地址:https://pypi.org/project/numpy/ https://pypi.org/project/opencv-python/ )
(二)连接安卓设备
本文使用MUMU版本为:2.3.4(0327192208)
1.找到adb
图2.1 adb_server
如图2.1,MUMU模拟器默认的adb位置为:MuMuemulator emuvmonitorin
2.修改环境变量
图2.2 打开环境变量
>此电脑>属性>高级系统设置>环境变量,双击Path更改:添加进adb_server所在的文件路径。
3.连接
对于windows系统,MUMU默认的连接端口为:127.0.0.1:7555
在命令行窗口输入指令:>adb_server connect 127.0.0.1:7555
图2.3 连接成功
(三)编写程序
1.框架
图3.0 auto_game框架
如图3.0 所示,程序分为4部分:setting(包含Settings对象)、robot_functions(包含一些操作函数)、robot(包含Robot对象)、main(主函数auto_game)。
2.setting.py
1 import cv2 2 class Settinigs: 3 """表示机器人参数设置的类""" 4 def __init__(self): 5 #机器人玩游戏局数 6 self.num = 30 7 #机器人可点击屏幕区域范围 8 self.clickx = [830,935] 9 self.clicky = [500,515] 10 self.t_start = cv2.imread("./pictures/t_start.png") 11 self.t_end = cv2.imread("./pictures/t_end.png")
3.robot_functions.py
1 import os 2 import cv2 3 import time 4 import random 5 6 7 def execute(cmd): 8 #构造并执行adb命令 9 str = "adb_server shell {cmdStr}".format(cmdStr=cmd) 10 # print(str) 11 os.system(str) 12 13 def click(x, y): 14 #点击像素点 15 click_order = 'input tap {} {}'.format(x, y) 16 execute(click_order) 17 18 def get_randpoint(x,y): 19 px = random.randint(x[0], x[1]) 20 py = random.randint(y[0], y[1]) 21 return px,py 22 23 def sleep_randtime(min,max): 24 time.sleep(random.uniform(min,max)) 25 26 def match(img,template): 27 """计算图像中包含模板的最大可能性,取值范围0~1""" 28 res = cv2.matchTemplate(img,template,cv2.TM_CCOEFF_NORMED) 29 return res.max() 30 31 def shot_screen(img_name): 32 """截屏并命名为img_name,返回图片""" 33 shot_order = "screencap -p /storage/emulated/0/Pictures/{name}.png".format(name = img_name) 34 execute(shot_order) 35 poll_order ="adb_server pull /storage/emulated/0/Pictures/{name}.png ./pictures/{name}.png".format(name = img_name) 36 #因为拉取命令格式特殊,直接用os 37 os.system(poll_order) 38 res = cv2.imread("./pictures/{name}.png".format(name = img_name)) 39 return res 40 41 def shot_match(img_name,template): 42 #截屏命名为img_name,img_name与template匹配,成功返回True,失败返回False 43 n = 0 44 while n < 15: 45 img1 = shot_screen(img_name) 46 res = match(img1, template) 47 if res > 0.97: 48 print("-Matched {} times.".format(n+1)) 49 return True 50 else: 51 sleep_randtime(0.8, 1.2) 52 n += 1 53 print("-Match failed.") 54 return False
4.robot.py
1 import robot_functions as rf 2 3 4 class Robot(): 5 def __init__(self,settings): 6 self.settings = settings 7 8 def start(self): 9 #截屏并匹配 10 rf.shot_match("img1",self.settings.t_start) 11 #延时点击区域内随机点两次 12 x,y = rf.get_randpoint(self.settings.clickx,self.settings.clicky) 13 rf.click(x,y) 14 rf.sleep_randtime(0.8,1.5) 15 rf.click(x, y) 16 17 def waiting(self): 18 print("-Waiting......") 19 rf.sleep_randtime(79.0,81.0) 20 21 def end(self): 22 #截屏并匹配 23 if not rf.shot_match("img2",self.settings.t_end): 24 print("Game over.") 25 return False 26 x, y = rf.get_randpoint([0,1023],[0,250]) 27 rf.click(x, y) 28 rf.sleep_randtime(1.8, 2.0) 29 return True
5.auto_game.py
1 from robot import Robot 2 from settings import Settinigs 3 4 5 settings = Settinigs() 6 n = 0 7 for n in range(settings.num): 8 robot = Robot(settings) 9 robot.start() 10 robot.waiting() 11 if not robot.end(): 12 break 13 14 print("Done {} times.".format(n+1)) 15 print("Consumed {} sanity.".format((n+1)*6))
注:本博客仅供学习交流,严禁其他非法用途。
1.MUMU开发者必备说明书:http://mumu.163.com/help/func/20190129/30131_797867.html