この記事では、4399 ミニゲーム「ペット連聯館クラシック エディション 2」をテスト ケースとして使用します。小さなアイコンを識別し、マウス クリックをシミュレートすることで、ペアリングをすばやく完了してゲーム スクリプトを完成させることができます。
ブラウザはゲーム ウィンドウ (単一ウィンドウ) を開きます。ゲームのメイン インターフェイスのスクリーンショットを決定するには、2 つの座標 (左上隅の座標と右下隅の座標) が必要です。原点は次のとおりです。一般的には画面の左上隅にあり、座標は不確かですが、学生は値をクリックすると、全画面のスクリーンショットを撮り、画像編集ソフトウェアを使用して座標値を表示できます。 (推奨される学習: Python ビデオ チュートリアル )
ウィンドウ ハンドルを取得します。これはブラウザのタイトル バーのタイトルです (右クリックしてソース コードを表示し、タイトルとソフトウェア名を加えます)。例: 「ペット Lianliankan Classic 2、Pet Lianliankan Classic Edition 2 ミニゲーム、4399 ミニゲーム www.4399.com - Google Chrome」。ウィンドウハンドルを取得すれば準備完了です。
全体的な開発アイデア: メインのゲーム画像をインターセプト---> 小さな画像に分割---> それぞれの小さな画像を比較し、画像の親しみやすさを比較し、その数値をマトリックスに保存します-- -> ペア行列 接続可能な計算を実行 ---> クリックをシミュレートします。
ウィンドウ ハンドルを取得し、ウィンドウを最前面に配置します。
Python は win32gui モジュールを使用して Windows API を呼び出し、ウィンドウを操作し、FindWindow() を使用できます。ウィンドウ ハンドル (ハンドル) を取得するメソッドでは、2 つのパラメーターを渡す必要があります。最初のパラメーターは親ウィンドウ ハンドル (ここでは 0 を入力するだけ)、2 番目のパラメーターはウィンドウの名前 (ラベル タイトル - Google Chrome) )。ハンドルを取得した後、SetForegroundWindows() を通じてウィンドウを前面に設定します。ここで、ゲーム ウィンドウのレポートを渡すことができます。コードは次のとおりです:
import win32gui class GameAssist: def __init__(self, wdname): """初始化""" # 取得窗口句柄 self.hwnd = win32gui.FindWindow(0, wdname) if not self.hwnd: print("窗口找不到,请确认窗口句柄名称:【%s】" % wdname ) exit() # 窗口显示最前面 win32gui.SetForegroundWindow(self.hwnd) if __name__ == "__main__": # wdname 为连连看窗口的名称,必须写完整 wdname = u'宠物连连看经典版2,宠物连连看经典版2小游戏,4399小游戏 www.4399.com - Google Chrome' demo = GameAssist(wdname) demo.start()
ゲーム インターフェイスをインターセプトし、
プログラムの検証には時間がかかりますが、撮影した画像が良くないとその後の動作に影響が出ますので、確認することが最も重要です。ゲームの左上隅と右下隅の座標値と、それぞれの小さなアイコンの幅と高さ。以下の図に示すように、まずゲーム インターフェイス図全体を切り取って、小さなアイコンを分割し、各アイコンを比較して、アイコンを数字に置き換えて行列に格納します (ここでの数字行列はゲームと一致しません)図、原理は同じです)。
初期化で設定された左上隅と右下隅の 2 つの座標に従って、ImageGrab.grab() メソッドを使用してスクリーンショットを取得し、タプルを渡し、セグメント化して、大きな画像を切り取って、images_list 配列の小さなアイコンに 1 つずつ保存します。
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 * offset left = y * offset right = (y + 1) * offset bottom = (x + 1) * offset # 用crop函数切割成小图标,参数为图标的左上角和右下角左边 im = image.crop((left, top, right, bottom)) # 将切割好的图标存入对应的位置 image_list[x][y] = im return image_list
上記のコードで切り取られた小さいアイコンは数値行列に変換されます。アイコンがimage_type_listに格納されている場合はインデックスが返され、存在しない場合は追加され、現在の長さは、新しく追加されたアイコンの番号になります。コードは次のとおりです:
def 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_list if index <p>上記の getIndex は、画像を比較し、アイコンが表示されているかどうか (image_type_list に既に存在するかどうか、ここでは、ハミング距離を使用して 2 つの画像の知り合いを判定します。度合い、しきい値を 10 に設定します。しきい値未満の場合は、しきい値と見なされます。具体的なコードは以下の通りです: </p><pre class="brush:php;toolbar:false"># 检查数组中是否有图标,如果有则返回索引下表 def getIndex(self,im, im_list): for i in range(len(im_list)): if self.isMatch(im, im_list[i]): return i return -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)) # 阀值设为10 return match <p>プログラムコアアイコン接続アルゴリズム(パス探索)</p><p>ここにアルゴリズムコードのみ 簡単な解析を実行します。プログラムをよく理解している場合は、メッセージを残してグラフィック分析でフォローアップできます。 </p><p>上記の開発プロセスにより、基本的には次のような行列が得られます。同じ番号を持つ 2 つの値を比較するだけで、接続可能なパスが見つかります。見つかった場合は、クリック操作をシミュレートします。ゲームのルールを簡単に紹介すると、ゲームアイコンのエリアは8行12列で、周囲の0は実はパスを探すときに通れるという意味で、例えば座標(1,1)は以下のようになります。 (1,10)に接続、(7,1)に接続 (7,2)に接続。 </p><pre class="brush:php;toolbar:false">arr = [ [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], [ 0, 1, 2, 3, 4, 5, 4, 6, 7, 2, 1, 1, 8, 0], [ 0, 9, 3, 3, 10, 4, 7, 11, 7, 2, 3, 1, 6, 0], [ 0, 6, 7, 4, 11, 5, 8, 1, 6, 5, 4, 2, 8, 0], [ 0, 6, 2, 9, 6, 8, 9, 7, 12, 11, 3, 11, 11, 0], [ 0, 5, 9, 8, 9, 2, 6, 11, 11, 3, 9, 2, 12, 0], [ 0, 12, 5, 12, 5, 10, 5, 6, 5, 7, 12, 4, 3, 0], [ 0, 1, 8, 10, 12, 9, 10, 4, 3, 7, 2, 1, 10, 0], [ 0, 1, 4, 10, 8, 12, 10, 10, 9, 12, 8, 7, 11, 0], [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0] ]
方法の考え方: パスを見つけるには、まず水平方向と垂直方向に直接接続できる座標のセットを見つけます。たとえば、座標のセット p1 (1,1)が [ (0,1), ( 1,0)] であり、別の座標 p2 (1,10) の接続可能な座標セットが [(0,10)] である場合、p1 と p2 の接続可能な座標セットを比較します。セット内には接続可能な座標もあります。これは、p1 と p2 が接続できることを意味します。明らかに、(0,1) と (0,10) は同じ線上にあり、接続できます。これは、接続可能なパスがあることを意味します
コード実装プロセスを簡単に分析します: isReachable() で比較する必要がある 2 つの座標値を渡し、次に、比較できる座標セットを取得します。水平方向と垂直方向の 2 つの点に接続し (isRowConnect()、isColConnect())、最後にコレクションをトラバースして、リンク可能なものが存在するかどうかを比較します。存在する場合は、入力された 2 つの座標を接続できることを意味します。
# 是否为同行或同列且可连 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 True return 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 True return False # 判断同行是否可连 def isRowConnect(self, x, y1, y2): minY = min(y1, y2) maxY = max(y1, y2) # 相邻直接可连 if maxY - minY == 1: return True # 判断两个坐标之间是否全为0 for y0 in range(minY + 1, maxY): if self.im2num_arr[x][y0] != 0: return False return True # 判断同列是否可连 def isColConnect(self, y, x1, x2): minX = min(x1, x2) maxX = max(x1, x2) # 相邻直接可连 if maxX - minX == 1: return True # 判断两个坐标之间是否全为0 for x0 in range(minX + 1, maxX): if self.im2num_arr[x0][y] != 0: return False return True
このようなゲーム補助スクリプトを学ぶことは、個人がプログラミングへの興味を養うのにも非常に役立ちます.仕事後の良い時間の過ごし方と考えることができます.私はこれらの方向でさらに勉強して学びたいと思っています.未来。
Python 関連の技術記事の詳細については、Python チュートリアル 列にアクセスして学習してください。
以上がPythonでゲームスクリプトを作る方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。