【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搭建虚拟环境 在打包…...

利用最小二乘法找圆心和半径
#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …...

MPNet:旋转机械轻量化故障诊断模型详解python代码复现
目录 一、问题背景与挑战 二、MPNet核心架构 2.1 多分支特征融合模块(MBFM) 2.2 残差注意力金字塔模块(RAPM) 2.2.1 空间金字塔注意力(SPA) 2.2.2 金字塔残差块(PRBlock) 2.3 分类器设计 三、关键技术突破 3.1 多尺度特征融合 3.2 轻量化设计策略 3.3 抗噪声…...

突破不可导策略的训练难题:零阶优化与强化学习的深度嵌合
强化学习(Reinforcement Learning, RL)是工业领域智能控制的重要方法。它的基本原理是将最优控制问题建模为马尔可夫决策过程,然后使用强化学习的Actor-Critic机制(中文译作“知行互动”机制),逐步迭代求解…...
在鸿蒙HarmonyOS 5中实现抖音风格的点赞功能
下面我将详细介绍如何使用HarmonyOS SDK在HarmonyOS 5中实现类似抖音的点赞功能,包括动画效果、数据同步和交互优化。 1. 基础点赞功能实现 1.1 创建数据模型 // VideoModel.ets export class VideoModel {id: string "";title: string ""…...

23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...

Swift 协议扩展精进之路:解决 CoreData 托管实体子类的类型不匹配问题(下)
概述 在 Swift 开发语言中,各位秃头小码农们可以充分利用语法本身所带来的便利去劈荆斩棘。我们还可以恣意利用泛型、协议关联类型和协议扩展来进一步简化和优化我们复杂的代码需求。 不过,在涉及到多个子类派生于基类进行多态模拟的场景下,…...

HBuilderX安装(uni-app和小程序开发)
下载HBuilderX 访问官方网站:https://www.dcloud.io/hbuilderx.html 根据您的操作系统选择合适版本: Windows版(推荐下载标准版) Windows系统安装步骤 运行安装程序: 双击下载的.exe安装文件 如果出现安全提示&…...
什么?连接服务器也能可视化显示界面?:基于X11 Forwarding + CentOS + MobaXterm实战指南
文章目录 什么是X11?环境准备实战步骤1️⃣ 服务器端配置(CentOS)2️⃣ 客户端配置(MobaXterm)3️⃣ 验证X11 Forwarding4️⃣ 运行自定义GUI程序(Python示例)5️⃣ 成功效果
处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的
修改bug思路: 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑:async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...
Java数值运算常见陷阱与规避方法
整数除法中的舍入问题 问题现象 当开发者预期进行浮点除法却误用整数除法时,会出现小数部分被截断的情况。典型错误模式如下: void process(int value) {double half = value / 2; // 整数除法导致截断// 使用half变量 }此时...