Make a game plug-in with python step by step

Welcome to join the Python learning exchange QQ group: 535993938 Gossip is prohibited! limited spots! Do not enter if you are not happy!

Students who have played computer games are definitely not unfamiliar with plug-ins, but have you ever thought about how to make a plug-in when you use a plug-in? (Of course, using a plug-in is not so moral, ha ha), then let's take a look at how to use python to make a plug-in. . . .

I opened the 4399 mini game website and clicked on an unknown game. Well, the sushi maker has ingredients on the side. After the guests come over, they say their requirements. Just follow the menu and serve it to him~ Why? So difficult? I can't remember 8 kinds of menus, I click the wrong one, the mouse is not good enough to cause muscle strain or something...

First of all, I have to declare that the concept of game plug-ins here is different from the plug-ins in those large-scale online games. Good question, it's useless. It's useless except to waste a little time, improve your programming skills, and add a little bit of the foundation for plug-ins. If you come here with the goal of immediately superseding the gods, I am afraid you will be disappointed, please detour as soon as possible. My purpose is very simple, just play this little game automatically.

Preparation of tools

Requires autopy and PIL and pywin32 packages to be installed. Autopy is a python library for automated operations. It can simulate some mouse and keyboard events, and can also access the screen. Originally, I wanted to use win32api to simulate input events. I found this to be relatively simple to use. The most powerful thing is that it is cross-platform. Yes, please search and install; and PIL is well-known, the No.1 of Python image processing, the following will explain what it is used for; pywin32 is not necessary, but for convenience (the mouse is moving by itself, how to end it ), it is recommended to install it, oh right, I did it on the win platform, and the plug-in is probably only needed by windows users, right?
Screenshot and Image Processing Tool
Screenshot is to obtain game images for analysis of game prompts. In fact, there is no special tool to directly print Screen and paste it into the image processing tool. I use PicPick, which is very easy to use, and free for individual users; and image processing is to obtain various information, we use it to get the order image and save it for external analysis and judgment. I'm using PhotoShop... Don't tell Adobe, in fact, the image editor that comes with PicPick is enough, as long as you can view image coordinates and clips, I'm hungry, but I'm used to PS~ I don't need to say about the
editor
Well, you need an editor to write code! I use VIM, you can also use WordPad if you like...
Principle analysis

I don't want to talk about the history of plug-ins. If you are interested, please ask Google or Du Niang (Note: Baidu can be used for non-technical problems).

Looking at this game, there are 8 kinds of dishes, and each dish has a fixed recipe. Once the customer sits down, there will be a picture above his head, look at the picture to know what dish he wants to order, click on the ingredients area on the left, and then click… ...I don't know what it's called, it's like a bamboo slip, the dishes are done, and then the finished food is dragged to the customer.

The position of the picture displayed on the customer's head is fixed, and there are only four positions in total. We can analyze them one by one, and the position of the raw materials is also fixed, and the practice of each dish is clearer, so we can fully judge, The program can help us make a delicious meal and serve it, so the money is coming :)

Introduction to autopy

github上有一篇很不错的入门文章,虽然是英文但是很简单,不过我还是摘几个这次用得到的说明一下,以显示我很勤劳。

移动鼠标

1 import autopy
2 autopy.mouse.move(100, 100) # 移动鼠标
3 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);
就会准多了,虽然理论上会慢一点点,不过我也懒得改代码重新编译了,差几个像素,这里对我们影响不大~咱要吸取教训呀。

点击鼠标

1 #引入autopy模块
2 # ***
3 import autopy
4 autopy.mouse.click() # 单击
5 autopy.mouse.toggle(True) # 按下左键
6 autopy.mouse.toggle(False) # 松开左键

 

这个比较简单,不过记得这里的操作都是非常非常快的,有可能游戏还没反应过来呢,你就完成了,于是失败了…… 所以必要的时候,请sleep一小会儿。

键盘操作

我们这次没用到键盘,所以我就不说了。
怎么做?分析顾客头上的图像就可以,来,从获取图像开始吧~

打开你钟爱的图像编辑器,开始丈量吧~ 我们得知道图像在屏幕的具体位置,可以用标尺量出来,本来直接量也是可以的,但是我这里使用了画面左上角的位置(也就是点1)来当做参考位置,这样一旦画面有变动,我们只需要修改一个点坐标就好了,否则每一个点都需要重新写一遍可不是一件快乐的事情。

看最左边的顾客头像上面的图像,我们需要两个点才可确定这个范围,分别是图像的左上角和右下角,也就是点2和点3,。后面还有三个顾客的位置,只需要简单的加上一个增量就好了,for循环就是为此而生!

同样的,我们原料的位置,“竹席”的位置等等,都可以用这种方法获得。注意获得的都是相对游戏画面左上角的相对位置。至于抓图的方法,PIL的ImageGrab就很好用,autopy也可以抓图,为什么不用,我下面就会说到。

