Python实现游戏自动操作脚本

您所在的位置:网站首页 可以自动打游戏的软件 Python实现游戏自动操作脚本

Python实现游戏自动操作脚本

2024-06-25 03:37| 来源: 网络整理| 查看: 265

1.自动操作基础代码 2.识别并定位指定目标代码 3.游戏自动操作代码 (1)崩坏3 (2)阴阳师

作为一个经常肝崩崩崩的舰长,在很久之前就有个想法,对于一些重复的操作,要是能自动点击实现就好了。 其实最开始有这个想法是肝阴阳师的时候,刷觉醒材料真是刷到吐,感觉自己就像机器人一样。 最开始研究了一下,发现想法很简单,但在手机上实现起来没那么容易。 最近忽然又想到可以利用Python实现,在Windows下开个Android模拟器就可以了。 所以便着手写代码试了下,效果还不错。

自动操作脚本的思想很简单,由于重复操作每次点击的位置和内容都非常固定,因此只需要在代码中指定好每次该往哪里点即可。 在Python中,可以通过Windows自带的API实现获取鼠标位置、移动鼠标、点击鼠标等操作。

关于如何获取点击要点击的位置,也有两种思路,一种是手动设置。自己先走一遍流程,记录下每次点击的位置,放到代码里。 优点是简单粗暴,效率高,缺点是灵活性较差,点击位置稍有变化就有可能导致失败。 另一种相对”高端”的办法是自动寻找。 因为我是做CV的,所以很自然就想到了用图像识别的办法寻找点击位置。先将需要点击的位置保存成小图片,在程序运行时,让程序根据小图片自动寻找待点击位置。 这样的有点是灵活性高,应变能力强,缺点是计算量相对较大。 而关于如何寻找,这里又有两种办法,一种是基于模板匹配,另一种是基于特征点匹配。 经过实践,发现基于特征点匹配会更加稳定些,不容易误匹配。

1.自动操作基础代码

首先是一些跟自动操作有关的基础代码,如设置鼠标位置、点击等。

# coding=utf-8 import win32api, win32gui, win32con from ctypes import * import time def getCurPos(): return win32gui.GetCursorPos() def getPos(): while True: res = getCurPos() print res time.sleep(1) def clickLeft(): win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN | win32con.MOUSEEVENTF_LEFTUP, 0, 0) def movePos(x, y): windll.user32.SetCursorPos(x, y) def animateMove(curPos, targetPos, durTime=1, fps=60): x1 = curPos[0] y1 = curPos[1] x2 = targetPos[0] y2 = targetPos[1] dx = x2 - x1 dy = y2 - y1 times = int(fps * durTime) dx_ = dx * 1.0 / times dy_ = dy * 1.0 / times sleep_time = durTime * 1.0 / times for i in range(times): int_temp_x = int(round(x1 + (i + 1) * dx_)) int_temp_y = int(round(y1 + (i + 1) * dy_)) windll.user32.SetCursorPos(int_temp_x, int_temp_y) time.sleep(sleep_time) windll.user32.SetCursorPos(x2, y2) def animateMoveAndClick(curPos, targetPos, durTime=1, fps=60, waitTime=1): x1 = curPos[0] y1 = curPos[1] x2 = targetPos[0] y2 = targetPos[1] dx = x2 - x1 dy = y2 - y1 times = int(fps * durTime) dx_ = dx * 1.0 / times dy_ = dy * 1.0 / times sleep_time = durTime * 1.0 / times for i in range(times): int_temp_x = int(round(x1 + (i + 1) * dx_)) int_temp_y = int(round(y1 + (i + 1) * dy_)) windll.user32.SetCursorPos(int_temp_x, int_temp_y) time.sleep(sleep_time) windll.user32.SetCursorPos(x2, y2) time.sleep(waitTime) clickLeft()

在Windows中提供了相关的API可供调用,因此写起来比较简单。自己主要写的是“动画函数”,这样在鼠标移动的时候看起来比较自然,不会“闪现”。 这里需要注意的问题是,鼠标坐标接受参数是整形,因此要类型转换。此外dx_、dy_不能一开始就变为int,否则每一次移动都会损失到一部分小数,到最后移动了指定次数后会发现和终点差很远。 这个差距就是由舍去的小数部分不断累积导致的,需要注意一下。

