一、目的
《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位置為:MuMu\emulator\nemu\vmonitor\bin
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