分析图像

我们这个外挂里相当有难度的一个问题出现了,如何知道我们获得的图像到底是哪一个菜?对人眼……甚至狗眼来说,这都是一个相当easy的问题,“一看就知道”!对的,这就是人比机器高明的地方,我们做起来很简单的事情,电脑却傻傻分不清楚。
autopy图像局限

如果你看过autopy的api,会发现它有一个bitmap包,里面有find_bitmap方法,就是在一个大图像里寻找样品小图像的。聪明的你一定可以想到,我们可以截下整个游戏画面,然后准备所有的菜的小图像用这个方法一找就明白哪个菜被叫到了。确实,一开始我也有这样做的冲动,不过立刻就放弃了……这个方法查找图像,速度先不说,它有个条件是“精确匹配”,图像上有一个像素的RGB值差了1,它就查不出来了。我们知道flash是矢量绘图,它把一个点阵图片显示在屏幕上是经过了缩放的,这里变数就很大,理论上相同的输入相同的算法得出的结果肯定是一致的,但是因为绘图背景等的关系,总会有一点点的差距,就是这点差距使得这个美妙的函数不可使用了……

好吧,不能用也是好事,否则我怎么引出我们高明的图像分析算法呢?

相似图像查找原理

相信你一定用过Google的“按图搜图”功能,如果没有,你就落伍啦,快去试试!当你输入一张图片时,它会把与这张图相似的图像都给你呈现出来,所以当你找到一张中意的图想做壁纸又觉得太小的时候,基本可以用这个方法找到合适的~

我们就要利用和这个相似的原理来判断用户的点餐,当然我们的算法不可能和Google那般复杂,知乎上有一篇很不错的文章描述了这个问题,有兴趣的可以看看,我直接给出实现:

1 def get_hash(self, img):
2     #使用PIL模块缩放图片,***
3     image = img.resize((18, 13), Image.ANTIALIAS).convert("L")
4     pixels = list(image.getdata())
5     avg = sum(pixels) / len(pixels)
6     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))
好了,我们可以用准备好的标准图像,然后预先读取计算特征码存储起来,然后再截图与它们比较就好了,距离最小的那个就是对应的菜,代码如下:

copy code
 1    def order(self, i):
 2        l, t = self.left + i * self.step, self.top
 3        r, b = l + self.width, t + self.height
 4        hash2 = self.get_hash(ImageGrab.grab((l, t, r, b)))
 5        (mi, dist) = None, 50
 6        for i, hash1 in enumerate(self.maps):
 7            if hash1 is None:
 8                continue
 9            this_dist = self.hamming_dist(hash1, hash2)
10            if this_dist < dist:
11                mi = i
12                dist = this_dist
13        return mi
copy code

 


这里有一个50的初始距离,如果截取图像与任何菜单相比都大于50,说明什么?说明现在那个位置的图像不是菜,也就是说顾客还没坐那位置上呢,或者我们把游戏最小化了(老板来了),这样处理很重要,免得它随意找一个最相近但又完全不搭边的菜进行处理。

自动做菜

这个问题很简单,我们只需要把菜单的原料记录在案,然后点击相应位置便可,我把它写成了一个类来调用:

copy code
 1 class Menu:
 2    def __init__(self):
 3        self.stuff_pos = []
 4        self.recipes = [None] * 8
 5        self.init_stuff()
 6        self.init_recipe()
 7    def init_stuff(self):
 8        for i in range(9):
 9            self.stuff_pos.append( (L + 102 + (i % 3) * 42, T + 303 + (i / 3) * 42) )
10    def init_recipe(self):
11        self.recipes[0] = (1, 2)
12        self.recipes[1] = (0, 1, 2)
13        self.recipes[2] = (5, 1, 2)
14        self.recipes[3] = (3, 0, 1, 2)
15        self.recipes[4] = (4, 1, 2)
16        self.recipes[5] = (7, 1, 2)
17        self.recipes[6] = (6, 1, 2)
18        self.recipes[7] = (8, 1, 2)
19    def click(self, i):
20        autopy.mouse.move(self.stuff_pos[i][0] + 20, self.stuff_pos[i][1] + 20)
21        autopy.mouse.click()
22    def make(self, i):
23        for x in self.recipes[i]:
24            self.click(x)
25        autopy.mouse.move(L + 315, T + 363)
26        autopy.mouse.click()
copy code

 

This is the least technical class in this plug-in :) Please forgive me for not writing comments and doc, because it is very simple, I believe you understand.

Welcome to join the Python learning exchange QQ group: 535993938 Gossip is prohibited! limited spots! Do not enter if you are not happy!

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=324520175&siteId=291194637