【Python】如何用pyth做游戏脚本(太简单了吧)
文章目录
- 前言
- 一、开发前景
- 二、开发流程
- 3.1、获取窗口句柄,把窗口置顶
- 3. 2、截取游戏界面,分割图标,图片比较
- 二、程序核心-图标连接算法(路径寻找)
- 四、开发总结
- 五、源码
- 总结
前言
简述:本文将以4399小游戏《 宠物连连看经典版2 》作为测试案例,通过识别小图标,模拟鼠标点击,快速完成配对。对于有兴趣学习游戏脚本的同学有一定的帮助。
运行环境:Win10/Python3.5。
主要模块:win32gui(识别窗口、窗口置顶等操作)、PIL(屏幕截图)、numpy(创建矩阵)、operator(比较值)、pymouse(模拟鼠标点击)。
注意点:
1、如果安装pymouse不成功或者运行报错,可以考虑先通过whl 安装pyHook、然后再通过pip安装pyuserinput。
2、如果报错 [ImportError: No module named ‘windows’ ],可以修改__init__.py相应的行 为 windows => pymouse.windows。
本文主要参考:https://baijiahao.baidu.com/s?
id=1618385402903335091&wfr=spider&for=pc。
一、开发前景
游戏辅助脚本在当前环境也算是比较流行了,对于经常玩游戏人来说,适当的游戏辅助还是很有帮助的,让计算机做一些繁琐乏味的操作。当然还有更加高大上的其他操作,这里就不赘述了。对于游戏辅助脚本,能想到基本有以下两种:一是读取游戏在内存中的数据,理想的话可以做到更改游戏一些基本属性,原理和很多的外挂或破解游戏类似;二是模拟用户用户行为,模拟鼠标点击、键盘操作等。当然,由于本人从未涉及游戏辅助脚本这一领域,出于个人兴趣,学习研究一下,本文例子则是第二种,主要还是模拟用户行为,让程序代替用户操作。
二、开发流程
先看看程序运行图吧:

浏览器打开游戏窗口(单个一个窗口),游戏界面如下图所示,游戏主要界面截图需要两个坐标(左上角坐标和右下角坐标)来确定,原点一般是屏幕左上角,不确定坐标点值的同学,可以全屏截图,用编辑图片软件查看坐标值。获取窗口句柄,这里就是浏览器标题栏的标题了(右键-查看源代码-title,加上软件名)比如:“宠物连连看经典2,宠物连连看经典版2小游戏,4399小游戏 www.4399.com - Google Chrome“。获取窗口句柄就可以开始了。
总体开发思路:截取游戏主图 —> 分割成小图 —> 对比每个小图,对比图片相识度,编号存入矩阵 —> 对矩阵进行可连计算 —> 模拟点击。

3.1、获取窗口句柄,把窗口置顶
python可以使用win32gui模块调用Windows API实现对窗口的操作,使用FindWindow()方法可以获取窗口的句柄(handle),需要传入两个参数,第一个为父窗口句柄(这里填0即可),第二个参数是窗口的名称(标签title - Google Chrome)。获取句柄之后然后通过SetForegroundWindows() 设置窗口在前面,这里传入游戏窗口的举报即可,代码如下:

3. 2、截取游戏界面,分割图标,图片比较
这里需要花费一些时间来校验程序,如果截取的图片不好,则会影响后续操作,所以比较主要的是确认游戏左上角和右下角这两个坐标值,以及每个小图标的宽高。如下图所示,先截取整个游戏界面图,然后分割小图标,接着对每个图标进行比较,然后以编号代替图标存入矩阵(这里的编号矩阵和游戏图不一致,原理一样)。

根据初始化设定的左上角和右下角两个坐标,使用ImageGrab.grab()方法进行截图,传入一个元组即可,然后对这个大图进行分割,切割成一个个小图标存入到images_list数组中。

通过上面代码切割的小图标,转成数字矩阵,如果图标已经存入image_type_list则返回这个索引,如果不存在,则在追加进去,然后当前长度就是这个新加入图标的编号,代码如下所示:

