Пока IT сообщество увлеченно наблюдает за криптовалютами и их добычей, я решил помайнить то, что майнилось задолго до того, как крипта и все связанное с ней стало мэйнстримом. Речь конечно же об игровом золоте в ММО играх.
Реализовать задумку мне помог python 3.6 и советы коллег программистов. Хотя статья и будет опираться на пример в конкретной игре, цель ее больше не рассказать историю хака, а расхвалить питон и показать еще не освоившим, что с ним может делать человек-не-программист и почему это так круто.
Сразу стоит сделать некоторые ремарки:
- Если вы святоша и веско, резко, решительно против любого мухлежа в играх — можете смело закрывать статью.
- Если вы «труъ» программист и готовы брызжа слюной доказывать, что питон фигня и новичков сразу нужно макать в ручное управление памятью, яки младенца в святую воду — можете смело закрывать статью.
- Если же вы мега квалифицированный программист без предрассудков — выбор за вами, но скорее всего мой быдлокод будет резать вам глаз и подобные штуки вы сами делаете на раз плюнуть.
- Новички и любители интересных задачек — добро пожаловать на борт.
Соль задачи
Есть игра GuildWars2, в ней запущен рождественский эвент (мини игра), которая очень похожа на guitar hero только с колокольчиком.
Смысл игры заключается в своевременном нажатии кнопок-нот 1-2-3-4 и 6-7-8-9 в зависимости от того, какой кружок по какой дорожке приедет к центру, где стоит персонаж. Если очень интересно, то можно посмотреть видео на ютубе, набрав guild wars 2 choir bell.
За полное прохождение, пусть и с погрешностями, дают максимальное количество ценных подарочков, которые можно продать на рынок по цене примерно 5.5 серебра за штуку. Я подсчитал, что за сутки неприрывного прохождения этого эвента, можно делать ~3300 подарочков а это больше 180 чистого золота, цена которому 2 рубля за ед. на черном рынке. Копейки в абсолютных величинах но очень неплохо в сравнении с тем же криптомайнингом, а? Особенно если учесть, что для этого нам не требуется дорогостоящая видеокарта или платный аккаунт.
В общем мои рученки идейного ботовода зачесались и я решил сие действо автоматизировать, хотя бы из спортивного интереса.
Шаг 0. Анализируем
Для автоматизации нам нужно всего 2 вещи: распознавать пиксели и нажимать кнопки.
Тут требуется сделать небольшое отступление и сказать, что я совсем не будучи программистом, пробовал быдлокодить на с++, с#, PHP, delphi и даже ассемблере в среде masm32. Выбор питона на этой стадии был почти случайным. Я просто подумал «А почему бы не попробовать до кучи на питоне? Вдруг будет удобнее?». Это не был какой то осознанный выбор, я тогда еще и не предполагал, насколько питон классный.
Нужно было понять, как можно зацепиться за цвета пикселей и я начал искать простую пипетку, которая показывала бы цвет под указателем мышки и его rgb значение. Из игры я записал на бандикам видео для анализа, поэтому фотошоп и редакторы изображений не подходили. Не нарезать же в самом деле видео на скриншоты. Мне нужно было что то простое, работающее в режиме реального времени и показывающее координаты. К сожалению гугл не нашел мне подходящей утили и я решил состряпать ее сам. Вот что получилось:
from graphics import *# Здесь и далее импортируемый модуль графических примитивов(скачивается отдельно)
import pyautogui #Здесь и далее импортируемый модуль автоматизации ( скачивается отдельно )
import time # время же. (Стандартный модуль)
def main():# определяем мэйн функцию
win = GraphWin("pipetka", 200, 200, autoflush=True)#создаем графическую форму размером 200х200 и элементы на ней
x, y = pyautogui.position()#получаем в x, y координаты мыши
r, g, b = pyautogui.pixel(x, y)# получаем в r, g, b цвет
ColorDot = Circle(Point(100, 100), 25)# создаем точку, отображающую цвет
ColorDot.setFill(color_rgb(r, g, b))# устанавливает ей заливку из ранее полученных цветов
ColorDot.draw(win)# рисуем на форме win
RGBtext = Entry(Point(win.getWidth()/2, 25), 10)# создаем RGB вывод
RGBtext.draw(win)# рисуем на форме win
RGBstring = Entry(Point(win.getWidth()/2, 45), 10)#создаем вывод цвета в web стиле
RGBstring.draw(win)# рисуем на форме win
Coordstring = Entry(Point(win.getWidth() / 2, 185), 10)# создаем отображение координат
Coordstring.draw(win)# рисуем на форме win
while True: # цикл перереисовки формы
time.sleep(0.1)# задержка в 0.1 с, чтобы питон не сходил с ума
x, y = pyautogui.position()#получаем в x, y координаты мыши
r, g, b = pyautogui.pixel(x, y)# получаем в r, g, b цвет
ColorDot.setFill(color_rgb(r, g, b))#Обновляем цвет
RGBtext.setText(pyautogui.pixel(x, y))#Обновляем RGB
RGBstring.setText(color_rgb(r, g, b))#Обновляем web цвет
Coordstring.setText(str(x)+" "+ str(y) )#Обновляем координаты
win.flush()# Даем команду на перерисовку формы
#основной код начинается ниже.
main()#вызываем нашу функцию.
Тулза в действии. Поковырялся я с ней и с прискорбием обнаружил, что моя первоначальная задумка захватывать пиксели уже на середине, провальная:
1) мало времени на определение цвета и посыл нажатия
2) цвета кружков очень неоднородные
3) незначительные отклонения в позиционировании камеры сильно мешают
Однако поковырявшись еще чуть чуть, мне в голову пришла идея захватывать не пиксели нужного цвета а изменения яркости в нужных местах т.к. эксперементы с пипеткой показали, что кружки гораздо выше по шкале R, G или B ( в зависимости от цвета) нежели фон игрового поля. В итоге я выбрал 8 точек где кружки проходят в наибольшем размере.
Шаг 1. Кодим распознавание кружка
import time# модуль времени ( стандартный )
import pyautogui# автоматизатор ( скачивается отдельно )
import winsound#модуль для сигнала, чтобы знать, что программа запустилась ( стандартный )
import keyboard#модуль для работы с клавиатурой ( скачивается отдельно )
def analyzer():
etalon = [pyautogui.pixel(355, 288), pyautogui.pixel(460, 200), pyautogui.pixel(600, 130), pyautogui.pixel(735, 112), pyautogui.pixel(875, 109), pyautogui.pixel(1000, 145), pyautogui.pixel(1139, 203), pyautogui.pixel(1260, 290) ]#массив эталонных цветов
trigger = [0,0,0,0,0,0,0,0]#массив триггеров, инициализируем нулями
while True:
change = [pyautogui.pixel(355, 288), pyautogui.pixel(460, 200), pyautogui.pixel(600, 130), pyautogui.pixel(735, 112), pyautogui.pixel(875, 109), pyautogui.pixel(1000, 145), pyautogui.pixel(1139, 203), pyautogui.pixel(1260, 290) ] #Забираем в цикле change массив текущего состояния точек
for nomer in range(0,8):
if change[nomer][0] > etalon[nomer][0]+50 or change[nomer][1] > etalon[nomer][1]+50 or change[nomer][2] > etalon[nomer][2]+50:
if trigger[nomer] == 0: #если точка изменила цвет по R,G или B больше чем на +50 и триггер прохождения выключен
trigger[nomer] = 1#включаем триггер прохождения
else:
if trigger[nomer] == 1: #проверяем не включен ли триггер прохождения
trigger[nomer] = 0 #обнуляем триггер прохождения
print("push " +str(nomer) + time.strftime(' %X'))
#основной код начинается ниже.
keyboard.wait(combination="home")#после старта ждем нажатия клавиши "Home"
winsound.Beep(1000, 100) #сигналим что программа стартанула
analyzer()# запускаем анализ
Разбор алгоритма:
- Кладем в массив etalon цвета фона игрового поля, с которым впоследствии будет происходить сравнение цветов массива change Строчка
keyboard.wait(combination="home")
нужна как раз, чтобы забрать эталонные цвета в момент, когда игра уже развернута и камера отцентрирована - Инициализируем массив триггеров trigger. Он нам нужен, поскольку питон отрабатывает много раз, пока кругляш бежит к центру. Кругляш большой а точка в которой мы снимаем показания маленькая. То есть, для того, чтобы один и тот же кругляш мы не зарегистрировали дважды и более.
- Запускаем бесконечный цикл в котором мы постоянно забираем значение цветов в массив change и сравниваем цвета каждой из забранных точек с эталонными цветами
for nomer in range(0,8): if change[nomer][0] > etalon[nomer][0]+50 or change[nomer][1] > etalon[nomer][1]+50 or change[nomer][2] > etalon[nomer][2]+50:
- Если в предыдущем IF'e мы выяснили что цвет точки с номером nomer ярче хотя бы на 50 единиц по любому из значений RGB, то проверяем зажжен ли триггер для этой точки и если нет — зажигаем
if trigger[nomer] == 0: trigger[nomer] = 1
- Если же цвет в постоянно обновляемом change соответствует эталонному цвету, то тут два варианта. Либо все тихо и кружка еще нет, либо кружок только что съехал дальше с проверяемой точки, что и является сигналом для нажатия кнопки. Определяемся мы в итоге по состоянию триггера. Если триггер был зажжен — значит кругляш уехал. Обнуляем триггер и пока условно нажимаем кнопку.
if trigger[nomer] == 1: trigger[nomer] = 0 print("push " +str(nomer) + time.strftime(' %X'))
Шаг 2. Запускаем и тестим
В игре отслеживать правильность работы и отлаживать трудно, поэтому я опять сделал запись окна игры на бандикам и тестировал на нем.
Слева — то, что выдал вывод питона, справа — то, что записал я, просматривая видео в замедленном режиме. Как видите есть погрешности в виде лишних нажатий 6 и 0 — это чертовы снежинки, которые никак нельзя убрать. Штука в том, что для исходной цели, непрерывного сбора подарочков, нам не нужен 100% счет, игра прощает игроку довольно много ошибок. Если бы это было не так, то просто нужно было бы ввести дополнительную проверку на белый цвет.
Шаг 3. Кодим нажималку кнопок через потоки
Тут собственно ничего заумного нет. Мы получаем номер точки и через 2 секунды нажимаем кнопку. Почему через 2 секунды? Потому, что кругляш с момента когда мы его засекли доезжает до середины примерно за 2 секунды. Небольшая хитрость тут заключается в том, что нажимать кнопки нужно независимо друг от друга. Мы не можем ставить исполнение программы на паузу применив классический sleep() т.к. все собьется да и вообще кругляши летят достаточно быстро. Можно организовать очередь или воспользоваться потоками, что, как мне думается, является более изящным решением( если конечно питон и много потоков не тормозят на вашем ПК ).
Добавляем в код
from threading import Timer
и сам обработчик отложенного нажатия
def delaypress(keynum):
if keynum < 4:
keynum +=1
else:
keynum +=2
t = Timer(2, keyboard.send, args=[str(keynum)])
t.start()
Если на вход поступает номер точки 0-1-2-3 нажимаем через 2 секунды номер точки + 1, если же поступает 4-5-6-7, то нажимаем через 2 секунды номер + 2 ( т.к. кнопка 5 не задействована в мини игре )
import time# модуль времени ( стандартный )
import pyautogui# автоматизатор ( скачивается отдельно )
import winsound#модуль для сигнала, чтобы значть, что программа запустилась ( стандартный )
import keyboard#модуль для работы с клавиатурой ( скачивается отдельно )
from threading import Timer#импортим таймер из модуля потоков ( стандартный )
def delaypress(keynum):
if keynum < 4:
keynum +=1
else:
keynum +=2
t = Timer(2, keyboard.send, args=[str(keynum)])
t.start()
def analyzer():
etalon = [pyautogui.pixel(355, 288), pyautogui.pixel(460, 200), pyautogui.pixel(600, 130), pyautogui.pixel(735, 112), pyautogui.pixel(875, 109), pyautogui.pixel(1000, 145), pyautogui.pixel(1139, 203), pyautogui.pixel(1260, 290) ]#массив эталонных цветов
trigger = [0,0,0,0,0,0,0,0]#массив триггеров, инициализируем нулями
while True:
change = [pyautogui.pixel(355, 288), pyautogui.pixel(460, 200), pyautogui.pixel(600, 130), pyautogui.pixel(735, 112), pyautogui.pixel(875, 109), pyautogui.pixel(1000, 145), pyautogui.pixel(1139, 203), pyautogui.pixel(1260, 290) ] #Забираем в цикле change массив текущего состояния точек
for nomer in range(0,8):
if change[nomer][0] > etalon[nomer][0]+50 or change[nomer][1] > etalon[nomer][1]+50 or change[nomer][2] > etalon[nomer][2]+50:
if trigger[nomer] == 0: #если точка изменила цвет по R,G или B больше чем на +50 и триггер прохождения выключен
trigger[nomer] = 1#включаем триггер прохождения
else:
if trigger[nomer] == 1: #проверяем не включен ли триггер прохождения
trigger[nomer] = 0 #обнуляем триггер прохождения
#print("push " +str(nomer) + time.strftime(' %X'))#заменяем печать на вызов нажималки
delaypress(nomer)
#основной код начинается ниже.
keyboard.wait(combination="home")#после старта ждем нажатия клавиши "Home"
winsound.Beep(1000, 100) #сигналим что программа стартанула
analyzer()# запускаем анализ
Шаг 4. Гребем профит
Заключение и ссылки
А теперь, как и обещано, расхваливаю питон( надеюсь достаточно обоснованно ).
- Питон отлично подходит людям с базовыми знаниями в области программирования и гуглинга для решения интересных задач.
- Реально юзер френдли язык. Лично по моим ощущениям синтаксиса меньше раза в три и нет идиотского количества ошибок, как в других языках, даже при написании небольших программ.
- Отличная экосистема. Если вы знаете, как сформулировать вопрос гуглу, вы с большой долей вероятности найдете или готовое решение или инструмент, позволяющей сделать, то, что вы хотите.
- Нет танцев с бесконечными перекомпиляциями. На современных ПК небольшие программки конечно компилятся быстро, но все равно это раздражает если вы учитесь и приходиться пересобирать проект десятки раз.
- Документация. По простоте, понятности и лаконичности ближайший аналог видел только у PHP.
- В питоне прослеживаются черты линукс философии. Даже установка новых модулей легка и приятна и не вызовет у вас трудностей если вы освоили какой нибудь apt или yum
- Питон удобен для создания всяких хаков и автоматизаций в играх, особенно тех, где требуется частая модификация. Если статья хорошо зайдет — обязательно расскажу как просто на питоне писать в память чужого процесса, делать zoom/speed хак и управлять всем этим безобразием с клавиатуры.
Pyautogui документация
Graphics документация
Документация по модулю keyboard
Если есть интересные идеи для хаков на питоне — пишите в личку.
Комментарии (37)
osmanov13
06.01.2018 18:17- Поручик, вы и на питоне программировать можете?
- Могу-с, только ноутбук постоянно соскальзывает.
danzalux
06.01.2018 18:17Это же великолепно!!!
Раньше я для автоматизации рудиментарного бота (зрение+кноподав) пользовался несложным AutoIt — тоже могу порекомендовать.artamonz Автор
06.01.2018 18:33Пробовал. Штука классная, но питон на порядок богаче по возможностям. В библиотеке pyautogui например есть locateOnScreen('вырезанная_картинка.png') которая позволяет в автоматическом режиме рапознавать изображение на экране и возвращает центр его координат. Таким образом можно например решать простые головоломки в играх или обходить каптчу самописной защиты в LineageII
xpcom
06.01.2018 18:17Ботов для игр проще писать на базе чтения памяти с помощью win32api readProcessMemory или MmCopyMemory.
artamonz Автор
06.01.2018 18:25Естественно. Это как раз и будет материалом следующей статьи. Просто на питоне это делать легко и приятно даже для новичков и я сильно удивлен, почему его еще активно не используют под это дело.
Merkat0r
07.01.2018 23:47Ну почему ж —
в наше времяраньше был популярен перл, просто он вдруг стал сложным для большинства :)
Ботик для РО
Waki
06.01.2018 22:23а такое разве не будет палить античит?
artamonz Автор
06.01.2018 23:27Практически для любой популярной онлайн игры есть обходы ее античитов в паблик доступе. Если нет в русском сегменте, то точно можно найти в англоязычном. Как говориться волков бояться — в лес не ходить. А вообще процесс python.exe исполняющий ваш код наверняка выглядит менее подозрительным, нежели какой нибудь Xc7$smkT.exe да еще и инжектящий в процесс игры свою библиотеку.
Terras
06.01.2018 19:06А если такое дело пошло, на каком стеке и какими тулзами проще всего писать эффективных(полноценных) ботов для игр?
artamonz Автор
06.01.2018 20:07+1Исследование игры на нижнем уровне и написание под нее бота — штука комплексная. Есть замечательная книга на эту тему которая на 90% описывает то что вам нужно. gamehacklab.ru/topic/4834-утекла-книга-гейм-хакинг-разработка-автономных-ботов-для-онлайн-игр Найти ее можно и в pdf правда на английском. Если такие вопросы — рекомендую начать с вещей попроще, вроде поиска нужных значений в памяти и программного чтения/записи в них. Например на том же питоне.
YAUljanenkov
06.01.2018 22:18-7После того, как попробовал писать на питоне, слег в больницу с диабетом
Waki
06.01.2018 22:30+1интересно получилось, как-то давно делал похожее на delphi, для LAII, играл на пиратке с хай рейтом, суть была в том чтобы банки CP использовались автоматически. Кто играл на пвп серверах думаю поймет.
Areso
07.01.2018 09:27«Спам ГЦП банок». С тех пор придумали игровые мыши с макросами и доп.клавишами)
P.S.: тоже делал, только для спама подходило плохо, а вот циклить макрос /nexttarget /attack /delay 15 /pickup /pickup /pickup получалось замечательно. Ставишь в центр маленькой комнаты в катах и машинка фармит камни за тебя)
berezuev
07.01.2018 00:41Делал подобную конструкцию для другой игры, тоже для новогоднего эвента и тоже ради спортивного интереса… Только использовал связку Python + OpenCV. Нарезал эталонных изображений, которые бот искал на экране и кликал по ним автоматически. На контрастных объектах отрабатывает с довольно высокой точностью.
Alexey2005
07.01.2018 01:03+2Главный недостаток Python'а в плане ботостроения — совершенно кошмарная работа с кодировками текста. Как только вы начинаете искать строки в памяти процесса и конвертить их, скажем, из cp1251 в utf-8, вы проклянёте Python. Все эти долбанные декодеры с энкодерами никогда не работают как надо, да к тому же любая ошибка закончится километром бессмысленных логов, увенчанных UnicodeDecodeError, и во всём этом мусоре не будет ни малейшего намёка на строку, реально вызвавшую ошибку.
ckpunT
07.01.2018 07:15+1В 3-ей версии Python "Все эти долбанные декодеры с энкодерами" всегда работают как надо. А километровые логи на много короче чем в Java и слева указывают имя модуля, имя функции, а справа номер строки для более полного понимания в каком месте произошла ошибка. Или Вы ожидаете от ЯП подобного:
Error in line 13 you meant print() instead pirnt()Kobalt_x
07.01.2018 10:23«Error in line 13 you meant print() instead pirnt()»
clang и GCC вроде в последних версиях так и делают
KvanTTT
07.01.2018 03:21Если вы «труъ» программист и готовы брызжа слюной доказывать, что питон фигня и новичков сразу нужно макать в ручное управление памятью, яки младенца в святую воду — можете смело закрывать статью.
Как бы между Python и ручным управлением памятью есть и промежуточное звено: языки с автоматической сборкой мусора.
Питон отлично подходит людям с базовыми знаниями в области программирования и гуглинга для решения интересных задач.
А C#, Kotlin да и другие языки не подходят?
Реально юзер френдли язык. Лично по моим ощущениям синтаксиса меньше раза в три и нет идиотского количества ошибок, как в других языках, даже при написании небольших программ.
Очень спорное утверждение. Как раз таки в Python ошибок может быть только больше из-за его динамической природы.
Отличная экосистема. Если вы знаете, как сформулировать вопрос гуглу, вы с большой долей вероятности найдете или готовое решение или инструмент, позволяющей сделать, то, что вы хотите.
Опять-таки. А к другим языкам это не относится?
Нет танцев с бесконечными перекомпиляциями. На современных ПК небольшие программки конечно компилятся быстро, но все равно это раздражает если вы учитесь и приходиться пересобирать проект десятки раз.
Помимо Python вы знаете только C++?
Документация. По простоте, понятности и лаконичности ближайший аналог видел только у PHP.
Да куча документации хорошей и разной по популярным языкам.
В питоне прослеживаются черты линукс философии. Даже установка новых модулей легка и приятна и не вызовет у вас трудностей если вы освоили какой нибудь apt или yum
nuget для C#, maven для Java.
Питон удобен для создания всяких хаков и автоматизаций в играх, особенно тех, где требуется частая модификация.
Какая модификация?
artamonz Автор
07.01.2018 04:36+6Если вы «труъ» программист и готовы брызжа слюной доказывать, что питон фигня и новичков сразу нужно макать в ручное управление памятью, яки младенца в святую воду — можете смело закрывать статью.
Как бы между Python и ручным управлением памятью есть и промежуточное звено: языки с автоматической сборкой мусора.
Сие было небольшим троллингом программистов, которые отрицают, что не все языки подходят для освоения юными падаванами и кричат что именно их язык нужно учить потому что он самый[хардкорный, массовый, энтерпрайзный, кошерный, ...] да еще и литературы вдобавок насоветуют а ля «паттерны проектирования» или опусов Кернигана и Ричи. Это ведет к скорейшему забиванию на идею что нибудь попрограммировать.
А C#, Kotlin да и другие языки не подходят?
На шарпе переделывал инъектор для игры Rust, опять же при помощи гугла и советов коллеги — то еще удовольствие если с языком не работаешь каждый день. Так же, если на питоне понравилась программка или модуль — то ты открываешь, изучаешь и копируешь нужный код. В c# для подобного пришлось качать net reflector и прогонять прогу через деобфускатор de4dot. Я думаю не стоит тут упоминать как выглядит код после деобфускации, кто ковырял сам знает.
Очень спорное утверждение. Как раз таки в Python ошибок может быть только больше из-за его динамической природы.
Возможно для больших и сложных проектов это так, но у меня есть только опыт написания небольших программок под собственные нужны и он говорит об обратном.
Опять-таки. А к другим языкам это не относится?
На мой, достаточно субъективный, взгляд накладывается опыт разбирательств с другими языками. Питон сообщество нацелено не только на профессионалов, вот в чем его плюс. Возможно, если вы опытный программист, вы не заметите разницу в общении на форумах или в подаче документации, но для начинающих важно чтобы объяснялось для их уровня. И да, никто не будет делать на c# или java программки для системного администрирования,
а на питоне будут. Это и создает ту экосистему для людей-не-программистов.
Помимо Python вы знаете только C++
А кто сказал что я знаю python и с++? Я знаю базовые для всех языков конструкции и как пользоваться гуглом. Дополнительный синтаксис осваивается за пару часов ( если это конечно не lisp или брэйнфак ). Это как раз та фишка о которой я и говорил в статье — питон не нужно хорошо знать чтобы решать на нем задачи.
Да куча документации хорошей и разной по популярным языкам.
Опять же с точки зрения профессионального программиста да, а с точки зрения не программиста вопрос очень спорный. Отписал выше.
nuget для C#, maven для Java
Не спорю. Тут это просто плюс, по сравнению с языками, в которой таких систем нет.
Какая модификация?
В играх отвратительно часто встречаются апдейты меняющие статические адреса и указатели, хранящие скорость, коэффициент разброса оружия или еще какую нибудь интересную переменную. Или например ввели в игре временное изменение и кликер тыкает уже не туда, куда ему положено.
SMullerin
07.01.2018 15:12-1Большое спасибо за статью, дали пищу для размышлений :) Плюс пока не могу поставить — карма низковата, но считайте этот плюс плюсом в свою личную карму ;)
Я немного поворчу, если позволитемой быдлокод будет резать вам глаз
То, что Вы это признали — хороший признак того, что Вы от него хотите избавиться и писать труЪ-код. Одно дело — хвастаться и буквально кичиться быдлокодерством, и совсем другое — признать и активно с ним бороться. Сейчас сам на этом или чуть более раннем этапе.
расхвалить питон и показать еще не освоившим, что с ним может делать человек-не-программист
Именно это как раз важно. Это как выучиться на сварщика, но работать/подрабатывать в оркестре барабанщиком (и делать это хорошо).
Статья хорошая, осталось чуть-чуть подтянуть правописание (судя по комментариям, Вы умеете писать грамотно, что не очень часто встречается — просто не торопитесь с публикацией)).
Всё, перестаю ворчать.PavelMSTU
07.01.2018 23:30Мы не можем ставить исполнение программы на паузу применив классический sleep() т.к. все собьется да и вообще кругляши летят достаточно быстро.
Что-то туплю… Почему собьется? По поводу скорости: а sleep(0.01) не пробовали?artamonz Автор
08.01.2018 00:36Смысл в том, что кругляш едет до центра около 2-х секунд и кнопку нужно нажимать через 2 секунды, после того как его засекаем программно. то Есть если поставить time.sleep(2) а потом нажать кнопку, кнопка то нажмется, но в эти 2 секунды программа не будет ловить другие кружки а тупо ждать.
grand_grego
08.01.2018 00:33А не подскажете модуль (не нашел, мб плохо искал) который анализирует звук исходящий из игры? И при помощи которого можно сделать специальные триггеры на определенный звук? Как выше в комментариях написано было, например,
locateOnScreen('вырезанная_картинка.png')
seniorjoker
08.01.2018 00:33Занятная статья. Также, хотелось бы увидеть пару слов о защите в таких играх.
artamonz Автор
08.01.2018 00:43У меня накопилось некоторое количество опыта по обходу защит и даже кое какие свои наработки, но боюсь ответ значительно превосходит формат комментария. Вроде статья неплохо зашла, думаю и на тему защит напишу со временем.
m0Ray
09.01.2018 10:05Поздравляю, вы изобрели велосипед. OpenCV поможет его сильно проапгрейдить.
Сам кодю на питоне, но без openCV в таких задачах повеситься можно.artamonz Автор
09.01.2018 20:56Ну у меня нет мании величия и я ни в коем образе не утверждал, что мой метод правильный и изящный. Всегда найдется тот, кто сделает лучше, выше, быстрее, сильнее. Суть статьи в том, чтобы показать, что человеку можно чуть чуть погуглить и сделать на питоне какую то интересную вундервафлю, даже если он не разу не профессионал. Ваш OpenCV гугл кстати не разу не выдал когда я искал либы под это дело. Если бы он мне попался на глаза первым — возможно в статье был бы он. В любом случае спасибо за инфу, буду иметь в виду.
m0Ray
09.01.2018 21:10Вот, посмотрите, как красиво и быстро всё это делается на openCV. Я его за это очень люблю.
pythonprogramming.net/color-filter-python-opencv-tutorial
opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_colorspaces/py_colorspaces.html
thecodacus.com/opencv-object-tracking-colour-detection-python
www.youtube.com/watch?v=mT4gmPCnU58
JoeyBlack
09.01.2018 20:48Арбитраж!))) А вообще понравилась, интересная идея и доведение её на результата
vin2809
Так держать!
Код не программиста, но для «Инженера» просто здорово.
Да, а в первом абзаце заключения, я бы просто поставил точку вот после этих слов: