使⽤Python开发windows桌⾯程序
这篇⽂章需要您有Python基础,我不会讲解Python语法啥的~
Python
lambda函数lisp需要安装autopy和PIL以及pywin32包。autopy是⼀个⾃动化操作的python库,可以模拟⼀些⿏标、键盘事件,还能对屏幕进⾏访问,本来我想⽤win32api来模拟输⼊事件的,发现这个⽤起来⽐较简单,No.1,下⾯会说明⽤它来做什么;pywin32其实不是必须的,但是为了⽅便(⿏标它在⾃⼰动着呢,如何结束它呢),还是建议安装⼀下,哦对了,我是在win平台上做的,外挂⼤概只有windows⽤户需要截屏和图像处理⼯具
截屏是获取游戏图像以供分析游戏提⽰,其实没有专门的⼯具直接Print Screen粘贴到图像处理⼯具⾥也可以。我⽤的是PicPick,相当好⽤,⽽且个⼈⽤户是免费的;⽽图像处理则是为了获取各种信息告诉Adobe,其实PicPick中⾃带的图像编辑器也⾜够了,只要能查看图像坐标和剪贴图⽚就好饿了,只不过我习惯PS了~
编辑器
这个我就不⽤说了吧,写代码得要个编辑器啊!俺⽤VIM,您若愿意⽤写字板也可以……
原理分析
外挂的历史啥的我不想说啦,有兴趣请⾕歌或度娘(注:⾮技术问题尽可以百度)。
看这个游戏,有8种菜,每种菜都有固定的做法,顾客⼀旦坐下来,头顶上就会有⼀个图⽚,看图⽚就知道他想要点什么菜,点击左边原料区域,然后点击⼀下……不知道叫什么,像个⽵简⼀样的东西,
顾客头上显⽰图⽚的位置是固定的,总共也只有四个位置,我们可以逐⼀分析,⽽原料的位置也是固定的,每种菜的做法更是清清楚楚,这样⼀来我们完全可以判断,程序可以很好的帮我们做出⼀份⼀autopy介绍
github上有⼀篇很不错的⼊门⽂章,虽然是英⽂但是很简单,不过我还是摘⼏个这次⽤得到的说明⼀下,以显⽰我很勤劳。
移动⿏标
import autopy
fifth
这个命令会让⿏标迅速移动到指定屏幕坐标,你知道什么是屏幕坐标的吧,左上⾓是(0,0),然后向右向下递增,所以1024×768屏幕的右下⾓坐标是……你猜对了,是(1023,767)。
不过有些不幸的,如果你实际⽤⼀下这个命令,然后⽤_pos()获得⼀下当前坐标,发现它并不在(100,100)上,⽽是更⼩⼀些,⽐如我的机器上是(97,99),和分辨率有关。这个移动是标不是很精确的。像我⼀样很好奇的,可以去读⼀下autopy的源码,我发现他计算绝对坐标算法有问题:
point.x *= 0xFFFF / GetSystemMetrics(SM_CXSCREEN);
这⾥先做除法再做乘法,学过⼀点计算⽅法的就应该知道对于整数运算,应该先乘再除的,否则就会产⽣⽐较⼤的误差,如果他写成:
point.x = point.x * 0xffff / GetSystemMetrics(SM_CXSCREEN);
就会准多了,虽然理论上会慢⼀点点,不过我也懒得改代码重新编译了,差⼏个像素,这⾥对我们影响不⼤~咱要吸取教训呀。
点击⿏标
import autopy
这个⽐较简单,不过记得这⾥的操作都是⾮常⾮常快的,有可能游戏还没反应过来呢,你就完成了,于是失败了…… 所以必要的时候,请sleep⼀⼩会⼉。
键盘操作
我们这次没⽤到键盘,所以我就不说了。
怎么做?分析顾客头上的图像就可以,来,从获取图像开始吧~
打开你钟爱的图像编辑器,开始丈量吧~ 我们得知道图像在屏幕的具体位置,可以⽤标尺量出来,本来直接量也是可以的,但是我这⾥使⽤了画⾯左上⾓的位置(也就是点1)来当做参考位置,这样⼀⼀件快乐的事情。python基础代码写字
看最左边的顾客头像上⾯的图像,我们需要两个点才可确定这个范围,分别是图像的左上⾓和右下⾓,
也就是点2和点3,。后⾯还有三个顾客的位置,只需要简单的加上⼀个增量就好了,for循环就是为此
同样的,我们原料的位置,“⽵席”的位置等等,都可以⽤这种⽅法获得。注意获得的都是相对游戏画⾯左上⾓的相对位置。⾄于抓图的⽅法,PIL的ImageGrab就很好⽤,autopy也可以抓图,为什么不⽤分析图像
我们这个外挂⾥相当有难度的⼀个问题出现了,如何知道我们获得的图像到底是哪⼀个菜?对⼈眼……甚⾄狗眼来说,这都是⼀个相当easy的问题,“⼀看就知道”!对的,这就是⼈⽐机器⾼明的地⽅,我autopy图像局限
如果你看过autopy的api,会发现它有⼀个bitmap包,⾥⾯有find_bitmap⽅法,就是在⼀个⼤图像⾥寻样品⼩图像的。聪明的你⼀定可以想到,我们可以截下整个游戏画⾯,然后准备所有的菜的⼩图像放弃了……这个⽅法查图像,速度先不说,它有个条件是“精确匹配”,图像上有⼀个像素的RGB值差了1,它就查不出来了。我们知道flash是⽮量绘图,它把⼀个点阵图⽚显⽰在屏幕上是经过了缩放的图背景等的关系,总会有⼀点点的差距,就是这点差距使得这个美妙的函数不可使⽤了……
一般属性克制什么属性图背景等的关系,总会有⼀点点的差距,就是这点差距使得这个美妙的函数不可使⽤了……
好吧,不能⽤也是好事,否则我怎么引出我们⾼明的图像分析算法呢?
相似图像查原理
相信你⼀定⽤过Google的“按图搜图”功能,如果没有,你就落伍啦,快去试试!当你输⼊⼀张图⽚时,它会把与这张图相似的图像都给你呈现出来,所以当你到⼀张中意的图想做壁纸⼜觉得太⼩的时
我们就要利⽤和这个相似的原理来判断⽤户的点餐,当然我们的算法不可能和Google那般复杂,知乎上有⼀篇很不错的⽂章描述了这个问题,有兴趣的可以看看,我直接给出实现:
def get_hash(self, img):
image = size((18, 13), Image.ANTIALIAS).convert("L")
pixels = data())
avg = sum(pixels) / len(pixels)
return "".join(map(lambda p : "1" if p > avg else "0", pixels))
因为这是类的⼀个⽅法,所以有个self参数,⽆视它。这⾥的img应该传⼊⼀个Image对象,可以使读设计模式 socket编程
⼊图像⽂件后的结果,也可以是截屏后的结果。⽽缩放的尺⼨(18,13)是我根据实际情况定的,因为菜有点⼉相似,如果⽐例不合适压缩后就失真了,容易误判(我之前就吃亏了)。
得到⼀个图⽚的“指纹”后,我们就可以与标准的图⽚指纹⽐较,怎么⽐较呢,应该使⽤“汉明距离”,也就是两个字符串对应位置的不同字符的个数。实现也很简单……
def hamming_dist(self, hash1, hash2):
return sum(itertools., hash1, hash2))
gradle文件是什么好了,我们可以⽤准备好的标准图像,然后预先读取计算特征码存储起来,然后再截图与它们⽐较就好了,距离最⼩的那个就是对应的菜,代码如下:
def order(self, i):
l, t = self.left + i * self.step, p
r, b = l + self.width, t + self.height
hash2 = _ab((l, t, r, b)))
(mi, dist) = None, 50
for i, hash1 in enumerate(self.maps):
if hash1 is None:
continue
this_dist = self.hamming_dist(hash1, hash2)
if this_dist < dist:
mi = i
dist = this_dist
return mi
这⾥有⼀个50的初始距离,如果截取图像与任何菜单相⽐都⼤于50,说明什么?说明现在那个位置的图像不是菜,也就是说顾客还没坐那位置上呢,或者我们把游戏最⼩化了(⽼板来了),这样处理很
⾃动做菜
这个问题很简单,我们只需要把菜单的原料记录在案,然后点击相应位置便可,我把它写成了⼀个类来调⽤:
class Menu:
def __init__(self):
self.stuff_pos = []
self.init_stuff()
self.init_recipe()
def init_stuff(self):
for i in range(9):
self.stuff_pos.append( (L + 102 + (i % 3) * 42, T + 303 + (i / 3) * 42) )
def init_recipe(self):
def click(self, i):
def make(self, i):
for x ipes[i]:
self.click(x)
这是本外挂中最没技术含量的⼀个类了:)请原谅我没有写注释和doc,因为都很简单,相信你懂得。作者:andyliulin 发表于 2017/10/26 11:51:41 blog.csdn/andyliulin/article/details/78352027
阅读:490
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论