if __name__ == '__main__': animateMove(getCurPos(), (500, 500)) animateMove(getCurPos(), (600, 400)) animateMove(getCurPos(), (500, 300)) animateMove(getCurPos(), (400, 400)) animateMove(getCurPos(), (500, 400)) animateMove(getCurPos(), (500, 500))

利用以上基础代码,就可以实现如下图的效果了。 如果你仅仅只是想要学习利用Python操控鼠标,那么到这里就可以了。后面的内容主要就是上面代码在游戏中的具体应用。

2.识别并定位指定目标代码

本部分偏向于计算机视觉,主要介绍通过特征点提取和匹配,找到目标在屏幕中的位置。关于特征提取和匹配的原理,之前说过太多太多了,在博客里找找就行。下面就直接放代码和演示效果了。 特征提取和匹配的代码来自于之前写的functionModule。

# coding=utf-8 from PIL import ImageGrab as ig import cv2 import numpy as np def getSiftKps(img, numKps=2000): """ 获取SIFT特征点和描述子 :param img: 读取的输入影像 :param numKps:期望提取的特征点个数,默认2000 :return:特征点和对应的描述子 """ sift = cv2.xfeatures2d_SIFT.create(nfeatures=numKps) kp, des = cv2.xfeatures2d_SIFT.detectAndCompute(sift, img, None) return kp, des def flannMatch(kp1, des1, kp2, des2): """ 基于FLANN算法的匹配 :param kp1: 特征点列表1 :param des1: 特征点描述列表1 :param kp2: 特征点列表2 :param des2: 特征点描述列表2 :return: 匹配的特征点对 """ good_matches = [] good_kps1 = [] good_kps2 = [] print("kp1 num:" + len(kp1).__str__() + "," + "kp2 num:" + len(kp2).__str__()) # FLANN parameters FLANN_INDEX_KDTREE = 0 index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5) search_params = dict(checks=50) # or pass empty dictionary flann = cv2.FlannBasedMatcher(index_params, search_params) matches = flann.knnMatch(des1, des2, k=2) # 筛选 for i, (m, n) in enumerate(matches): if m.distance 15: exit() time.sleep(5) print "opening game..." bf.animateMoveAndClick(bf.getCurPos(), bengbengbeng) counter = 0 while True: print "waiting..." login = bf.findLocWithKp(img_login) if login[0] != 0 and login[1] != 0: break if counter > 15: exit() time.sleep(5) bf.animateMoveAndClick(bf.getCurPos(), (login[0] + 300, login[1])) time.sleep(8) message_box = bf.findLocWithKp(img_message) if message_box[0] != 0 and message_box[1] != 0: bf.animateMoveAndClick(bf.getCurPos(), message_box) time.sleep(2) daily = bf.findLocWithKp(img_daily) if daily[0] != 0 and daily[1] != 0: bf.animateMoveAndClick(bf.getCurPos(), daily) time.sleep(1) confirm = bf.findLocWithKp(img_confirm) bf.animateMoveAndClick(bf.getCurPos(), confirm) time.sleep(8) def collectCoinsAuto(): img_base = cv2.imread("bh3/05.png", cv2.IMREAD_GRAYSCALE) img_coin = cv2.imread("bh3/06.png", cv2.IMREAD_GRAYSCALE) img_confirm = cv2.imread("bh3/07.png", cv2.IMREAD_GRAYSCALE) img_back = cv2.imread("bh3/08.png", cv2.IMREAD_GRAYSCALE) counter = 0 while True: print "waiting..." counter += 1 base = bf.findLocWithKp(img_base) if base[0] != 0 and base[1] != 0: break if counter > 15: exit() time.sleep(5) bf.animateMoveAndClick(bf.getCurPos(), base) time.sleep(2) coins = bf.findLocWithKp(img_coin) bf.animateMoveAndClick(bf.getCurPos(), coins) time.sleep(2) confirm = bf.findLocWithKp(img_confirm) bf.animateMoveAndClick(bf.getCurPos(), confirm) time.sleep(2) back = bf.findLocWithKp(img_back) bf.animateMoveAndClick(bf.getCurPos(), back) time.sleep(2) def adventureAuto(): img_base = cv2.imread("bh3/05.png", cv2.IMREAD_GRAYSCALE) img_adventure = cv2.imread("bh3/14.png", cv2.IMREAD_GRAYSCALE) img_refresh = cv2.imread("bh3/11.png", cv2.IMREAD_GRAYSCALE) img_back = cv2.imread("bh3/08.png", cv2.IMREAD_GRAYSCALE) img_goto = cv2.imread("bh3/10.png", cv2.IMREAD_GRAYSCALE) img_onekey = cv2.imread("bh3/12.png", cv2.IMREAD_GRAYSCALE) img_confirm = cv2.imread("bh3/13.png", cv2.IMREAD_GRAYSCALE) img_home = cv2.imread("bh3/16.png", cv2.IMREAD_GRAYSCALE) base = bf.findLocWithKp(img_base) bf.animateMoveAndClick(bf.getCurPos(), base) time.sleep(2) venture = bf.findLocWithKp(img_adventure, numKps=5000) bf.animateMoveAndClick(bf.getCurPos(), venture) time.sleep(2) loc1 = bf.findLocWithKp(img_back) loc2 = bf.findLocWithKp(img_refresh) y_start = loc1[1] y_end = loc2[1] print y_start, y_end y_range = y_end - y_start task1_y_start = int(y_start + 0.194 * y_range) task1_y_end = int(y_start + (0.194 + 0.225) * y_range) task2_y_start = int(y_start + 0.434 * y_range) task3_y_start = int(y_start + 0.673 * y_range) screen = ig.grab() screen_cv = cv2.cvtColor(np.asarray(screen), cv2.COLOR_RGB2GRAY) task1_img = screen_cv[task1_y_start:task1_y_end, :] _, kp_task1 = bf.siftFlannMatch(img_goto, task1_img) mean_x_task = 0 mean_y_task = 0 for i in range(kp_task1.__len__()): mean_x_task += kp_task1[i][0] mean_y_task += kp_task1[i][1] mean_x_task = mean_x_task / kp_task1.__len__() mean_y_task = mean_y_task / kp_task1.__len__() target1 = (int(mean_x_task), int(task1_y_start + mean_y_task)) target2 = (int(mean_x_task), int(task2_y_start + mean_y_task)) target3 = (int(mean_x_task), int(task3_y_start + mean_y_task)) bf.animateMoveAndClick(bf.getCurPos(), target1) time.sleep(2) onekey = bf.findLocWithKp(img_onekey) bf.animateMoveAndClick(bf.getCurPos(), onekey) time.sleep(2) confirm = bf.findLocWithKp(img_confirm) bf.animateMoveAndClick(bf.getCurPos(), confirm) time.sleep(2) bf.animateMoveAndClick(bf.getCurPos(), target2) time.sleep(2) bf.animateMoveAndClick(bf.getCurPos(), onekey) time.sleep(2) bf.animateMoveAndClick(bf.getCurPos(), confirm) time.sleep(2) bf.animateMoveAndClick(bf.getCurPos(), target3) time.sleep(2) bf.animateMoveAndClick(bf.getCurPos(), onekey) time.sleep(2) bf.animateMoveAndClick(bf.getCurPos(), confirm) time.sleep(2) home = bf.findLocWithKp(img_home) bf.animateMoveAndClick(bf.getCurPos(), home) time.sleep(2) if __name__ == '__main__': openBh3Auto() collectCoinsAuto() adventureAuto()

对于流程中有一些等待时间不确定的步骤,采用了while循环,每隔5秒检查一次,最多检查15次。运行效果如下。

(2)阴阳师

其实相比于崩坏3,阴阳师更适合于自动操作脚本,尤其是上面说到的觉醒材料副本。写了个自动打开游戏,然后刷觉醒副本的脚本。

# coding=utf-8 import baseFunctions as bf import cv2 import time def openYysAuto(): img_start = cv2.imread("yys/01.png", cv2.IMREAD_GRAYSCALE) img_mumu = cv2.imread("yys/02.png", cv2.IMREAD_GRAYSCALE) img_yys = cv2.imread("yys/03.png", cv2.IMREAD_GRAYSCALE) img_announce = cv2.imread("yys/04.png", cv2.IMREAD_GRAYSCALE) img_enter = cv2.imread("yys/05.png", cv2.IMREAD_GRAYSCALE) print "opening application..." start_menu = bf.findLocWithKp(img_start) bf.animateMoveAndClick(bf.getCurPos(), start_menu) time.sleep(2) mumu = bf.findLocWithKp(img_mumu) bf.animateMoveAndClick(bf.getCurPos(), mumu) counter = 0 while True: print "waiting..." counter += 1 yys = bf.findLocWithKp(img_yys) if yys[0] != 0 and yys[1] != 0: break if counter > 15: exit() time.sleep(5) print "opening game..." bf.animateMoveAndClick(bf.getCurPos(), yys) time.sleep(15) bf.animateMoveAndClick(bf.getCurPos(), yys) time.sleep(10) announce = bf.findLocWithKp(img_announce) bf.animateMoveAndClick(bf.getCurPos(), (announce[0], announce[1] - 80)) time.sleep(1) enter = bf.findLocWithKp(img_enter) bf.animateMoveAndClick(bf.getCurPos(), enter) time.sleep(5) bf.animateMoveAndClick(bf.getCurPos(), enter) time.sleep(8) def juexingAuto(type, times=5): img_explore = cv2.imread("yys/06.png", cv2.IMREAD_GRAYSCALE) img_juexing = cv2.imread("yys/07.png", cv2.IMREAD_GRAYSCALE) img_huo = cv2.imread("yys/08.png", cv2.IMREAD_GRAYSCALE) img_feng = cv2.imread("yys/09.png", cv2.IMREAD_GRAYSCALE) img_shui = cv2.imread("yys/10.png", cv2.IMREAD_GRAYSCALE) img_lei = cv2.imread("yys/11.png", cv2.IMREAD_GRAYSCALE) img_challenge = cv2.imread("yys/12.png", cv2.IMREAD_GRAYSCALE) img_prepare = cv2.imread("yys/13.png", cv2.IMREAD_GRAYSCALE) img_confirm = cv2.imread("yys/14.png", cv2.IMREAD_GRAYSCALE) img_close = cv2.imread("yys/15.png", cv2.IMREAD_GRAYSCALE) img_back = cv2.imread("yys/16.png", cv2.IMREAD_GRAYSCALE) time.sleep(4) explore = bf.findLocWithKp(img_explore) bf.animateMoveAndClick(bf.getCurPos(), explore) time.sleep(5) juexing = bf.findLocWithKp(img_juexing) bf.animateMoveAndClick(bf.getCurPos(), juexing) time.sleep(3) if type == 1: exe_type = bf.findLocWithKp(img_huo) elif type == 2: exe_type = bf.findLocWithKp(img_feng) elif type == 3: exe_type = bf.findLocWithKp(img_shui) elif type == 4: exe_type = bf.findLocWithKp(img_lei) bf.animateMoveAndClick(bf.getCurPos(), exe_type) time.sleep(2) for i in range(times): print i + 1, '/', times challenge = bf.findLocWithKp(img_challenge) bf.animateMoveAndClick(bf.getCurPos(), challenge) time.sleep(10) prepare = bf.findLocWithKp(img_prepare) bf.animateMoveAndClick(bf.getCurPos(), prepare) time.sleep(50) counter = 0 while True: print "waiting..." counter += 1 confirm = bf.findLocWithKp(img_confirm) if confirm[0] != 0 and confirm[1] != 0: break if counter > 15: exit() time.sleep(5) bf.animateMoveAndClick(bf.getCurPos(), confirm) time.sleep(3) close = bf.findLocWithKp(img_close) bf.animateMoveAndClick(bf.getCurPos(), close) time.sleep(2) back = bf.findLocWithKp(img_back) bf.animateMoveAndClick(bf.getCurPos(), back) if __name__ == '__main__': openYysAuto() juexingAuto(1, 2) juexingAuto(2, 1) juexingAuto(3, 1) juexingAuto(4, 1)

演示效果如下。视频里让电脑自动刷了两遍火,其它各一遍。

终于可以把手机扔在那里,让电脑自动刷一下午了。最后完整项目代码放在了Github上,点击查看。



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3