Goodgame Empire自动攻击机器人
#python #opencv #computervision #script

你好呀,

查看机器人视频,以了解该机器人的工作原理link here

要遵循本指南,请克隆项目 from here

第113至613行的所有代码都与GUI有关(以您自身的风险阅读,因为本指南不会在此处解释)。

本指南将通过615到1015的行。

在第615行 中,您可以看到函数“运行”包含几个功能定义,这些函数定义充当“助手”功能,以帮助繁琐的bot工作,例如:

(第616行)

       def find_object(file):
            img = pag.screenshot()
            img = img.convert('RGB')
            img = np.array(img)
            img_rgb = img[:, :, ::-1].copy()
            img_gray = cv.cvtColor(img_rgb, cv.COLOR_BGR2GRAY)
            template = cv.imread("objects/" + file,0)
            w, h = template.shape[::-1]

            res = cv.matchTemplate(img_gray,template,cv.TM_SQDIFF_NORMED)
            mn,_,mnLoc,_ = cv.minMaxLoc(res)

            print(file, "->", mn)

            if mn < 0.007:
                return mnLoc
            else:
                return False

'Find_Object'函数,进行游戏的屏幕截图,并试图在该屏幕截图内找到图像“文件”,使用此功能是在游戏屏幕中找到游戏对象。

函数从616到700,都是“助手”功能,其中大多数使用库pyautogui库,而pyautogui则短于代码中的“ pag”,pyautogui提供的功能提供了使用键盘移动鼠标并输入键盘的功能(read pyautogui读取pyautogui了解这些功能如何工作)。

功能从700到930,都是“任务”功能,它使用Pyautogui函数和“助手”功能的组合来执行游戏内任务(将在下面说明)。

然后,我们继续进行前循环初始化:

(第931行)

        castle = 1
        max = (4 if i > 1 else 10)
        cur_task = 0
        tasks = {
            0 : lambda : selector(i),
            1 : lambda : enter_target_info(ALL[i]["C" + str(castle) + "_x"], ALL[i]["C" + str(castle) + "_y"]),
            2 : lambda : open_attackWin(),
            3 : lambda : select_preset(int(ALL[i]['Slot'])),
            4 : lambda : apply_preset(),
            5 : lambda : attack(),
            6 : lambda : select_speedup(i)
        }

在这里,变量“城堡”是要从(GUI中的10个记录的城堡)开始的城堡号。

“ max”是要使用的最大城堡数量。

“ cur_task”是一个索引变量,可以跟踪当前运行任务。

“任务”是游戏中任务的字典,应按顺序完成,以获得成功的城堡攻击。

任务0-选择器(i)功能

(第895行)

        def selector(i):
            if i > 1 and not self.firstRotation:
                return extinguish(ALL[i]["C" + str(castle) + "_x"], ALL[i]["C" + str(castle) + "_y"])
            elif i <= 1 and not self.firstRotation:
                return waitFor_reappear(ALL[i]["C" + str(castle) + "_x"], ALL[i]["C" + str(castle) + "_y"])
            else:
                sleep(5)
                return True

此任务作业是在可能的情况下熄灭攻击城堡,如果没有,它将等待城堡重新出现,但此任务被称为首先称为,尽管它直到机器人完成攻击后才实际使用,因此它可以使用,因为它不会执行第一个旋转中的两个功能之一。

任务1- enter_target_info(a,b)功能

(第659行)

        def enter_target_info(x, y):
            press("tab")
            pag.write(x)
            press("tab")
            pag.write(y)
            press("enter")
            sleep(0.5)
            press("tab")
            pag.write(x)
            press("tab")
            pag.write(y)
            press("enter")
            sleep(1)

            if findClick_object("target.bmp") == False: return False

            return repeat(lambda: find_object("success_targselect.bmp"), True)

使用pyautogui,pynput。

然后单击“ target.bmp”对象,打开攻击对话框。

它还检查了攻击对话框是否打开,并将其返回为布尔。

任务2 -Open_attackwin()函数

(第904行)

        def open_attackWin():
            if findClick_object("confirm.bmp") == False: return False

            sleep(2)

            return repeat(lambda: find_object("use_preset.bmp"), True)

此任务单击“攻击”对话框上的确认按钮,以打开“攻击设置”窗口。

然后检查攻击设置窗口是否打开,并将其返回为布尔。

任务3 -select_preset(i)函数

(第685行)

        def select_preset(i):
            cords = find_object("drop_preset.bmp")

            if cords == False: return False

            click(cords[0] - 50, cords[1] + 60)
            sleep(1)
            if self.checkBox.isChecked():
                pag.move(0, -(int(22 * 1.25) * i))
            else:
                pag.move(0, -(22 * i))
            sleep(0.25)
            pag.click()

            self.preset_ready = True

在“预设”下降菜单中选择“ i”。

任务4- apply_preset()函数

(第912行)

        def apply_preset():
            if findClick_object("use_preset.bmp", x=10, y=5) == False: return False

            sleep(1)

            return repeat(lambda: find_object("failed_preset_use.bmp"), False)

此任务唯一的作业是单击蓝色按钮应用预设,然后检查预设是否应用并返回为bool。

任务5-攻击()功能

(第919行)

        def attack():
            if findClick_object("start_attack.bmp", x=50, y=10) == False: return False

            sleep(1)

            return repeat(lambda: find_object("success_attack.bmp"), True)

再次,一个简单的任务,目标是单击攻击按钮,然后检查最后一个确认窗口是否可见,并将其返回为布尔。

任务6 -select_speedup(i)函数

(第876行)

        def select_speedup(i):
            cords = find_object("confirm3.bmp")

            if cords == False: return False

            if i > 1:
                click(cords[0] - 300, cords[1] - 200)
            else:
                click(cords[0] + 100, cords[1] - 200)

            sleep(0.5)

            click(cords[0], cords[1])

            sleep(1)

            return repeat(lambda: find_object("success_attack.bmp"), False)

此任务工作是选择适当的攻击速度,然后单击“确认”按钮,然后检查是否执行攻击并将其返回为布尔。

这些都是主要的机器人任务,由主要机器人循环控制

前进到主机器人循环:

(第963行)

        while self.on:
            if next_task() != False:
                #fcounter = 0
                if cur_task == (len(tasks) - 1):
                    cur_task = 0

                    if castle == max:
                        self.firstRotation = False
                        castle = 1
                    else:
                        castle += 1

                else:
                    cur_task += 1
            else:
                boxCheck()

“如果next_task()!= false:”行运行下一个,并通过检查返回布尔来检查它是否成功,并且如果成功完成任务,则仅移至下一个任务。

“ BoxCheck”功能,顾名思义,它检查是否有游戏对话框阻止与游戏的bot交互,并在发现的对话框中删除对话框。

(第994行)

    def kb_listener(self):
        def on_release(key):
            if key == Key.esc:
                self.on = False
                self.statusbar.showMessage("Stopping...")
                return False


        with Listener(on_release=on_release) as listener:
            listener.join()

该部分负责使用键盘快捷键停止机器人。

此函数'kb_listener'定义了一个键的侦听器,当bot运行时,一旦释放了一个键,键'on_release(key)'被释放的键“键”调用。

该函数中的第一行检查“如果key == key.esc:”,该函数指出,如果发布的键是“逃生或ESC”,它将仅执行IF支架。

检查pynput库以获取有关此听众的更多信息。

总结:

bot是以序列/任务逻辑开发的,因为游戏是通过彼此进行多个对话框进行的,因此每个任务都取决于在开始之前要完成任务之前的任务。

我很久以前开发了这个机器人,这里有一些必读的反思:

  • GUI代码不应与Bot脚本相同的模块。
  • 辅助功能不应全部包含在主要机器人功能中。
  • 机器人循环应在其自己的函数中。
  • 机器人需要一种安全的失败方法,内置案例被卡在其中一个任务中。