上面的getIndex就是对比图片,判断图标是否出现过(是否已存在image_type_list中,没出现则追加进去),这里使用汉明距离判断两个图片的相识度,设置阀值10,当小于阀值则认为是同一个图片,具体代码如下:

二、程序核心-图标连接算法(路径寻找)
这里仅对算法代码进行简单分析,如果对程序不好理解,可以留言,后续可以图文分析。
通过上面的开发流程,基本获取如下这样的矩阵,只要比较两个编号相同的值进行可连路径寻找,如果找到即进行模拟点击操作。这里简单介绍下游戏规则:8行乘12列游戏图标区域,外围的0其实表示寻找路径的时候可以通过,例如坐标(1, 1)可以与(1,10)进行连接、(7, 1)和(7,2)进行连接。

算法的思路:路径的寻找首先是寻找一个坐标的横向竖向可以直接相连的坐标集合,比如坐标p1(1,1)这样的集合有[ (0,1), (1,0) ],另外一个坐标p2(1,10)的可连集合为[ (0,10) ],然后再对p1和p2的可连坐标集合进行比较,如果集合中坐标也有可连,则表示p1和p2可连,很明显,(0,1)和(0,10)为同一行且可连,这样就表示p1和p2两点存在可连路径了,代码如下所示:
简单分析下代码实现过程:在isReachable()传入两个需要比较的坐标值,然后分别获取两个点横竖向(isRowConnect()、isColConnect())可以连接的坐标集合,最后再对集合进行遍历比较是否存在可连的,如果存在则表示传入的两个坐标是可以连接的。


四、开发总结
学习这样一个游戏辅助脚本,对于个人培养编程兴趣也是有很多帮助的,在工作之余不失为一个好的消遣方式,以后会多向这些方向研究学习。本案例仅仅是截图、比较图片和模拟鼠标点击,我觉得还可以更加强大,而且还不局限于游戏这样一个领域,相信大家应该见过自动发QQ消息的软件吧,我觉得这完全可以做。还有很多模拟操作可以实现:鼠标滚轮,左右键、键盘输入等。
五、源码
# -*- coding:utf-8 -*-import win32guiimport timefrom PIL import ImageGrab, Imageimport numpy as npimport operatorfrom pymouse import PyMouseclass GameAssist:def __init__(self, wdname):"""初始化"""# 取得窗口句柄self.hwnd = win32gui.FindWindow(0, wdname)if not self.hwnd:print("窗口找不到,请确认窗口句柄名称:【%s】" % wdname )exit()# 窗口显示最前面win32gui.SetForegroundWindow(self.hwnd)# 小图标编号矩阵self.im2num_arr = []# 主截图的左上角坐标和右下角坐标self.scree_left_and_right_point = (299, 251, 768, 564)# 小图标宽高self.im_width = 39# PyMouse对象,鼠标点击self.mouse = PyMouse()def screenshot(self):"""屏幕截图"""# 1、用grab函数截图,参数为左上角和右下角左标# image = ImageGrab.grab((417, 257, 885, 569))image = ImageGrab.grab(self.scree_left_and_right_point)# 2、分切小图# exit()image_list = {}offset = self.im_width # 39# 8行12列for x in range(8):image_list[x] = {}for y in range(12):# print("show",x, y)# exit()top = x * offsetleft = y * offsetright = (y + 1) * offsetbottom = (x + 1) * offset# 用crop函数切割成小图标,参数为图标的左上角和右下角左边im = image.crop((left, top, right, bottom))# 将切割好的图标存入对应的位置image_list[x][y] = imreturn image_listdef image2num(self, image_list):"""将图标矩阵转换成数字矩阵"""# 1、创建全零矩阵和空的一维数组arr = np.zeros((10, 14), dtype=np.int32) # 以数字代替图片image_type_list = []# 2、识别出不同的图片,将图片矩阵转换成数字矩阵for i in range(len(image_list)):for j in range(len(image_list[0])):im = image_list[i][j]# 验证当前图标是否已存入index = self.getIndex(im, image_type_list)# 不存在image_type_listif index < 0:image_type_list.append(im)arr[i + 1][j + 1] = len(image_type_list)else:arr[i + 1][j + 1] = index + 1print("图标数:", len(image_type_list))self.im2num_arr = arrreturn arr# 检查数组中是否有图标,如果有则返回索引下表def getIndex(self,im, im_list):for i in range(len(im_list)):if self.isMatch(im, im_list[i]):return ireturn -1# 汉明距离判断两个图标是否一样def isMatch(self, im1, im2):# 缩小图标,转成灰度image1 = im1.resize((20, 20), Image.ANTIALIAS).convert("L")image2 = im2.resize((20, 20), Image.ANTIALIAS).convert("L")# 将灰度图标转成01串,即系二进制数据pixels1 = list(image1.getdata())pixels2 = list(image2.getdata())avg1 = sum(pixels1) / len(pixels1)avg2 = sum(pixels2) / len(pixels2)hash1 = "".join(map(lambda p: "1" if p > avg1 else "0", pixels1))hash2 = "".join(map(lambda p: "1" if p > avg2 else "0", pixels2))# 统计两个01串不同数字的个数match = sum(map(operator.ne, hash1, hash2))# 阀值设为10return match < 10# 判断矩阵是否全为0def isAllZero(self, arr):for i in range(1, 9):for j in range(1, 13):if arr[i][j] != 0:return Falsereturn True# 是否为同行或同列且可连def isReachable(self, x1, y1, x2, y2):# 1、先判断值是否相同if self.im2num_arr[x1][y1] != self.im2num_arr[x2][y2]:return False# 1、分别获取两个坐标同行或同列可连的坐标数组list1 = self.getDirectConnectList(x1, y1)list2 = self.getDirectConnectList(x2, y2)
# print(x1, y1, list1)# print(x2, y2, list2)# exit()# 2、比较坐标数组中是否可连for x1, y1 in list1:for x2, y2 in list2:if self.isDirectConnect(x1, y1, x2, y2):return Truereturn False# 获取同行或同列可连的坐标数组def getDirectConnectList(self, x, y):plist = []for px in range(0, 10):for py in range(0, 14):# 获取同行或同列且为0的坐标if self.im2num_arr[px][py] == 0 and self.isDirectConnect(x, y, px, py):plist.append([px, py])return plist# 是否为同行或同列且可连def isDirectConnect(self, x1, y1, x2, y2):# 1、位置完全相同if x1 == x2 and y1 == y2:return False# 2、行列都不同的if x1 != x2 and y1 != y2:return False# 3、同行if x1 == x2 and self.isRowConnect(x1, y1, y2):return True# 4、同列if y1 == y2 and self.isColConnect(y1, x1, x2):return Truereturn False# 判断同行是否可连def isRowConnect(self, x, y1, y2):minY = min(y1, y2)maxY = max(y1, y2)# 相邻直接可连if maxY - minY == 1:return True# 判断两个坐标之间是否全为0for y0 in range(minY + 1, maxY):if self.im2num_arr[x][y0] != 0:return Falsereturn True# 判断同列是否可连def isColConnect(self, y, x1, x2):minX = min(x1, x2)maxX = max(x1, x2)# 相邻直接可连if maxX - minX == 1:return True# 判断两个坐标之间是否全为0for x0 in range(minX + 1, maxX):if self.im2num_arr[x0][y] != 0:return Falsereturn True# 点击事件并设置数组为0def clickAndSetZero(self, x1, y1, x2, y2):# print("click", x1, y1, x2, y2)# (299, 251, 768, 564)# 原理:左上角图标中点 + 偏移量p1_x = int(self.scree_left_and_right_point[0] + (y1 - 1)*self.im_width + (self.im_width / 2))p1_y = int(self.scree_left_and_right_point[1] + (x1 - 1)*self.im_width + (self.im_width / 2))p2_x = int(self.scree_left_and_right_point[0] + (y2 - 1)*self.im_width + (self.im_width / 2))p2_y = int(self.scree_left_and_right_point[1] + (x2 - 1)*self.im_width + (self.im_width / 2))time.sleep(0.2)self.mouse.click(p1_x, p1_y)time.sleep(0.2)self.mouse.click(p2_x, p2_y)# 设置矩阵值为0self.im2num_arr[x1][y1] = 0self.im2num_arr[x2][y2] = 0print("消除:(%d, %d) (%d, %d)" % (x1, y1, x2, y2))# exit()# 程序入口、控制中心def start(self):# 1、先截取游戏区域大图,然后分切每个小图image_list = self.screenshot()# 2、识别小图标,收集编号self.image2num(image_list)print(self.im2num_arr)# 3、遍历查找可以相连的坐标while not self.isAllZero(self.im2num_arr):for x1 in range(1, 9):for y1 in range(1, 13):if self.im2num_arr[x1][y1] == 0:continuefor x2 in range(1, 9):for y2 in range(1, 13):# 跳过为0 或者同一个if self.im2num_arr[x2][y2] == 0 or (x1 == x2 and y1 == y2):continueif self.isReachable(x1, y1, x2, y2):self.clickAndSetZero(x1, y1, x2, y2)if __name__ == "__main__":# wdname 为连连看窗口的名称,必须写完整wdname = u'宠物连连看经典版2,宠物连连看经典版2小游戏,4399小游戏 www.4399.com - Google Chrome'demo = GameAssist(wdname)demo.start()
GameAssist.py
总结
希望大家继续关注徐浪大讲堂!
相关文章:
【Python】如何用pyth做游戏脚本(太简单了吧)
文章目录 前言一、开发前景二、开发流程3.1、获取窗口句柄,把窗口置顶3. 2、截取游戏界面,分割图标,图片比较 二、程序核心-图标连接算法(路径寻找)四、开发总结五、源码总结 前言 简述:本文将以4399小游戏…...
【Linux】磁盘与文件系统
目录 一、磁盘的物理结构 二、磁盘逻辑抽象 三、文件系统 1、Super Block 2、Group Descriptor Table 3、inode Table 4、Data Blocks 5、inode Bitmap 6、Block Bitmap 四、Linux下文件系统 1、inode与文件名 2、文件的增删查改 2.1、查看文件内容 2.2、删除文件…...
Transformer中的注意力机制及代码
文章目录 1、简介2、原理2.1 什么是注意力机制2.2 注意力机制在NLP中解决了什么问题2.3 注意力机制公式解读2.4 注意力机制计算过程 3、单头注意力机制与多头注意力机制4、代码4.1 代码14.2 代码2 1、简介 最近在学习transformer,首先学习了多头注意力机制…...
ChatGPT在连续追问下对多线程和双重检查锁模式的理解--已经超越中级程序员
一、问: private static final Map<Method, GZHttpClientResultModel> CACHE_RESULT_MODEL new ConcurrentHashMap<>();public void abc(Method method){cacheResultMode(method);GZHttpClientResultModel model CACHE_RESULT_MODEL.get(method);}pr…...
每天一道大厂SQL题【Day22】华泰证券真题实战(四)
每天一道大厂SQL题【Day22】华泰证券真题实战(四) 大家好,我是Maynor。相信大家和我一样,都有一个大厂梦,作为一名资深大数据选手,深知SQL重要性,接下来我准备用100天时间,基于大数据岗面试中的经典SQL题&…...
【智能电网】智能电网中针对DOS和FDIA的弹性分布式EMA(Matlab代码实现)
💥💥💞💞欢迎来到本博客❤️❤️💥💥 🏆博主优势:🌞🌞🌞博客内容尽量做到思维缜密,逻辑清晰,为了方便读者。 ⛳️座右铭&a…...
IDEA 创建微服务项目实例
🎈 作者:Linux猿 🎈 简介:CSDN博客专家🏆,华为云享专家🏆,Linux、C/C++、云计算、物联网、面试、刷题、算法尽管咨询我,关注我,有问题私聊! 🎈 关注专栏:C/C++面试通关【精讲】 优质好文持续更新中……🚀🚀🚀 🎈 欢迎小伙伴们点赞👍、收藏⭐、留…...
注册苹果开发者账号的方法
在2020年以前,注册苹果开发者账号后,就可以生成证书。 但2020年后,因为注册苹果开发者账号需要使用Apple Developer app注册开发者账号,所以需要缴费才能创建ios证书了。 所以新政策出来后,注册苹果开发者账号&#…...
OpenCV2 计算机视觉应用编程秘籍:1~5
原文:OpenCV2 Computer Vision Application Programming Cookbook 协议:CC BY-NC-SA 4.0 译者:飞龙 本文来自【ApacheCN 计算机视觉 译文集】,采用译后编辑(MTPE)流程来尽可能提升效率。 当别人说你没有底线…...
Domino自带的JSON校验工具
大家好,才是真的好。 JSON数据在Notes/Domino已经变得非常重要。从Domino 10开始,在LotusScript语言中就加入了对JSON数据处理功能。在管理中,我们知道,从Domino 12版本开始就支持Domino自动化配置,也是使用JSON数据作…...
CentOS(linux)使用Docker安装nacos
1. 拉取nacos镜像 docker pull nacos/nacos-server:2.0.3 2. 创建所需文件夹(以安装在home目录下为例) 1) 创建conf文件夹 mkdir -p /home/nacos/conf a. 新增文件application.properties(或者不增加该文件,会使用默认的) 文件内容如下: # spring server.servlet.contextP…...
无线测温在线监测系统工作原理与产品选型
摘要:本文首先介绍了无线测温在线监测系统的基本工作原理以及软硬件组成,重点介绍了在线监测的无线测温技术特点。在此研究基础上,探讨了无线测温在线监测系统在实际工作场景中的应用案例,证明了其在温度检测方面的重要应用价值。…...
Nginx rewrite ——重写跳转
Nginx常见模块 http http块是Nginx服务器配置中的重要部分,代理、缓存和日志定义等绝大多数的功能和第三方模块的配置都可以放在这模块中。作用包括:文件引入、MIME-Type定义、日志自定义、是否使用sendfile传输文件、连接超时时间、单连接请求数上限等…...
【华为OD机试真题 C++】1038 - 全量和已占用字符集 | 机试题+算法思路+考点+代码解析
文章目录 一、题目🔸题目描述🔸输入输出🔸样例1二、代码参考作者:KJ.JK🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🌈 🍂个人博客首页: KJ.JK 💖系列专栏:华为OD机试真题(C++) 一、题目 🔸题目描述 所谓水仙花数,是指一个n位的正整数…...
网络中的网关和物联网的网关区别 局域网 路由器 交换机 服务器
网关:是个概念。连接两种不同的网络。例如局域网要与外部通信,需要经过网关。 设备和设备之间的通信,转换协议需要网关 路由器里有功能是对网关这个概念的实现。 所以网关它可以是路由器,交换机或者是PC。 路由器有网关功能&a…...
2023 年嵌入式世界的3 大趋势分析
目录 大家好,本文讲解了嵌入式发展的3个大趋势,分享给大家。 趋势#1 – Visual Studio Code Integration 趋势#2 –支持“现代”软件流程 趋势 #3 – 在设计中利用 AI 和 ML 结论 大家好,本文讲解了嵌入式发展的3个大趋势,分享…...
基于 DolphinDB 机器学习的出租车行程时间预测
DolphinDB 集高性能时序数据库与全面的分析功能为一体,可用于海量结构化数据的存储、查询、分析、实时计算等,在工业物联网场景中应用广泛。本文以纽约出租车行程时间预测为例,介绍如何使用 DolphinDB 训练机器学习模型,并进行实时…...
Python调用最小二乘法
文章目录 numpy实现scipy封装速度对比 所谓线性最小二乘法,可以理解为是解方程的延续,区别在于,当未知量远小于方程数的时候,将得到一个无解的问题。最小二乘法的实质,是保证误差最小的情况下对未知数进行赋值。 最小…...
15.数据表格.上
本节课我们来开始了解 Layui 的内置模块:table 数据表格。 一.基本使用 1. table 模块,通过异步加载数据来渲染表格来展现数据内容; <table id"table"></table> layui.use([table], () > { const table …...
在poetry虚拟环境下打包exe
本博客介绍了在poetry虚拟环境下打包exe的流程,包含两个部分 打包的基本流程打包过程中遇到的问题 打包的基本流程 copy打包工具到本地,(share:\公用共享\芯片部\乔羽\img_generate\系统部提供的打包exe工具) 用poetry搭建虚拟环境 在打包…...
可靠性+灵活性:电力载波技术在楼宇自控中的核心价值
可靠性灵活性:电力载波技术在楼宇自控中的核心价值 在智能楼宇的自动化控制中,电力载波技术(PLC)凭借其独特的优势,正成为构建高效、稳定、灵活系统的核心解决方案。它利用现有电力线路传输数据,无需额外布…...
在四层代理中还原真实客户端ngx_stream_realip_module
一、模块原理与价值 PROXY Protocol 回溯 第三方负载均衡(如 HAProxy、AWS NLB、阿里 SLB)发起上游连接时,将真实客户端 IP/Port 写入 PROXY Protocol v1/v2 头。Stream 层接收到头部后,ngx_stream_realip_module 从中提取原始信息…...
Android15默认授权浮窗权限
我们经常有那种需求,客户需要定制的apk集成在ROM中,并且默认授予其【显示在其他应用的上层】权限,也就是我们常说的浮窗权限,那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
Typeerror: cannot read properties of undefined (reading ‘XXX‘)
最近需要在离线机器上运行软件,所以得把软件用docker打包起来,大部分功能都没问题,出了一个奇怪的事情。同样的代码,在本机上用vscode可以运行起来,但是打包之后在docker里出现了问题。使用的是dialog组件,…...
基于TurtleBot3在Gazebo地图实现机器人远程控制
1. TurtleBot3环境配置 # 下载TurtleBot3核心包 mkdir -p ~/catkin_ws/src cd ~/catkin_ws/src git clone -b noetic-devel https://github.com/ROBOTIS-GIT/turtlebot3.git git clone -b noetic https://github.com/ROBOTIS-GIT/turtlebot3_msgs.git git clone -b noetic-dev…...
怎么让Comfyui导出的图像不包含工作流信息,
为了数据安全,让Comfyui导出的图像不包含工作流信息,导出的图像就不会拖到comfyui中加载出来工作流。 ComfyUI的目录下node.py 直接移除 pnginfo(推荐) 在 save_images 方法中,删除或注释掉所有与 metadata …...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现指南针功能
指南针功能是许多位置服务应用的基础功能之一。下面我将详细介绍如何在HarmonyOS 5中使用DevEco Studio实现指南针功能。 1. 开发环境准备 确保已安装DevEco Studio 3.1或更高版本确保项目使用的是HarmonyOS 5.0 SDK在项目的module.json5中配置必要的权限 2. 权限配置 在mo…...
聚六亚甲基单胍盐酸盐市场深度解析:现状、挑战与机遇
根据 QYResearch 发布的市场报告显示,全球市场规模预计在 2031 年达到 9848 万美元,2025 - 2031 年期间年复合增长率(CAGR)为 3.7%。在竞争格局上,市场集中度较高,2024 年全球前十强厂商占据约 74.0% 的市场…...
【iOS】 Block再学习
iOS Block再学习 文章目录 iOS Block再学习前言Block的三种类型__ NSGlobalBlock____ NSMallocBlock____ NSStackBlock__小结 Block底层分析Block的结构捕获自由变量捕获全局(静态)变量捕获静态变量__block修饰符forwarding指针 Block的copy时机block作为函数返回值将block赋给…...
