主页 > GUI教程 > 正文

一步步用python制造游戏外挂

玩过电脑游戏的同学关于外挂必定不生疏,可是你在用外挂的时分有没有想过怎样做一个外挂呢?(当然用外挂不是那么道义哈,呵呵),那咱们就来看一下怎样用python来制造一个外挂。。。。


我翻开了4399小游戏网,点开了一个不知名的游戏,唔,做寿司的,有资料在一边,客人过来后说出他们的要求,你依照菜单做好端给他便好~ 为啥这么有难度?8种菜单记不清,点点就点错,鼠标还不好使肌肉劳损啥的伤不起啊……


首先要声明,这儿的游戏外挂的概念,和那些大型网游里的外挂可不同,不能主动打怪,不能喝药不能逃避GM…… 那做这个外挂有啥用?问的好,没用,除了能够糟蹋你一点时刻,进步一下编程技能,添加一点点点点点点的做外挂的根底以外,毫无用处,假如您是以制造一个惊天地泣鬼神不开则已一开马上超神的外挂为方针过来的话,恐怕要让您绝望了,请及早绕道。我的意图很简略,便是主动玩这款小游戏罢了。


东西的预备


这篇文章需求您有Python根底,我不会解说Python语法啥的~


Python

需求装置autopy和PIL以及pywin32包。autopy是一个主动化操作的python库,能够模仿一些鼠标、键盘工作,还能对屏幕进行拜访,原本我想用win32api来模仿输入工作的,发现这个用起来比较简略,最厉害的是它是跨渠道的,请查找装置;而PIL那是大名鼎鼎了,Python图画处理的No.1,下面会阐明用它来做什么;pywin32其实不是有必要的,可是为了便利(鼠标它在自己动着呢,怎样完毕它呢),仍是主张装置一下,哦对了,我是在win渠道上做的,外挂大约只要windows用户需求吧?

截屏和图画处理东西

截屏是获取游戏图画以供剖析游戏提示,其实没有专门的东西直接Print Screen粘贴到图画处理东西里也能够。我用的是PicPick,适当好用,并且个人用户是免费的;而图画处理则是为了获取各种信息的,咱们要用它得到点菜图画后保存起来,供外挂剖析判别。我用的是PhotoShop… 不要告知Adobe,其实PicPick中自带的图画编辑器也足够了,只要能检查图画坐标和剪贴图片就好饿了,只不过我习气PS了~

编辑器

这个我就不必说了吧,写代码得要个编辑器啊!俺用VIM,您若乐意用写字板也能够……

原理剖析


外挂的前史啥的我不想说啦,有爱好请谷歌或度娘(注:非技能问题尽能够百度)。


看这个游戏,有8种菜,每种菜都有固定的做法,顾客一旦坐下来,头顶上就会有一个图片,看图片就知道他想关键什么菜,点击左面质料区域,然后点击一下……不知道叫什么,像个竹简相同的东西,菜就做完了,然后把做好的食物拖拽到客户面前就好了。


顾客头上显现图片的方位是固定的,一共也只要四个方位,咱们能够逐个剖析,而质料的方位也是固定的,每种菜的做法更是清清楚楚,这样一来咱们完全能够判别,程序能够很好的帮咱们做出一份一份的好菜并奉上,所以钱滚滚的来:)


autopy介绍


github上有一篇很不错的入门文章,尽管是英文可是很简略,不过我仍是摘几个这次用得到的阐明一下,以显现我很勤劳。


移动鼠标


import autopy

autopy.mouse.move(100, 100) # 移动鼠标

autopy.mouse.smooth_move(400, 400) # 滑润移动鼠标(上面那个是瞬间的)

这个指令会让鼠标敏捷移动到指定屏幕坐标,你知道什么是屏幕坐标的吧,左上角是(0,0),然后向右向下递加,所以1024×768屏幕的右下角坐标是……你猜对了,是(1023,767)。


不过有些不幸的,假如你实践用一下这个指令,然后用autopy.mouse.get_pos()取得一下当时坐标,发现它并不在(100,100)上,而是更小一些,比方我的机器上是(97,99),和分辨率有关。这个移动是用户了和windows中mouse_event函数,若不清楚api的,知道这回事就好了,便是这个坐标不是很准确的。像我相同很猎奇的,能够去读一下autopy的源码,我发现他核算肯定坐标算法有问题:


point.x *= 0xFFFF / GetSystemMetrics(SM_CXSCREEN);

这儿先做除法再做乘法,学过一点核算办法的就应该知道关于整数运算,应该先乘再除的,不然就会发生比较大的差错,假如他写成:


point.x = point.x * 0xffff / GetSystemMetrics(SM_CXSCREEN);

就会准多了,尽管理论上会慢一点点,不过我也懒得改代码从头编译了,差几个像素,这儿对咱们影响不大~咱要吸取教训呀。


点击鼠标


import autopy

autopy.mouse.click() # 单击

autopy.mouse.toggle(True) # 按下左键

autopy.mouse.toggle(False) # 松开左键

这个比较简略,不过记住这儿的操作都是十分十分快的,有或许游戏还没反响过来呢,你就完成了,所以失利了…… 所以必要的时分,请sleep一小会儿。


键盘操作


咱们这次没用到键盘,所以我就不说了。

怎样做?剖析顾客头上的图画就能够,来,从获取图画开端吧~




翻开你宠爱的图画编辑器,开端测量吧~ 咱们得知道图画在屏幕的具体方位,能够用标尺量出来,原本直接量也是能够的,可是我这儿运用了画面左上角的方位(也便是点1)来作为参阅方位,这样一旦画面有变化,咱们只需求修正一个点坐标就好了,不然每一个点都需求从头写一遍可不是一件高兴的工作。


看最左面的顾客头像上面的图画,咱们需求两个点才可确认这个规模,分别是图画的左上角和右下角,也便是点2和点3,。后边还有三个顾客的方位,只需求简略的加上一个增量就好了,for循环便是为此而生!


相同的,咱们质料的方位,“竹席”的方位等等,都能够用这种办法取得。留意取得的都是相对游戏画面左上角的相对方位。至于抓图的办法,PIL的ImageGrab就很好用,autopy也能够抓图,为什么不必,我下面就会提到。


剖析图画


咱们这个外挂里适当有难度的一个问题出现了,怎样知道咱们取得的图画到底是哪一个菜?对人眼……乃至狗眼来说,这都是一个适当easy的问题,“一看就知道”!对的,这便是人比机器高超的当地,咱们做起来很简略的工作,电脑却傻傻分不清楚。

autopy图画限制


假如你看过autopy的api,会发现它有一个bitmap包,里边有find_bitmap办法,便是在一个大图画里寻觅样品小图画的。聪明的你必定能够想到,咱们能够截下整个游戏画面,然后预备一切的菜的小图画用这个办法一找就理解哪个菜被叫到了。的确,一开端我也有这样做的激动,不过马上就抛弃了……这个办法查找图画,速度先不说,它有个条件是“准确匹配”,图画上有一个像素的RGB值差了1,它就查不出来了。咱们知道flash是矢量绘图,它把一个点阵图片显现在屏幕上是经过了缩放的,这儿变数就很大,理论上相同的输入相同的算法得出的成果必定是共同的,可是由于绘图布景等的联系,总会有一点点的间隔,便是这点间隔使得这个美好的函数不行运用了……


好吧,不能用也是功德,不然我怎样引出咱们高超的图画剖析算法呢?


类似图画查找原理


相信你必定用过Google的“按图搜图”功用,假如没有,你就掉队啦,快去试试!当你输入一张图片时,它会把与这张图类似的图画都给你出现出来,所以当你找到一张中意的图想做壁纸又觉得太小的时分,根本能够用这个办法找到适宜的~


咱们就要运用和这个类似的原理来判别用户的点餐,当然咱们的算法不或许和Google那般杂乱,知乎上有一篇很不错的文章描绘了这个问题,有爱好的能够看看,我直接给出完成:


   def get_hash(self, img):

       image = img.resize((18, 13), Image.ANTIALIAS).convert("L")

       pixels = list(image.getdata())

       avg = sum(pixels) / len(pixels)

       return "".join(map(lambda p : "1" if p > avg else "0", pixels))

由于这是类的一个办法,所以有个self参数,无视它。这儿的img应该传入一个Image目标,能够使读入图画文件后的成果,也能够是截屏后的成果。而缩放的尺度(18,13)是我依据实践情况定的,由于顾客头像上的菜的图画根本便是这个份额。事实证明这个份额仍是挺重要的,由于咱们的菜有点儿类似,假如份额不适宜紧缩后就失真了,简略误判(我之前就吃亏了)。


得到一个图片的“指纹”后,咱们就能够与规范的图片指纹比较,怎样比较呢,应该运用“汉明间隔”,也便是两个字符串对应方位的不同字符的个数。完成也很简略……


   def hamming_dist(self, hash1, hash2):

       return sum(itertools.imap(operator.ne, hash1, hash2))

好了,咱们能够用预备好的规范图画,然后预先读取核算特征码存储起来,然后再截图与它们比较就好了,间隔最小的那个便是对应的菜,代码如下:


   def order(self, i):

       l, t = self.left + i * self.step, self.top

       r, b = l + self.width, t + self.height

       hash2 = self.get_hash(ImageGrab.grab((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.recipes = [None] * 8

       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):

       self.recipes[0] = (1, 2)

       self.recipes[1] = (0, 1, 2)

       self.recipes[2] = (5, 1, 2)

       self.recipes[3] = (3, 0, 1, 2)

       self.recipes[4] = (4, 1, 2)

       self.recipes[5] = (7, 1, 2)

       self.recipes[6] = (6, 1, 2)

       self.recipes[7] = (8, 1, 2)

   def click(self, i):

       autopy.mouse.move(self.stuff_pos[i][0] + 20, self.stuff_pos[i][1] + 20)

       autopy.mouse.click()

   def make(self, i):

       for x in self.recipes[i]:

           self.click(x)

       autopy.mouse.move(L + 315, T + 363)

       autopy.mouse.click()


这是本外挂中最没技能含量的一个类了:)请原谅我没有写注释和doc,由于都很简略,相信你懂得。

上一篇:wxPython运用delayedresult进行耗时核算
下一篇:用wx888真人赌博GUI第一个示例解说

PythonTab微信大众号:

Python技能交流合作群 ( 请勿加多个群 ):

群1: 87464755

群2: 333646237

群3: 318130924

群4: 385100854