Хабрахабр

[Из песочницы] Пишем бот для рыбалки в игре Albion Online на языке Python

image

Всем привет, я являюсь счастливым пользователем операционной системы GNU/Linux.И как многим известно, игрушек идущих на линукс без дополнительных танцев с бубном намного меньше чем в «Винде».

И еще меньше игр в жанре MMORPG.

И дабы не тратить свои драгоценные часы жизни по напрасну, я решил написать бота. Однако, где-то пол года или год назад я узнал что под линукс портировали игру Albion Online.
Игра очень занимательная, однако занимает достаточно большое количество времени. Который будет фармить мне ресурсы, пока я буду заниматься своими делами.

В игре есть много видов ремесла, можно рубить лес, камни копать, даже выращивать огороды, однако мой выбор был сделан в пользу рыбалки.
Итак, суть рыбалки в альбион онлайн проста, берете удочку, подходите к водоему, зажимаете кнопку, дабы закинуть наживку, ждете в течении определённого времени поклевки.

image

Когда клюет, вы должны опять нажать на кнопки и сыграть в мини-игру.

Поплавок движется всегда случайно, с разными последовательностями и скоростями. Тут потребуется попеременно то тянуть, то не тянуть удочку, в зависимости от движений поплавка. И если вы все сделаете верно и поплавок не выйдет за прелы допустимой зоны, то вы выловите рыбу.

По средствам компьютерного языка python. Итак, все это дело мы будем автоматизировать. Тут снова мне на выручку пришла моя любимая библиотека с компьютерным зрением OpenCV. Начать я решил с самого сложного, а именно с момента, где начинается игра с поплавком. Однако сама библиотека не знает что именно нам нужно обнаружить. Запустив ее мы можем обнаруживать объекты к примеру на картинках. Однако, там точно нет поплавков для Albion Online. Конечно существуют множество шаблонов где представлены различные предметы для их определения.

И в качестве шаблона я просто взял скриншот нашего поплавка. Зато в данной библиотеке есть замечательная функция поиска по заданному шаблону.

image

И как мы видим все прекрасно нашлось на картинке.

И вот мы уже можем находить поплавок на потоковом видео. А разница между картинкой и потоковым виде не велика, ведь по сути это просто поток картинок с очень быстрой скоростью, и несколько строчек кода.

Код

import numpy as np
import cv2
from mss.linux import MSS as mss
from PIL import Image
import time
import pyautogui as pg
import cv2
import mss
import numpy template = cv2.imread("2019-07-02_06-55_1.png", cv2.IMREAD_GRAYSCALE)
w, h = template.shape[::-1] with mss.mss() as sct: monitor = while "Screen capturing": last_time = time.time() img = numpy.array(sct.grab(monitor)) cv2.imshow("OpenCV/Numpy normal", img) print("fps: {}".format(1 / (time.time() - last_time))) gray_frame = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) res = cv2.matchTemplate(gray_frame, template, cv2.TM_CCOEFF_NORMED) loc = np.where(res >= 0.7) for pt in zip(*loc[::-1]): cv2.rectangle(img, pt, (pt[0] + w, pt[1] + h), (0, 255, 0), 3) cv2.imshow("Frame", img) key = cv2.waitKey(1) if cv2.waitKey(25) & 0xFF == ord("q"): cv2.destroyAllWindows() break

Идем далее. Сам поплавок двигается туда-сюда и мы также должны его двигать, нажимая кнопку на мышке.

И для этого нас выручают вот эти строчки. А посему, нам нужны его координаты.

for p in img: pts = (pt[0],pt[1]) x = (pt[0]) y = (pt[1]) print (x) cv2.circle(template,pts,5,(200,0,0),2) cv2.putText(img, "%d-%d" % (x,y), (x+10,y-10), cv2.FONT_HERSHEY_SIMPLEX, 1, color_yellow, 2)

Затем мы просто воспользуемся библиотекой PyAutoGUI, которая будет зажимать кнопку мыши и отжимать ее с определенной периодичностью.

if 100 < x < 500: pyautogui.mouseDown(button='left') time.sleep(1) pyautogui.mouseUp(button='left') x = 0

И сама мини игра успешно выигрывается.

image

Засунем все это дело в функцию и пока оставим.

Затем вернемся к изначальной части, где мы должны следить за поплавком.

Однако поплавок закинутый в воду предстает под разными углами и постоянно колышется. Тут все несколько иначе, допустим мы можем определить, куда закинется поплавок, и попробовать анализировать ту часть экрана на наличие поплавка.

Суть его в том, что мы анализируем, скажем так разницу в пикселях внутри отслеживаемого фрагмента. В таком случае мы возьмём тот несколько иной метод. Которая, если поплавка нет приближается к нулю.

В итоге было найдено оптимальное значение при котором при исчезновении поплавка, мы можем производить действия.

Код

def screen_record(): sct = mss.mss() last_time = time.time() while(True): img = sct.grab(mon) print('loop took {} seconds'.format(time.time() - last_time)) last_time = time.time() img = np.array(img) processed_image = process_image(img) mean = np.mean(processed_image) print('mean = ', mean) if mean <= float(0.11): print('SSSSSSSS ') pyautogui.click(button='left') break return else: time.sleep(0.01) continue return if cv2.waitKey(25) & 0xFF == ord('q'): cv2.destroyAllWindows() break

И мы их производим, а именно нажимаем на кнопку мыши. Также засовываем это в функцию.

Ну и наконец в заключении мы просто записываем скрипт где в бесконечном цикле мы забрасываем удочку и выполняем попеременно первую и вторую функцию.

while "Черный": time.sleep(1) pyautogui.moveTo(431,175,duration=1) pyautogui.mouseDown(button='left') pyautogui.moveTo(450.200,duration=1) pyautogui.mouseUp(button='left') time.sleep(2) screen_record() time.sleep(0.01) ss()

Вот полная видео инструкция и пример работы данного бота:

Есть правда некоторые нюансы в том что там надо шаманить с цифрами, так как эти цифры подобраны под мой монитор, локацию, персонажа и экипировку. Но я думаю для грамотного питониста это не составит проблем.

Весь скрипт:

Код

import numpy as np
import cv2
from mss.linux import MSS as mss
from PIL import Image
import time
import pyautogui as pg
import imutils
import mss
import numpy
import pyautogui template = cv2.imread("2019-07-02_06-55_1.png", cv2.IMREAD_GRAYSCALE)
w, h = template.shape[::-1] color_yellow = (0,255,255) mon = {'top': 80, 'left': 350, 'width': 100, 'height': 100} def process_image(original_image): processed_image = cv2.cvtColor(original_image, cv2.COLOR_BGR2GRAY) processed_image = cv2.Canny(processed_image, threshold1=200, threshold2=300) return processed_image def ss(): op = 1 with mss.mss() as sct: monitor = {"top": 40, "left": 0, "width": 800, "height": 640} while "Screen capturing": last_time = time.time() img = numpy.array(sct.grab(monitor)) gray_frame = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) res = cv2.matchTemplate(gray_frame, template, cv2.TM_CCOEFF_NORMED) loc = np.where(res >= 0.7) op += 1 print (op) for pt in zip(*loc[::-1]): cv2.rectangle(img, pt, (pt[0] + w, pt[1] + h), (0, 255, 0), 3) for p in img: pts = (pt[0],pt[1]) x = (pt[0]) y = (pt[1]) print (x) if 100 < x < 490: pyautogui.mouseDown(button='left') time.sleep(2) pyautogui.mouseUp(button='left') x = 0 break else: continue break else: continue break key = cv2.waitKey(1) if cv2.waitKey(25) & 0xFF == ord("q"): cv2.destroyAllWindows() if op > 35: return def screen_record(): sct = mss.mss() last_time = time.time() while(True): img = sct.grab(mon) print('loop took {} seconds'.format(time.time() - last_time)) last_time = time.time() img = np.array(img) processed_image = process_image(img) mean = np.mean(processed_image) print('mean = ', mean) if mean <= float(0.11): print('SSSSSSSS ') pyautogui.click(button='left') break return else: time.sleep(0.01) continue return if cv2.waitKey(25) & 0xFF == ord('q'): cv2.destroyAllWindows() break while "Черный": time.sleep(1) pyautogui.moveTo(431,175,duration=1) pyautogui.mouseDown(button='left') pyautogui.moveTo(450.200,duration=1) pyautogui.mouseUp(button='left') time.sleep(2) screen_record() time.sleep(0.01) ss()

Те кто любит сказать, что это бесполезная трата времени, я замечу, что это лишь инструмент, эти библиотеки вы можете применить и в других проектах. Само компьютерное зрение применяется как при наведении баллистических ракет, так и в программах для помощи инвалидам. Куда вы решите их применить, только ваше желание.

Всем спасибо за внимание.

Теги
Показать больше

Похожие статьи

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть