Как сделать бота для игры
Перейти к содержимому

Как сделать бота для игры

  • автор:

Как создать бота для игры.

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

Лучший ответ

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

Если игра со скриптами, такая как FarCry или СТАЛКЕР, то для этих игр самодельщики делают моды.
Только боты там готовые, предусмотренные разработчиками. Возможно, их поведение можно изменить, но в пределах, дозволенных разработчиками.
Про делание модов поищите на форумах, связанных с этими играми.

Остальные ответы

Боты ботам рознь. Есть предусмотренные разработчиками боты (как указал предыдущий оратор), есть автокликеры и вообще повторители действий по шаблону, и есть имитаторы действий человека. Написание бота для имитации действий человека сложнее всего: требуется перехват текущего состояния (который не будет детектироваться противодействующими встроенными в игру инструментами), чёткая интерпретация этих данных, запись действий реальных людей в различных ситуациях (причём с объективной оценкой успешности этих действий), способ адекватного распространения этих записей на весь спектр возможных ситуаций, применение этих записей для собственно имитации.

Олег ГородскойМыслитель (9661) 7 лет назад

Вы имеете в виду читы?
Тут путаница в названиях: намример, есть название «аим» и «аимбот».

А еще бывает промежуточнй вариант: в некоторых играх разрабы сами дозволяют макросы! Например, в одной игре («немыльной») при смене дроба на нож и обратно дроб получается перезаряжен! И там еще донат есть: ускорение смены оружия! Ясно, для чего.

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

Как пишут ботов для игр (или для программ с интерфейсом)?

Здравствуйте.
Интересует вопрос, как пишут ботов для игр (хоть самых простых) или для программ (у которых есть интерфейс).
Мне интересен сам принцип. Вот как заставить бота по сайтам лазить — это понятно (просто по ссылкам переходит и всё).
А как в приложениях, я вообще не понимаю (неужели просто программа мышку перемещает и щелкает по кнопкам вместо человека?)
p.s. Лучше на python-е.
Заранее спасибо!

  • Вопрос задан более трёх лет назад
  • 68596 просмотров

1 комментарий

Оценить 1 комментарий

Есть программа для создания ботов Zennoposte.
Не требует знаний программирования. Похожа на конструктор.
Позволяет создать любого бота, автоматизировать любой процесс на компьютере.
— Боты для игр
— Боты для ВК, Одноклассников, Facebook, Instagram, бот для телеграмм, для авито.
— Онлайн боты для создания аккаунтов.
— Боты для всего
Не бесплатная, но есть тестовый период 14 дней.
www.zennolab.com/ru/products/zennoposter/pid/18bec.

Решения вопроса 1

ты видел ботов на питоне?

Ответ написан более трёх лет назад
Алексей Мистин @Mistin Автор вопроса
На питоне ботов не пишут что ли?

Я не встречал. Если сможете на питоне взаимодействовать напрямую с операционной системой — пожалуйста.

Алексей Мистин @Mistin Автор вопроса

Такие боты всегда взаимодействуют с ОС? И на каких языках тогда можно их писать? (более-менее популярных)

Алексей Мистин: на PHP. Извините за шутку
Алексей Мистин @Mistin Автор вопроса
на сколько я понял на assembler можно это сделать, а на таких как c++, java можно?

А как вы собираетесь взаимодействовать с другими приложениями, не взаимодействуя с ОС?))
Delphi, C/C++, Assembler
Тут точно можно 🙂

На java не знаю, я просто на ней никогда не кодил 🙂
Алексей Мистин @Mistin Автор вопроса

А что Вы можете посоветовать изучать мне? (я молодой начинающий программист, который пока знает не много, но хочет это исправить)

А какие у вас цели в общем то?
Алексей Мистин @Mistin Автор вопроса

Честно говоря я сам не знаю чего хочу, но основной мой интерес в написании обычных прикладных приложений для пользователей (ну или сайтов разных).

Определитесь, вам нужно прикладное программирование, или веб-программирование.

Если под веб — php, html, css, js и какую-нибудь базу данных, желательно MySQL
Если прикладное — C++ или Delphi ( не рекомендую, а то большинство тех, кто кодил на делфи первым языком почему-то отрофируются из-за компонент ).
Есть еще системное программирование.

DiMithras

Python + selenium чем не веб-бот?

Что до языков программирования, начали с Python, освойте хорошенько Python, его применение нынче довольно широко и не ограничивается pandas, big data и ML, можно довольно спокойно и успешно писать те же самые прикладные программы. Из скриптовых языков, тот же Ruby не ограничивается рельсами и на нём довольно удобно писать прикладные программы, тем более что его стандартный набор превосходит Python, например Regular Expressions вшиты как стандарт и под них отведён отдельный синтаксис, в то время как в Python необходимо делать импорт.

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

Ответы на вопрос 6

riky

от себя добавлю что основные методы это
1) простейший понятный способ — поиск нужного элемента на экране и кликание по экрану, или клик по указанным координатам. я в основном использую этот способ, так как вмешательство в игру минимальное — ее не надо ломать, для онлайн игр — меньше шансов получить бан. Подходит для простых игр, в основном те что 2D пошаговые.
Гуглить отправку событий мыши и клавиатуры на выбранном вами ЯП (java robots например).
Минусы — игра должна быть постоянно открыта на экране и иметь фокус (можно решить — запустив игру с ботом в виртуалке).

2) для онлайн игр — изучение протокола обмена данными с сервером. нужно изучать куда отправляются/откуда получаются данные и в каком формате. пишем программу которая эмулирует клиент игры. очень хороший способ — для очень интерактивных игр — максимальная скорость. Способ довольно сложный надо реверсить протокол (гуглить wireshark) и возможно само приложение (гуглить дизассемблирование / декомпиляция). Если игра браузерная — то все может быть проще — запросы и ответы можно смотреть в консоли браузера. Очень перспективный способ — визуальный клиент не обязателен — можно делать армию ботов и размещать на серверах — скорее всего они будут потреблять немного памяти и процессора и возможности впечатляющие.

3) для десткопных игр — патчинг памяти запущенной игры. варианты от простых типа — поменять очки/деньги в игре (artmoney) это в основном для не онлайн игр, и до очень сложных — подменить адрес вызова системной функции — например функции отрисовки directx — то есть меняем адрес вызова на свою функци (недавно была серия статей на эту тему, к сожалению не нашел побыстрому). Либо как разновидность — декомпиляция игры — изменение логики — компиляция (гуглить все что связано с крекерством, создание кейгенов). Для этого варинта требуется довольно высокая квалификация, понимание того как работает игра. Также игры могут иметь защиту от этого.

Кстати понимание того как работают игры/программы — одно из главных в этом деле. Поэтому в первую очередь следует заняться тем чтобы понять как работает конкретная игра, а потом уже думать на каком этапе можно вмешаться в ее логику чтобы достичь нужного эффекта. Изучайте также средства тестирования игр/приложений — с помощью их также можно малой кровью добится хороших результатов.

Ответ написан более трёх лет назад
Нравится 8 5 комментариев

riky

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

чтобы понять этот способ — попробуйте с чего нибудь простого — например напишите бота для сапера.

Какая нафиг декомпиляция игры и последующая компиляция? Ты че, собрался из экзешника рабочие сорцы собрать? Че ты там у ся куришь, или у тебя версия HexRays Decompiler из далекого будущего?

Neuroware

Coderast: все игры на Unity состоят из «шлака» типа текстур объектов и т.п. и «игры» в виде пары тройки библиотек на .net, если автор игры не заморачивался с обфускацией этих библиотек (например ранние версии the forest) то код библиотеки легко раскрывался в сорцы (см Dot Peak), которые спокойно компилятся в студии обратно, естественно с нужными вам читами или ботами. Так что riky прав, хотя это не со всеми играми так легко сделать.

riky

Coderast: разве речь только про exe? есть еще штуки которые можно декомпилить во вполне читаемый код, flash, андроид приложения например.

Как написать игрового бота на Python для Web

Этот туториал, и код в нем, требует установки нескольких дополнительных библиотек для Python. Они обеспечивают обертку Python’а в кусок низкоуровневого C-кода, который значительно упрощает создание и скорость исполнения.

Некоторые библиотеки существуют только под Windows. У них могут быть эквиваленты под Mac или linux, но мы не будем их рассматривать.

Вам нужно скачать и установить следующие библиотеки:

Все представленные библиотеки комплектуются установщиками. Запуск их автоматически установит модуль в директорию \lib\site-packages и, теоретически, добавит соответствующий pythonPath . Однако, на практике это происходит не всегда. Если Вы получите сообщение об ошибке после установки, добавьте их вручную в переменные Path.

Последний инструмент это графический редактор. Я предлагаю использовать Paint.Net как лучший из бесплатных, но подойдет любая программа с линейками и измерениями в пикеслях.

Мы будем использовать несколько игр в качестве примеров.

Введение

Это руководство написано с целью дать базовое понимание основы разработки ботов для браузерных игр. Подход, который мы собираемся дать, вероятно немного отличается от того, что многие ожидают услышать говоря о ботах. Вместо того, чтобы сделать программу, вставляющую код между клиентом и сервером (как боты для Quake или CS), наш бот будет находиться чисто снаружи. Мы будем опираться на методы Компьютерного зрения и вызовы Windows API для сбора необходимой информации и выполнения движений.

С этим подходом мы теряем часть деталей и контроля, но сокращаем время разработки и получим простоту в использовании. Автоматизирование специфичных игровых функций может быть создано в несколько строк кода, и полноценный бот, от начала до конца (для простой игры) может быть собран за несколько часов.

Когда вы привыкните к тому, что компьютер может видеть, начнете смотреть на игры по-другому. Хороший пример это поиск в играх-пазлах. Обычное решение основывается на ограничении скорости игрока, что заставляет принимать не оптимальные решения. Интересно (и довольно легко) «взломать» их скриптами движений которые не повторить человеку.

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

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

Шаг 1: Создание проекта

В папке с проектом создайте текстовый файл quickGrab, измените расширение на ‘py’ и откройте его в редакторе кода.

Шаг 2: Создаем приложение, которое делает скриншот экрана

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

Вставим в наш файл с проектом quickGrab.py следующий код:

ImageGrab import os import time def screenGrab(): box = () im = ImageGrab.grab() im.save(os.getcwd() + '\\full_snap__' + str(int(time.time())) + '.png', 'PNG') def main(): screenGrab() if __name__ == '__main__': main() 

Запустив этот код, вы получите скриншот экрана:

screenshot

Данный код забирает всю ширину и высоту области экрана и сохраняет в PNG файл в директорию проекта.

Давайте пошагово разберем код, чтобы понять как это работает. Первые три строки:

import ImageGrab import os import time 

. называются ‘import statements’. Они говорят Pytjon’у какие модули загружать во время выполнения. Это дает доступ к методам этих модулей через синтаксис module.attribute .

Первый модуль Python Image Library мы установили ранее. Как следует из названия, он дает нам функциональность взаимодействия с экраном на которую ссылается бот.

Вторая строка импортирует модуль операционной системы (OS — operating system). Он дает возможность простой навигации по директориям в операционной системе. Это пригодится, когда мы начинаем размещать файлы в разных папках.

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

Следующие четыре строки определяют функцию screenGrab() .

def screenGrab(): box = () im = ImageGrab.grab() im.save(os.getcwd() + '\\full_snap__' + str(int(time.time())) + '.png', 'PNG') 

Первая строка def screenGrab() определяет имя функции. Пустые скобки означают, что она не принимает аргументов.

Строка 2, box = () присваивает пустое значение переменной «box». Мы заполним это значение дальше.

Строка 3, im = ImageGrab.grab() создает полный скриншот экрана и возвращает RGB изображение в переменную im .

Строка 4, может быть немного сложнее если вы не очень хорошо знакомы с тем как работает Time module. Первая часть im.save( вызывает метод «save». Он принимает два аргумента. Первый это директория в которую нужно сохранить файл, а второй это формат файла.

Здесь мы устанавливаем директорию вызовом метода os.getcwd() . Функция получает текущую директорию в которой выполняется код и возвращает её как строку. Далее мы добавим «+». Сложение нужно использовать между каждым новым аргументом для соединения всех строк вместе.

Следующая часть ‘\\full_snap__ дает нам простое описание в имени файла. Обратный слеш является экранирующим символом в Python, и мы добавили два, чтобы избежать отмены одного из символов.

Далее идет эта сложная конструкция: str(int(time.time())). Она использует встроенные функции Питона. Мы рассмотрим работу этого куска кода изнутри:

time.time() возвращает количество секунд с начала Эпохи , тип данных Float (число с плавающей точкой). Так как мы используем дату для именования файлов, мы не можем использовать десятичное число, поэтому мы обернем выражение в int() , чтобы конвертировать в целое число (Integer). Это делает нас ближе к решению, но Python не может соединить тип Integer с типом String, поэтому следующим шагом мы обернем все в функцию str(). Далее остается только добавить расширение как часть строки + ‘.png’ и добавить вторым аргументом функции снова расширение: «PNG».

Последняя часть кода определяет функцию main() , которая вызывает функцию screenGrab(), когда исполняется.

И, наконец, условное обозначение, которое позволяет интерпретатору определить, какую функцию запускать в случае, если файл запущен как основной (а не просто импортирован в другой скрипт). В противном случае, если он загружен как модуль другого скрипта — он только передает доступ к этому методу, вместо выполнения.

def main(): screenGrab() if __name__ == '__main__': main() 

Шаг 3: Область видимости

Функция ImageGrab.grab() принимает один аргумент, который определяет область видимости. Это набор координат по шаблону (x,y,x,y), где

  1. Первая пара значение (x,y. определяет левый верхний угол рамки;
  2. Вторая пара . x,y) определяет правый нижний.

Это дает нам возможность скопировать только часть экрана, которая нам нужна.

Рассмотрим это на практике.

Для примера рассмотрим игру Sushi Go Round (Довольно увлекательная. Я Вас предупредил). Откройте игру в новой вкладке и сделайте скриншот использую существующий код screenGrab():

screenshot

Шаг 4: Задание координат

Пришло время задания координат для нашей области видимости.

Откройте скриншот в редакторе картинок.

Координаты (0,0) это всегда левый верхний угол изображения. Мы хотим заполнить X и Y таким образом, чтобы нашему новому скриншоту функция установила координаты (0,0) в крайний левый угол игровой области.

Этому есть две причины. Во-первых, это упрощает нахождение координат, когда мы должны определять координаты относительно игровой области, по сравнению со всем экраном монитора. Во-вторых, захват меньшей части экрана уменьшает нагрузку на процессор. Полноэкранные скриншоты производят довольно много данных, чтобы их можно было циклично повторять несколько раз в секунду.

координаты экрана

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

Наведите курсор на первый пиксель игровой области и запишите координаты на линейках. Это будут первые два значения для нашей функции. У меня получились значения (305, 243).

Затем следуйте к нижнему краю и запишите вторую пару координат. У меня получилось (945, 723). Вместе эти пары дают область с координатами (305,243,945,723).

Давайте добавим координаты в код:

import ImageGrab import os import time def screenGrab(): box = (305,243,945,723) im = ImageGrab.grab(box) im.save(os.getcwd() + '\\full_snap__' + str(int(time.time())) + '.png', 'PNG') def main(): screenGrab() if __name__ == '__main__': main() 

На строке 6 мы обновили массив для хранения координат игровой области.

Сохраните и запустите код. Откройте новое сохраненное изображение и вы увидите следующее:

Отлично! Это идеальный снимок игровой области. Нам не всегда будет требоваться эта напряженная охота за координатами. После того, как мы узнаем о win32api, мы рассмотрим более быстрые методы для установки координат, когда нам нужна идеальная точность.

Шаг 5: Перспективное планирование для гибкости

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

Давайте создадим две новые переменные: x_pad и y_pad. В них будет храниться расстояние между игровой областью и остальным экраном. Это поможет легко портировать код с места на место, так как каждая новая координата будет задаваться относительно двух глобальных переменных, которые мы создадим. Чтобы настроить изменения экрана нужно сбросить эти две переменные.

Так как мы уже сделали измерения, установить отступы для нашей текущей системы достаточно просто. Мы собираемся установить отступы, чтобы хранить положение первого пикселя за пределами игровой площадки. От первой пары координат нашего кортежа вычесть по 1. Получается 304 и 242.

Давайте добавим это в наш код:

# Globals # ------------------ x_pad = 304 y_pad = 242 

Теперь, когда они установлены, мы скорректируем координаты игровой области относительно них.

def screenGrab(): box = (x_pad+1, y_pad+1,945,723) im = ImageGrab.grab(box) im.save(os.getcwd() + '\\full_snap__' + str(int(time.time())) + '.png', 'PNG') 

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

def screenGrab(): box = (x_pad+1, y_pad+1, x_pad+641, y_pad+481) im = ImageGrab.grab(box) im.save(os.getcwd() + '\\full_snap__' + str(int(time.time())) + '.png', 'PNG') 

Для координаты x значение стало 945 — 304 = 641, а для y стало 723 — 242 = 481.

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

Шаг 6: Создание документации

Перед тем как перейти дальше, создадим документацию в начале нашего проекта. Так как большая часть нашего кода будет базироваться на особых координатах экрана и отношении к этим координатам, важно понимать окружение в котором всё будет работать правильно. Например, таких условия как разрешение монитора, браузер, включенная панель инструментов (так как это меняет размер окна браузера), и другие настройки необходимые для центровки игровой области на экране, все это влияет на относительные позиции координат. Документирование всего этого сильно помогает в решении проблем, когда код запускается на разных браузерах и компьютерах.

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

Для примера, я обычно добавляю подобный комментарий в начало моего кода:

""" All coordinates assume a screen resolution of 1280x1024, and Chrome maximized with the Bookmarks Toolbar enabled. Down key has been hit 4 times to center play area in browser. x_pad = 156 y_pad = 345 Play area = x_pad+1, y_pad+1, 796, 825 """ 

Добавление всей этой информации в начало файла позволяет быстро и легко перепроверить все настройки и выравнивание экрана без необходимости корпеть над кодом, пытаясь вспомнить, где вы сохранили конкретную x-координату.

Шаг 7: Делаем quickGrab.py удобным инструментом

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

Сохраните и закройте текущий проект.

Создайте копию проекта в этой же папке и переименуйте файл в code.py . Теперь добавление и редактирование всех изменений мы будем производить в code.py, а quickGrab.py оставим исключительно для скриншотов. Только добавим одно финальное изменение: изменим расширение на .pyw

Это расширение сообщает Питону, что нужно запускать скрипт без открытия консоли. Двойной клик по файлу и он быстро выполнится в фоне и сохранит скриншот в рабочую директорию.

Держите игру открытой в фоне (не забудьте отключить зацикленную музыку, иначе она сведет вас с ума); мы скоро к ней вернемся. У нас еще есть несколько инструментов для внедрения, прежде чем начать контролировать вещи на экране.

Шаг 8: win32api — краткий обзор

Работать с win32api может быть немного сложно на начальном этапе. Это обертка в низкоуровневый Windows C, которых хорошо задокументирован здесь, но навигация похожа на лабиринт, так что пару раз придется пройти по кругу.

Если при выполнении Вы видите ошибку «ImportError: No module named win32api», значит не установлен этот модуль. Выполните в консоли команду pip install pypiwin32

Прежде чем мы начнем писать код, давайте поближе познакомимся с некоторыми функциями API на которые далее мы будем опираться. После того как у нас появится четкое понимание каждого параметра, мы сможем легко настроить их для наших целей в игре.

win32api.mouse_event( dwFlags, dx, dy, dwData ) 

Первый параметр dwFlags определяет «действия» мыши. Такие как перемещение, клик, скроллинг и т.п. Следующий список показывает распространенные параметры, используемые для программирования движений.

  • win32con.MOUSEEVENTF_LEFTDOWN
  • win32con.MOUSEEVENTF_LEFTUP
  • win32con.MOUSEEVENTF_MIDDLEDOWN
  • win32con.MOUSEEVENTF_MIDDLEUP
  • win32con.MOUSEEVENTF_RIGHTDOWN
  • win32con.MOUSEEVENTF_RIGHTUP
  • win32con.MOUSEEVENTF_WHEEL

Имена говорят сами за себя. Если вы хотите выполнить виртуальный правый клик, нужно отправить параметр win32con.MOUSEEVENTF_RIGHTDOWN в dwFlags.

Следующие два параметра, dx и dy, описывают абсолютную позицию вдоль осей x и y. Пока мы будем использовать эти параметры для программирования движения мыши, они будут использовать систему координат отличную от той, которую мы использовали до этого. Мы зададим нули и будем опираться на другую часть API для движения мыши.

Четвертый параметр это dwData. Эта функция используется тогда и только тогда, когда dwFlags содержит MOUSEEVENTF_WHEEL. В других случаях она может быть опущена или установлена в 0. dwData скорость прокрутки колеса мыши.

Простой пример для закрепления

Если мы представим игру с переключением оружия как в Half-Life 2 (где оружие может быть выбрано вращением колеса) — мы можем использовать эту функцию для выбора оружия из списка:

def browseWeapons(): weaponList = ['crowbar','gravity gun','pistol'. ] for i in weaponList: win32api.mouse_event(win32con.MOUSEEVENTF_MOUSEEVENTF_WHEEL,0,0,120) 

Здесь мы хотим симулировать скроллинг колеса мыши для навигации по нашему теоретическому списку оружия, поэтому мы вносим . MOUSEEVENTF_WHEEL в dwFlag. Не нужно указывать позиционирование dx и dy, оставим эти значения 0, и нам нужен один скрол вперед для каждого оружия в списке, поэтому устанавливаем значение 120 для dwData, что соответствует одному скролу мыши.

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

Шаг 9: Клики мыши

Мы переходим к созданию трех новых функций. Одна общая функция нажатия левой кнопки мыши, и два обработчика состояний нажатия и отпускания.

Откройте code.py в редакторе и добавьте следующее выражение к списку импортов

import win32api, win32con

Как и ранее, это дает нам доступ к содержимому модуля через синтаксис module.attribute

Далее создадим первую функцию клика мыши

def leftClick(): win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN,0,0) time.sleep(.1) win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP,0,0) print "Click." #completely optional. But nice for debugging purposes. 

Напомню, что все, что мы делаем здесь это назначаем действие первому аргументу mouse_event. Мы не должны указывать никакую информацию о позиционировании, поэтому мы опускаем параметры координат (0,0), и мы не должны указывать дополнительную информацию, такую как dwData. Функция time.sleep(.1) говорит Питону приостановить выполнение на время указанное в скобках. Добавим это в наш код. Обычно это очень короткий промежуток времени. Без этого клик может получиться до того, как меню обновится.

Мы создали функцию для левого клика. Один раз нажать, один раз отпустить. Мы потратили много времени на нее, но давайте создадим еще две вариации. Это тоже самое, но теперь каждый шаг мы разобьем на отдельную функцию. Это можно использовать когда нам надо удерживать нажатой мышь в течение продолжительного времени (например, для перетаскивания предметов или стрельбы.)

def leftDown(): win32api.mouse_event(win32con.MOUSEEVENTF_LEFTDOWN,0,0) time.sleep(.1) print 'left Down' def leftUp(): win32api.mouse_event(win32con.MOUSEEVENTF_LEFTUP,0,0) time.sleep(.1) print 'left release' 

Шаг 10: Простые движения мышью

Все, что остается это движение мыши по экрану. Добавим следующие функции в файл code.py

def mousePos(cord): win32api.SetCursorPos((x_pad + cord[0], y_pad + cord[1]) def get_cords(): x,y = win32api.GetCursorPos() x = x - x_pad y = y - y_pad print x,y 

Эти две функции служат совершенно разным целям. Первая будет использоваться для задания движения в программе. Благодаря соглашению об именовании, тело функции делает именно то, что обозначает название SetCursorPos() . Вызов этой функции устанавливает координаты мыши по заданным (x,y). Обратите внимание, что мы добавили поправки x_pad и y_pad к координатам; это важно делать там, где координаты объявляются.

Вторая функция это простой инструмент который мы будем использовать в интерактивном режиме. Он выводит в консоль координаты текущей позиции мыши. Это сильно ускоряет процесс навигации в меню без необходимости делать скриншот и пользоваться линейками. Мы не хотим постоянно использовать эту функцию, так как некоторая активность мыши будет требовать точного позиционирования, но там где это возможно, это хорошо сэкономит нам время.

На следующем шаге мы применим эти техники для начала навигации в игровом меню. Но сначала надо удалить текущий контент у main() в сode.py и заменить его на тот, который мы написали. На следующем шаге мы будем работать с интерактивным режимом , поэтому функция screenGrab() нам пока не понадобиться.

Шаг 11: Навигация в меню

В этом и в следующих нескольких этапах мы попытаемся собрать координаты для разных событий используя метод get_cords(). Используя его мы сможем быстро построить код для таких вещей как навигация по меню, очистка столов, приготовление еды. После сбора мы встроим их в логику бота.

Давайте начнем. Сохраните и запустите код в Python Shell. С тех пор как на прошлом шаге мы заменили тело функции main() на pass , вы должны увидеть пустое окно после запуска Shell.

Теперь прежде чем перейти к игровой части, нужно пройти 4 начальных меню.

  1. Кнопка «Play»
  2. Кнопка «continue»
  3. Пропустить обучение «skip»
  4. Кнопка «continue»

Мы должны получить координаты каждой кнопки и добавить их в новую функцию startGame() . Расположите на экране Shell так, чтобы была видна игровая область. Нужно поставить мышь на кнопку, координаты которой нужно получить и выполнить в Shell функцию get_cords(). Убедитесь, что активным окном является Shell. Мы получим в Shell’е координаты текущей позиции мыши. Повторите это для остальных трех окон.

Оставьте Shell открытым и настройте экран так, чтобы видеть IDLE редактор. Добавим функцию startGame() и заполним новыми координатами.

def startGame(): #location of first menu mousePos((182, 225)) leftClick() time.sleep(.1) #location of second menu mousePos((193, 410)) leftClick() time.sleep(.1) #location of third menu mousePos((435, 470)) leftClick() time.sleep(.1) #location of fourth menu mousePos((167, 403)) leftClick() time.sleep(.1) 

Теперь у нас есть компактная функция, которую можно вызывать на старте каждой игры. Она устанавливает курсор на каждую позицию в меню, которую мы заранее определили и кликает. time.sleep(.1) говорит Питону остановить выполнение на 1/10 секунды между каждым кликом, чтобы меню успевало обновляться между кликами. Сохраните и запустите код.

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

Шаг 12: Зададим координаты еды

Давайте повторим процесс для каждой кнопки.

меню с едой

С помощью get_cords(), соберите координаты еды из меню. Еще раз в Python Shell напишите get_cords(), наведите мышь на еду и выполните команду.

Как вариант, для ускорения работы, если у вас есть второй монитор или вы можете организовать расположение таким образом, чтобы видеть браузер и окно Shell, можно не вводить каждый раз get_cords(), а сделать простой цикл for . Используйте метод time.sleep() чтобы успевать перемещать мышь между итерациями цикла.

for i in range(6): time.sleep(1.2) print get_cords() 

Нам нужно создать новый класс Cord , чтобы хранить в нем собранные координаты. Возможность вызова через Cord.f_rice дает большие преимущества, так как можно передававть координаты прямо в mousePos() . Как вариант, можно хранить всё в словарях, но я нахожу синтаксис классов более удобным.

class Cord: f_shrimp = (40,340) f_rice = (90, 340) f_nori = (40, 387) f_roe = (90, 387) f_salmon = (40, 440) f_unagi = (90, 440) 

Мы будем хранить много наших координат в этом классе, там будет некоторое дублирование, поэтому добавив префикс ‘f_’ мы будем знать, что это ссылка на еду, а не, скажем, на заказ еды по телефону.

Продолжим добавлять координаты.

Шаг 13: Координаты пустых мест

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

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

""" Plate cords: 87, 208 194, 208 288, 208 395, 208 491, 208 591, 208 

Осталось всего несколько шагов до действительно интересных штук.

Шаг 14: Координаты телефона

Итак, это будет последняя часть координат. Здесь понадобиться намного больше действий, поэтому вы можете сделать это вручную функцией get_cords() , вместо цикла. Мы собираемся прокликать всё меню телефона, чтобы получить координаты каждого пункта.

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

Есть шесть меню, через которые нам надо пройти.

  1. Телефон
  2. Начальное меню
  3. Начинки
  4. Рис
  5. Доставка

Нам нужно получить координаты всех, кроме Саке (можете её тоже добавить, если хотите. На мой взгляд бот отлично работает и без нее).

class Cord: f_shrimp = (40,340) f_rice = (90, 340) f_nori = (40, 387) f_roe = (90, 387) f_salmon = (40, 440) f_unagi = (90, 440) #----------------------------------- phone = (574, 358) menu_toppings = (528, 273) t_shrimp = (495, 224) t_nori = (490, 287) t_roe = (574, 279) t_salmon = (494, 340) t_unagi = (576, 218) t_exit = (591, 342) menu_rice = (532, 293) buy_rice = (548, 281) delivery_norm = (490, 292) 

Окей! Мы наконец собрали все необходимые координаты. Давайте создадим что-нибудь полезное!

Шаг 15: Убираем со стола

Мы используем координаты собранные ранее для создания функции clear_tables().

def clear_tables(): mousePos((87, 208)) leftClick() mousePos((194, 208)) leftClick() mousePos((288, 208)) leftClick() mousePos((395, 208)) leftClick() mousePos((491, 208)) leftClick() mousePos((591, 208)) leftClick() time.sleep(1) 

Как вы можете видеть, это выглядит более менее похоже на нашу прошлую функцию startGame(). С одним небольшим отличием: нет функции time.sleep() между кликами. Нам не нужно ждать обновления меню, поэтому не нужно ждать задержку между кликами.

Однако, у нас есть функция time.sleep() в самом конце. Хотя это и не обязательно, лучше добавить паузы в выполнение кода, чтобы была возможность вручную завершить цикл, если это потребуется. В противном случае скрипт будет менять позицию мыши снова и снова и вы не будете в состоянии переместить фокус на Shell, чтобы остановить сценарий. Это прикольно первые два или три раза, но быстро теряет свое очарование.

Шаг 16: Создание суши

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

''' Recipes: onigiri 2 rice, 1 nori caliroll: 1 rice, 1 nori, 1 roe gunkan: 1 rice, 1 nori, 2 roe ''' 

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

def makeFood(food): if food == 'caliroll': print 'Making a caliroll' mousePos(Cord.f_rice) leftClick() time.sleep(.05) mousePos(Cord.f_nori) leftClick() time.sleep(.05) mousePos(Cord.f_roe) leftClick() time.sleep(.1) foldMat() time.sleep(1.5) elif food == 'onigiri': print 'Making a onigiri' mousePos(Cord.f_rice) leftClick() time.sleep(.05) mousePos(Cord.f_rice) leftClick() time.sleep(.05) mousePos(Cord.f_nori) leftClick() time.sleep(.1) foldMat() time.sleep(.05) time.sleep(1.5) elif food == 'gunkan': mousePos(Cord.f_rice) leftClick() time.sleep(.05) mousePos(Cord.f_nori) leftClick() time.sleep(.05) mousePos(Cord.f_roe) leftClick() time.sleep(.05) mousePos(Cord.f_roe) leftClick() time.sleep(.1) foldMat() time.sleep(1.5) 

Эта функция такая же как и все остальные, но с одним небольшим отличием: мы не передаем координаты непосредственно, а вызываем их в качестве атрибутов класса Cord .

Функция foldMat() вызывается в конце каждого приготовления. Она кликает по циновке, чтобы завернуть суши, которое мы приготовили. Давайте зададим её:

def foldMat(): mousePos((Cord.f_rice[0]+40,Cord.f_rice[1])) leftClick() time.sleep(.1) 

Давайте кратко пройдемся по функции mousePos() . Мы обращаемся к первому значению f_rice через добавление [0] в конце атрибута. Напомню, что это координата x. Для клика по циновке нам необходимо добавить небольшое смещение по оси х, и мы прибавим 40 к значению координаты x и передадим f_price[1] в y. Это сдвинет нашу позицию по x достаточно, чтобы активировать циновку.

Обратите внимание, что после вызова foldMat() у нас идет длинный time.sleep() . Циновка будет закручиваться и ингредиенты будут не доступны для клика, поэтому придется подождать конца анимации.

Шаг 17: Навигация в телефонном меню

В этом шаге мы зададим все точки mousePos() для подходящий пунктов меню, координаты которых были оставлены для этого момента. Эта часть программы которая будет обернута и контролируема логикой бота. Мы вернемся к этой функции, после того как обзаведемся несколькими новыми техниками.

def buyFood(food): mousePos(Cord.phone) mousePos(Cord.menu_toppings) mousePos(Cord.t_shrimp) mousePos(Cord.t_nori) mousePos(Cord.t_roe) mousePos(Cord.t_salmon) mousePos(Cord.t_unagi) mousePos(Cord.t_exit) mousePos(Cord.menu_rice) mousePos(Cord.buy_rice) mousePos(Cord.delivery_norm) 

Краткое введение в компьютерное зрение

Сейчас в нашем распоряжении имеются очень интересные куски кода. Давайте рассмотрим как научить компьютер «видеть» события. Это очень увлекательная часть процесса.

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

Другая большая часть в написании бота это обучение игре. Понимание какие значения нужно отслеживать в игре, а какие можно игнорировать. Например, можно не отслеживать деньги в кассе. Это то, что в конечном счете не имеет отношения к боту. Все, что ему надо знать это достаточно ли еды, чтобы продолжать работать. Таким образом, вместо того, чтобы мониторить количество денег, он просто проверяет, может ли бот что-то купить независимо от цены, потому что в игре это вопрос лишь нескольких секунд. Поэтому если бот не может что-то купить, он просто ждет несколько секунд.

Это подводит нас к финальной точке. Это брутфорс против элегантного решения. Алгоритмы зрения требуют значительного процессорного времени. Проверка нескольких точек во многих разных областях игровой области могут сильно снижать производительность. Таким образом все сводится к вопросу «должен бот узнать о том что что-то случилось или нет?»

Например, посетитель может проходить через четыре состояния: отсутствует, ожидает, ест и закончил есть. Когда закончил есть, он оставляет пустую тарелку. Мы могли бы затратить ресурсы на проверку всех мест просмотрев их, а затем кликнуть напротив ожидаемой тарелки (что может приводить к ошибкам, так как тарелки мигают, давая ложный сигнал). Или можно убирать их простым перебором, прокликивая все места через каждые несколько секунд. На практике прокликивание оказывается таким же эффективным, как и элегантное решение, позволяющее определить состояние клиента. Прокликать шесть мест занимает доли секунды, в то время как захват и обработка шести изображений сравнительно медленный способ. Мы можем использовать сэкономленное время для других более важных задач, связанных с обработкой изображений.

Шаг 18: Импорт библиотек Numpy и ImageOps

Добавим следующие выражения импорта

import ImageOps from numpy import * 

ImageOps это еще одна библиотека для работы с изображениями Python’а. Она используется для выполнения операций над изображениями (таких как перевод в черно-белый формат).

Я кратко поясню вторую строку для тех, кто близко не знаком с Питоном. Стандартное выражение импорта загружает пространство имен модуля (коллекцию имен переменных и функций). Таким образом, для доступа к элементам из области видимости мы используем синтаксис module.attribute . Однако, используя выражение from _ import мы наследуем имена в локальную область видимости. То есть синтаксис module.attribute больше не нужен. Это не верхний уровень, поэтому мы можем использовать их как встроенные функции Питона, как str() или list() . Импорт Numpy таким способом дает нам возможность просто вызвать array() вместо numpy.array().

Символ * означает импорт всего из модуля.

Шаг 19: Создаем компьютерное зрение

Первый метод сравнивает значения RGB у пикселей с ожидаемым значением. Этот метод отлично подходит для статичных объектов, таких как меню. Так как нужно иметь дело с конкретными пикселями, то метод не слишком надежен для движущихся объектов. Однако, это варьируется от случая к случаю. Иногда это отличная техника, а в другой раз приходится искать другой метод.

Запустите Sushi Go Round в браузере и начните новую игру. Откройте телефонное меню. Можете пока не обращать внимание на посетителей. Вы начинаете игру без денег, поэтому все пункты меню будут серыми как показано ниже. Это и будут те значения RGB, которые мы будем проверять.

В code.py перейдите к функции screenGrub() . Нужно внести следующие изменения:

def screenGrab(): b1 = (x_pad + 1,y_pad+1,x_pad+640,y_pad+480) im = ImageGrab.grab(b1) ##im.save(os.getcwd() + '\\Snap__' + str(int(time.time())) +'.png', 'PNG') return im 

Мы сделали два небольших изменения. Во—первых, мы закомментировали строку, которая сохраняет скриншот. Во—вторых, на шестой строке мы возвращаем объект с изображением после выполнения функции.

Сохраните и запустите код.

Во время того как открыто телефонное меню и все пункты серые, выполните следующий код:

>>>im = screenGrab() >>> 

Это сохранит скриншот, который мы сделали с помощью функции screenGrub() в переменную im . Теперь мы можем вызвать функцию getpixel(xy) чтобы получить данные о заданных пикселях.

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

Мы же имеем необходимые координаты после выполнения предыдущих шагов, поэтому просто передадим их в качестве аргументов в функцию getpixel() и запишем результаты.

>>> im = screenGrab() >>> im.getpixel(Cord.t_nori) (109, 123, 127) >>> im.getpixel(Cord.t_roe) (127, 61, 0) >>> im.getpixel(Cord.t_salmon) (127, 71, 47) >>> im.getpixel(Cord.t_shrimp) (127, 102, 90) >>> im.getpixel(Cord.t_unagi) (94, 49, 8) >>> im = screenGrab() >>> im.getpixel(Cord.buy_rice) (127, 127, 127) >>> 

Если мы добавим эти значения в функцию buyFood() , чтобы знать доступна покупка в данный момент или нет.

def buyFood(food): if food == 'rice': mousePos(Cord.phone) time.sleep(.1) leftClick() mousePos(Cord.menu_rice) time.sleep(.05) leftClick() s = screenGrab() if s.getpixel(Cord.buy_rice) != (109, 123, 127): print 'rice is available' mousePos(Cord.buy_rice) time.sleep(.1) leftClick() mousePos(Cord.delivery_norm) time.sleep(.1) leftClick() time.sleep(2.5) else: print 'rice is NOT available' mousePos(Cord.t_exit) leftClick() time.sleep(1) buyFood(food) if food == 'nori': mousePos(Cord.phone) time.sleep(.1) leftClick() mousePos(Cord.menu_toppings) time.sleep(.05) leftClick() s = screenGrab() print 'test' time.sleep(.1) if s.getpixel(Cord.t_nori) != (109, 123, 127): print 'nori is available' mousePos(Cord.t_nori) time.sleep(.1) leftClick() mousePos(Cord.delivery_norm) time.sleep(.1) leftClick() time.sleep(2.5) else: print 'nori is NOT available' mousePos(Cord.t_exit) leftClick() time.sleep(1) buyFood(food) if food == 'roe': mousePos(Cord.phone) time.sleep(.1) leftClick() mousePos(Cord.menu_toppings) time.sleep(.05) leftClick() s = screenGrab() time.sleep(.1) if s.getpixel(Cord.t_roe) != (127, 61, 0): print 'roe is available' mousePos(Cord.t_roe) time.sleep(.1) leftClick() mousePos(Cord.delivery_norm) time.sleep(.1) leftClick() time.sleep(2.5) else: print 'roe is NOT available' mousePos(Cord.t_exit) leftClick() time.sleep(1) buyFood(food) 

Мы передаем имя ингредиента в функцию buyFood() . Серия выражений if/else получает переданный параметр и дает соответствующий ответ. Каждая ветка следует одинаковой логике, поэтому мы рассмотрим только одну.

if food == 'rice': mousePos(Cord.phone) time.sleep(.1) leftClick() mousePos(Cord.menu_rice) time.sleep(.05) leftClick() s = screenGrab() time.sleep(.1) 

Первое, что мы должны сделать это кликнуть на телефон и открыть нужное меню. В этом случае меню с рисом.

s = screenGrab() if s.getpixel(Cord.buy_rice) != (109, 123, 127): 

Далее мы делаем скриншот области и вызываем getpixel() , чтобы получить RGB-значение пикселя у координат Cord.buy_rice . Мы сравниваем их с RGB-значением пикселя, полученного до этого на неактивном элементе. Если мы получаем в результате сравнения значение True , значит кнопка больше не серая и у нас достаточно денег для покупки. Соответственно, если получаем False , значит не можем себе это позволить.

print 'rice is available' mousePos(Cord.buy_rice) time.sleep(.1) leftClick() mousePos(Cord.delivery_norm) time.sleep(.1) leftClick() time.sleep(2.5) 

Если у нас достаточно денег, мы просто проходим через оставшиеся этапы, необходимые для покупки.

else: print 'rice is NOT available' mousePos(Cord.t_exit) leftClick() time.sleep(1) buyFood(food) 

Наконец, если нам не хватает денег, то мы говорим боту закрыть меню, подождать секунду и повторить все сначала. Обычно это вопрос секунд, когда нам снова становится доступна покупка. Довольно просто добавить дополнительную логику, чтобы бот мог решить, нужно ли продолжать ждать или заняться в это время чем-то полезным и вернуться позже.

Шаг 20: Следим за ингредиентами

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

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

Количество каждого ингредиента остается постоянным на старте каждого уровня. Всегда начинаем с 10 обычных ингредиентов (рис, нори, икра), и по 5 дефицитных ингредиентов (креветки, лосось, угорь).

Начальные ингредиенты

Давайте добавим информацию о них в массив.

foodOnHand =

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

Шаг 21: Добавим отслеживание продуктов в код

Каждый раз, когда мы готовим, мы расходуем ингредиенты. И также пополняем их, когда делаем покупки. Давайте немного расширим нашу функцию makeFood()

def makeFood(food): if food == 'caliroll': print 'Making a caliroll' foodOnHand['rice'] -= 1 foodOnHand['nori'] -= 1 foodOnHand['roe'] -= 1 mousePos(Cord.f_rice) leftClick() time.sleep(.05) mousePos(Cord.f_nori) leftClick() time.sleep(.05) mousePos(Cord.f_roe) leftClick() time.sleep(.1) foldMat() time.sleep(1.5) elif food == 'onigiri': print 'Making a onigiri' foodOnHand['rice'] -= 2 foodOnHand['nori'] -= 1 mousePos(Cord.f_rice) leftClick() time.sleep(.05) mousePos(Cord.f_rice) leftClick() time.sleep(.05) mousePos(Cord.f_nori) leftClick() time.sleep(.1) foldMat() time.sleep(.05) time.sleep(1.5) elif food == 'gunkan': print 'Making a gunkan' foodOnHand['rice'] -= 1 foodOnHand['nori'] -= 1 foodOnHand['roe'] -= 2 mousePos(Cord.f_rice) leftClick() time.sleep(.05) mousePos(Cord.f_nori) leftClick() time.sleep(.05) mousePos(Cord.f_roe) leftClick() time.sleep(.05) mousePos(Cord.f_roe) leftClick() time.sleep(.1) foldMat() time.sleep(1.5) 

Теперь каждый раз при приготовлении Суши, мы уменьшаем значения наших ингредиентов на соответствующие значения. Теперь дополним код в функции buyFood()

def buyFood(food): if food == 'rice': mousePos(Cord.phone) time.sleep(.1) leftClick() mousePos(Cord.menu_rice) time.sleep(.05) leftClick() s = screenGrab() print 'test' time.sleep(.1) if s.getpixel(Cord.buy_rice) != (127, 127, 127): print 'rice is available' mousePos(Cord.buy_rice) time.sleep(.1) leftClick() mousePos(Cord.delivery_norm) foodOnHand['rice'] += 10 time.sleep(.1) leftClick() time.sleep(2.5) else: print 'rice is NOT available' mousePos(Cord.t_exit) leftClick() time.sleep(1) buyFood(food) if food == 'nori': mousePos(Cord.phone) time.sleep(.1) leftClick() mousePos(Cord.menu_toppings) time.sleep(.05) leftClick() s = screenGrab() print 'test' time.sleep(.1) if s.getpixel(Cord.t_nori) != (33, 30, 11): print 'nori is available' mousePos(Cord.t_nori) time.sleep(.1) leftClick() mousePos(Cord.delivery_norm) foodOnHand['nori'] += 10 time.sleep(.1) leftClick() time.sleep(2.5) else: print 'nori is NOT available' mousePos(Cord.t_exit) leftClick() time.sleep(1) buyFood(food) if food == 'roe': mousePos(Cord.phone) time.sleep(.1) leftClick() mousePos(Cord.menu_toppings) time.sleep(.05) leftClick() s = screenGrab() time.sleep(.1) if s.getpixel(Cord.t_roe) != (127, 61, 0): print 'roe is available' mousePos(Cord.t_roe) time.sleep(.1) leftClick() mousePos(Cord.delivery_norm) foodOnHand['roe'] += 10 time.sleep(.1) leftClick() time.sleep(2.5) else: print 'roe is NOT available' mousePos(Cord.t_exit) leftClick() time.sleep(1) buyFood(food) 

Шаг 22: Проверка запасов еды

Теперь когда функции makeFood() и buyFood() могут менять количество ингредиентов, нам нужно создать функцию, которая будет отслеживать что количество какого-то ингредиента стало ниже критического уровня.

def checkFood(): for i, j in foodOnHand.items(): if i == 'nori' or i == 'rice' or i == 'roe': if j  

Мы будем циклом обходить пары ключ:значение в массиве с запасами ингредиентов. Если нори, риса или икры останется меньше 4, вызывается функция buyFood(), параметром в которую передается имя ингредиента.

Шаг 23: Перевод RGB значений - Установка

Для того, чтобы двигаться дальше, мы должны получать информацию о том, какой тип суши запрашивает клиент. Сделать это с помощью функции getpixel() было бы достаточно тяжело, так как нам пришлось бы искать область с уникальным значением RGB для каждого вида суши для каждого посетителя. Кроме того, для каждого нового типа суши, вам придется вручную осмотреть его, чтобы увидеть, есть ли у него уникальный RGB, который не найден ни в одном из других типов суши. Это значит, что нам пришлось бы хранить 6 мест, по 8 типов суши. Это 48 уникальных координат.

Очевидно, нам нужен метод попроще.

Метод номер два: усреднение изображения. Этот способ работает с набором RGB-значений, вместо конкретного пикселя. Для каждого скриншота, переведенного в оттенки серого, и загруженного в массив, мы просуммируем все пиксели. Эта сумма обрабатывается также как значение RGB в методе getpixel() .

Гибкость этого метода в том, что, когда он настроен, от нас больше ничего не требуется. По мере ввода новых суши, их значения RGB суммируются и выводятся для нашего использования. Нет необходимости искать конкретные координаты с помощью getpixel() .

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

Найдите уже написанную функцию screenGrab() и скопируйте ее рядом. Переименуйте копию в grab() , и внесите следующие изменения:

def grab(): box = (x_pad + 1,y_pad+1,x_pad+641,y_pad+481) im = ImageOps.grayscale(ImageGrab.grab(box)) a = array(im.getcolors()) a = a.sum() print a return a 

На второй строке мы переводим скриншот в оттенки серого и записываем в переменную im . Такой скриншот позволяет работать с ним намного быстрее, так как вместо 3 значений Красного, Зеленого и Голубого, каждый пиксель имеет только одно значение от 0 до 255.

На третьей строчке мы создаем массив значений цветов использую PIL метод getcolors() и записываем в переменную im .

На четвертой строке мы суммируем все точки и выводим их в консоль. Это число по которому мы будем сравнивать изображения.

Шаг 24: Зададим области для скринов заказов

Начните новую игру и дождитесь когда все посетители рассядутся по своим местам. Сделайте скрин двойным кликом по quickGrab.py .

Области с заказами

Нам нужно задать ограничивающие области внутри каждого из этих спич-баблов (белые облака с рисунком суши). Приблизьте из в редакторе так, чтобы было видно пиксели:

Области с заказами

Для каждого спич-бабла мы должны быть уверены что верхний левый край начинается в одном и том же месте. Для этого отступим два пикселя от внутреннего края спич-бабла. Первый белый пиксель на второй ступеньке будет началом отсчета.

Области с заказами

Для создания пары координат, отсчитайте 63 по оси x и 16 по оси y. Это даст подобный прямоугольник:

Области с заказами

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

Приступим к созданию 6 новых функций, каждая будет уточнением функции grab() и будет передавать аргументом координаты спич-баблов. Как только закончим, создадим функцию, запускающую их все сразу для тестирования.

def get_seat_one(): box = (45,427,45+63,427+16) im = ImageOps.grayscale(ImageGrab.grab(box)) a = array(im.getcolors()) a = a.sum() print a im.save(os.getcwd() + '\\seat_one__' + str(int(time.time())) + '.png', 'PNG') return a def get_seat_two(): box = (146,427,146+63,427+16) im = ImageOps.grayscale(ImageGrab.grab(box)) a = array(im.getcolors()) a = a.sum() print a im.save(os.getcwd() + '\\seat_two__' + str(int(time.time())) + '.png', 'PNG') return a def get_seat_three(): box = (247,427,247+63,427+16) im = ImageOps.grayscale(ImageGrab.grab(box)) a = array(im.getcolors()) a = a.sum() print a im.save(os.getcwd() + '\\seat_three__' + str(int(time.time())) + '.png', 'PNG') return a def get_seat_four(): box = (348,427,348+63,427+16) im = ImageOps.grayscale(ImageGrab.grab(box)) a = array(im.getcolors()) a = a.sum() print a im.save(os.getcwd() + '\\seat_four__' + str(int(time.time())) + '.png', 'PNG') return a def get_seat_five(): box = (449,427,449+63,427+16) im = ImageOps.grayscale(ImageGrab.grab(box)) a = array(im.getcolors()) a = a.sum() print a im.save(os.getcwd() + '\\seat_five__' + str(int(time.time())) + '.png', 'PNG') return a def get_seat_six(): box = (550,427,550+63,427+16) im = ImageOps.grayscale(ImageGrab.grab(box)) a = array(im.getcolors()) a = a.sum() print a im.save(os.getcwd() + '\\seat_six__' + str(int(time.time())) + '.png', 'PNG') return a def get_all_seats(): get_seat_one() get_seat_two() get_seat_three() get_seat_four() get_seat_five() get_seat_six() 

Отлично! Много кода, но это только вариации функции ImageGrab.Grab . Теперь нужно перейти в игру и протестировать. Нужно убедиться, что не зависимо от того в каком спич-бабле находится суши, один и тот же заказ отображает одну и ту же сумму.

Шаг 25: Создаем массив с типами Суши

Как только Вы убедились, что каждый тип суши дает одинаковое значение суммы пикселей, запишите эти суммы в массив:

sushiTypes =

Здесь значение стоит на месте ключа потому, что по нему будет осуществляться поиск.

Шаг 26: Создаем массив мест без спич-баблов

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

Нужно начать игру и выполнить функцию get_all_seats() до того как придет первый посетитель. Полученные значения запишем в массив Blank .

class Blank: seat_1 = 8041 seat_2 = 5908 seat_3 = 10984 seat_4 = 10304 seat_5 = 6519 seat_6 = 8963 

Шаг 27: Соединяем все вместе

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

Основа логики будет следующая: Проверка мест > Проверка заказов > Если не хватает ингредиентов, то купить > почистить столы > Повторить сначала

def check_bubs(): checkFood() s1 = get_seat_one() if s1 != Blank.seat_1: if sushiTypes.has_key(s1): print 'table 1 is occupied and needs %s' % sushiTypes[s1] makeFood(sushiTypes[s1]) else: print 'sushi not found!\n sushiType = %i' % s1 else: print 'Table 1 unoccupied' clear_tables() checkFood() s2 = get_seat_two() if s2 != Blank.seat_2: if sushiTypes.has_key(s2): print 'table 2 is occupied and needs %s' % sushiTypes[s2] makeFood(sushiTypes[s2]) else: print 'sushi not found!\n sushiType = %i' % s2 else: print 'Table 2 unoccupied' checkFood() s3 = get_seat_three() if s3 != Blank.seat_3: if sushiTypes.has_key(s3): print 'table 3 is occupied and needs %s' % sushiTypes[s3] makeFood(sushiTypes[s3]) else: print 'sushi not found!\n sushiType = %i' % s3 else: print 'Table 3 unoccupied' checkFood() s4 = get_seat_four() if s4 != Blank.seat_4: if sushiTypes.has_key(s4): print 'table 4 is occupied and needs %s' % sushiTypes[s4] makeFood(sushiTypes[s4]) else: print 'sushi not found!\n sushiType = %i' % s4 else: print 'Table 4 unoccupied' clear_tables() checkFood() s5 = get_seat_five() if s5 != Blank.seat_5: if sushiTypes.has_key(s5): print 'table 5 is occupied and needs %s' % sushiTypes[s5] makeFood(sushiTypes[s5]) else: print 'sushi not found!\n sushiType = %i' % s5 else: print 'Table 5 unoccupied' checkFood() s6 = get_seat_six() if s6 != Blank.seat_6: if sushiTypes.has_key(s6): print 'table 1 is occupied and needs %s' % sushiTypes[s6] makeFood(sushiTypes[s6]) else: print 'sushi not found!\n sushiType = %i' % s6 else: print 'Table 6 unoccupied' clear_tables() 

Первое что мы делаем — это проверяем запасы. Далее делаем скрин позиции заказа первого посетителя и записываем в s1. После этого проверяем скрин на неравенство пустому месту. Если они не равны, значит у нас есть посетитель. Далее проверяем массив sushiTypes чтобы определить какой заказ сделал посетитель и передаем этот аргумент в функцию makeFood() .

Clear_tables() выполняется через проверку каждых двух мест.

Теперь надо это зациклить.

Шаг 28: Главный цикл

Мы создаем цикл. Так как мы не задаем никакого условия выхода из цикла, то чтобы завершить игру, нужно в консоли нажать CTRL + C.

def main(): startGame() while True: check_bubs() 

Вот и все! Обновите страницу, дождитесь загрузки игры и запустите бота!

Бот немного неуклюжий и нуждается в доработках. Но это отличный скелет для того чтобы продолжить экспериментировать!

Как создать игру в Телеграме

Игры в Телеграме появились в 2016 году. Они представлены как HTML5 и чат-боты. В них можно играть самому с собой, с одним собеседником в переписке или с несколькими людьми в чате, открытом или приватном. Это игры с разнообразной графикой и звуком. Чтобы разработать такую игру, нужно от 3 часов до нескольких месяцев, в зависимости от планов и задуманного масштаба.

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

Больше об арбитраже трафика и в целом о Партнеркине можно узнать в нашем основном телеграм-канале, а если хочется узнать больше о различных приложениях и принципах работы с ними, переходите по этой ссылке.

Какие игры можно создавать в Телеграме

Можно создавать не только простые, но и сложные игры. Простые HTML-5 игры похожи на игры в ICQ вроде War Sheep, Zoopaloola, Rock Paper Scissors. Их не нужно скачивать и отдельно устанавливать на телефон. Возможно играть прямо в браузере мессенджера, например в десктопной версии Телеграма, на iPhone новее 4+, Android 4,4+.

Преимущества простых игр: низкий порог входа как для разработчика, так и для игрока. Разработать такую игру может человек с нулевыми техническими навыками. Цель игры с самой простой механикой — набрать больше очков, выиграть у других людей. Для каждой группы игроков составляется турнирная таблица. Когда кто-то начинает выбиваться в победители, остальные получают уведомления об этом.

Также возможности Телеграм позволяют разработать сложный многоуровневый 3D-шутер, масштабную ролевую игру в стиле фэнтези или постапокалипсиса, крупную стратегию в реальном времени. Если требуется игра, выполняющая широкий круг задач, с продвинутым геймплеем и механикой, скорее всего будет нужна команда и более мощное сложное оборудование.

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

Рынок Телеграм-игр: что в тренде

Создать игру может любой человек — Телеграм предоставляет для этого ресурсы. Для разработки такой простой игры достаточно несколько часов. Примеры: игра MathBattle была создана за 3 часа, Corsairs — за 5 часов, включая разработку, графику, музыку.

Чтобы найти другие примеры, можно воспользоваться ботом Gamee. Основные жанры — стратегии, RPG, баттлеры, интерактивные квесты, многопользовательские текстовые игры или MUD — Multi User Dungeon.

Разновидности популярных игр:

  • Логические мини-игры, включая карточные, интеллектуальные. StrawberryLogicBot, M0n0Bot, PokerBot, ruassoc_bot, krestikiBot. В Телеграме можно сыграть в Мафию, кости, покер, крестики-нолики, слова с ботом или с друзьями.
  • Текстовые игры. Они реализуются с помощью переписки. Questgamebot, viselkaBot, BastionSiegeBot, ChatWarsBot, EverlastingSummerBot, villagegamebot, WastelandWarsBot (про эту игру кейс далее). Механика таких игр может включать в себя жанры фэнтези или постапокалипсиса, симулятор средневековых войн, квесты, чаты, кланы, визуальную новеллу с интерактивными вариантами развития сюжета.
  • Викторины и квизы. Pandaquizbot, QuizariumBot, natgeowild2. Такие игры включают десятки тысяч вопросов разной сложности, игровой чат и даже возможность получения дополнительного дохода. Например, в natgeowild2 нужно быстро успевать отвечать на вопросы и заработать реальные деньги за выигрыш. С помощью этих ботов можно прокачаться в разных областях знаний: география, история, музыка, спорт, биология, точные науки, литература.

  • Гонки. F1 Racer, Moto FX, Beach Racer. Механика представляет собой симулятор гонок на разных видах транспорта, нужно обгонять соперников, быстрее добраться до финиша.
  • Релакс. Color Hit, Disco Ball, Mars Rover, Paint.IO, Sunshine Solitare. Игры для медитации, чиллаута, основное назначение — дать пользователю возможность отдохнуть, расслабиться, разгрузить мозг.
  • Экшн. Tube Runner, Gravity Ninja, Gateway, Pixel Dungeon, ATARI Asteroids. Игры, которые требуют от пользователя высокой скорости реакции. Многие из них имеют достаточно продвинутый сложный геймплей.
  • Аркады. Space Traveler, Geometry Run 3D, Neon Blaster, Karate Kido. Похожи по механике на логические и экшн-игры, предполагают активное выполнение разных действий. Например, перепрыгивания с одной плиты на другую.
  • Спорт. Penalty Shooter, Keep it UP, Football Star, Doozie Dunks, Pocket World Cup. Это симуляторы различных спортивных игр, например футбол, хоккей.
  • Быстрые. Skipper, Crazy Cat, Little Plane, Ding Dong, Spiky Fish. В игре нужна высокая скорость реакции, персонаж передвигается слишком быстро.
  • Сумасшедшие, Crazy. Tube Runner, Kung Fu Inc., Paintball Pandas, Qubo. Такой жанр выделен отдельно в каталоге игр Телеграм Gamee, обозначает игры с необычным эпатажным сюжетом и нестандартной механикой.
  • Паззлы. 99 Blocks, 1+2=3, Ten 2 One, Kingdoms of 2048, Bratz Pop, Tents and Trees. Относятся к подвиду логических игр.

Кейс Максима Газизова: создание MMORPG — аналога Fallout

Кейс доказывает востребованность Телеграм-игр. Разработчик мобильных приложений Максим Газизов искал идею для игры и создал комплексную survival-MMORPG Wasteland Wars в формате бота для Telegram — t.me/WastelandWarsBot. В своем кейсе он подчеркивает, что на идею повлиял растущий тренд развития Телеграма как мессенджера. В Телеграме есть возможность создать игру и сразу получить для нее аудиторию.

Игры в Телеграме в схожем жанре постапокалипсиса востребованы у людей 18-50 лет, разного социального статуса — то есть у платежеспособной взрослой аудитории. Максим отмечает, что некоторые игроки проводят в игре-боте 16-18 часов в день.

Механика игры основана на текстовом формате. Чтобы создать игру, нужно только писать; нет необходимости делать сложную графику, звук. В игре Максима есть сюжетные квесты, лут, торговля, альянсы, битвы, NPC, рейды на боссов, наземный и подземный открытый мир. При создании Максим делал акцент на максимально простой интерфейс для пользователя, качественный UI/UX, буквально выверял каждую кнопку.

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

Результаты: В игру играло 500-1 000 человек в сутки. Средний суточный онлайн зависел от игровых событий, запланированных на этот день, праздников, выходных, поэтому менялся каждый день.

Реализована монетизация. За реальные деньги можно купить игровую валюту, за которую можно сменить ник, фракцию или на короткое время ускорить передвижение по Пустоши. Сколько было заработано за время существования проекта, автор кейса не дает такую информацию.

Как игра и геймплей выглядят для пользователя

Пользователь переходит в каталог @Gamee. В открывшемся окне бот предложит выбрать тип или жанр игры. Пользователь может выбрать, с кем ему играть — самому с собой (с ботом-NPC), с друзьями, либо с неизвестными противниками из числа пользователей Телеграм.

Если пользователь хочет сыграть с друзьями, он нажимает на With Friends и выбирает друга из списка контактов. Этому другу бот присылает ссылку-приглашение, друг переходит и участвует в игре. Игру можно остановить в любой момент, продолжить позднее — действует сохранение. Пользователь может управлять своими действиями в игре с помощью кнопок в боте.

Преимущества Телеграм-игр для пользователя:

  • игра не занимает места на телефоне, не перегружает оперативную память;
  • вашему другу-соигроку не нужно добавлять себе бота;
  • подходящую игру всегда легко найти, например с помощью ключевого слова в поиске;
  • пользователь может скачать игру из Телеграма себе на устройство или ПК.

Один из несущественных минусов — запуск происходит через облако, возможны зависания на несколько секунд.

Для чего создавать игру в Телеграм и как монетизировать

Условия Телеграм запрещают напрямую монетизировать игры, оставлять в них ссылки на сторонние ресурсы и сайты. Но игрового бота можно применять в рекламных, маркетинговых, мотивационных целях:

  • Корпоративное обучение, геймификация процесса. Например, когда сотруднику нужно пройти викторину, квиз на полученные знания.
  • Нестандартный подарок. Создать игру, индивидуально предназначенную для конкретного человека.
  • Рекламный проект. Создать тематическую игру, где клиенты могут выиграть приз.
  • Монетизация с помощью внедрения функционала магазина и ссылки на платежный кабинет сайта. Например, внутриигровой магазин реализован в Happy Farmer.

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

Анализ конкурентов и поиск идей

Анализ конкурентов поможет сэкономит время, даст понимание, что работает, а что нет. Как проводить анализ конкурентов и поиск идей перед разработкой:

  • выбрать наиболее подходящие проекты из ниши: другие Телеграм-игры, сервисы, приложения;
  • тестировать каждый такой сервис и проект, выписывать в отдельную таблицу лучшие практики;
  • смотреть на ключевые механики и их реализацию;
  • посмотреть показатели сайта или приложения через сервисы аналитики, например с помощью SimilarWeb.

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

Создавали бота или игру в Телеграме?
444 голоса

Упрощенное создание игры через бота @BotFather

Чтобы разработать игру, нужно воспользоваться ботом @BotFather. Этапы работы:

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

После создания игру можно отправлять в группы, чаты — также как обычное сообщение. Также её можно отправить в inline-режиме.

Под сообщением с игрой будет кнопка inline, которая начинает игру. Если пользователь решает поиграть, жмет на кнопку, боту приходит call-back с информацией о выбранной игре. Разработчик отвечает уникальным url, который сформирован для этого конкретного игрока. Приложение открывает игру у игрока в браузере.

Самые высокие ставки по RU, BY, KZ от прямого рекламодателя FONBET PARTNERS! К заливам!

Если кнопка не будет добавлена разработчиком, система сама добавит ее автоматически. Также кроме кнопки запуска, можно добавлять другие кнопки, например с правилами, ссылками на официальный ТГ-канал.

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

В интерфейсе игры система предусматривает постоянную кнопку «Поделиться» вверху экрана. Разработчик может настроить другие кнопки на HTML-странице. Нажав на них, можно открыть желаемый чат и отправить туда сообщение с количеством набранных очков.

Если в URL используется хэш, то Telegram может к нему что-то добавить от себя. Названия добавленных параметров будет начинаться с tg. Чтобы достать собственные параметры из адреса, можно воспользоваться объектом TelegramGameProxy.initParams.

Дизайн Телеграм-игр

Дизайн похож на классические HTML5-игры. Важно учитывать вес и размер изображений: фона, игровых элементов. Если они будут тяжелыми, это может негативно сказаться на скорости игры. Лучше выбирать векторные изображения, а не растровые.

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

Окно Телеграма может растягиваться благодаря автомасштабированию по ширине. Игра должна быть адаптивной, подходить под любые разрешения. Для больших окон можно добавлять небольшие поля, из-за того что рендеринг изображений на больших экранах отнимает много ресурсов. Экраны и раскадровки анимаций можно собрать в Figma или обратиться за помощью к опытным специалистам-фрилансерам.

В игре Happy Farmer поля фермы динамически генерируются под каждого игрока:

Возможности коммуникации с игроками ограничены. Можно передавать сообщения игрового мира с помощью HTML-разметки. Получить ответ игрока затруднительно. Чтобы отправить такое сообщение, пользователь должен создать команду через знак «/», а это умеют не все. В сообщение может быть встроенная клавиатура, но добавить ее достаточно сложно для разработчика. Если игра должна быть локализована на много языков и работать на всех типах устройств — сложностей прибавляется.

На клавиатуре могут отображаться символы из набора UTF-16. При создании любой игры все основные игровые предметы должны помещаться в этот набор. Игроку такая стандартизация удобна: алмаз в одной игре — премиум-валюта, значит, в другой — тоже что-то ценное.

Преимущества текстовых игр без графики

Текстовая направленность имеет плюс для разработчиков, которые не любят «заморачиваться» с красивой графикой. Текстовые игры создавать проще, расширять за счет текста мир. Помимо локализации понадобится качественная адаптация при выходе на разные рынки.

Преимущество текстовых игр:

  • высокая скорость разработки;
  • нет ограничений по игровому миру;
  • можно добавлять в игру ситуации любых масштабов;
  • возможна любая степень проработки игрового мира;
  • не нужно мощное оборудование для разработки.

Есть опыт разработки текстовых игр?

Особенности разработки

Для создания Телеграм-игр подойдут любые технологии и библиотеки, которые доступны в браузере: JavaScript, WebGL-библиотеки, 3D-графика. Конечно, для работы с некоторыми веб-технологиями, возможно, придется освоить языки программирования на базовом уровне.

Например, движок Pixi.js удобен для игр, где используются столкновения объектов в игровой механике. Pixi.js предлагает подробную документацию, с которой разберется frontend-разработчик любого уровня.

В движениях объектов может применяться растровая графика, либо векторные анимации, например lottie-файлы, другие виды svg-анимации.

Чтобы игра интегрировалась в Телеграме, заработала в нем, нужен доступ в интернет. Также игра должна отправлять информацию об очках в API Телеграма. Поэтому нужен веб-сервер, который будет получать сообщения из Телеграм, отдавать игру с отмеченным идентификатором игрока, принимать от Frontend очки и отправлять их в API.

В конце игры очки игрока должны идти с frontend на backend. Из игры нужно отправлять запросы с подставленными очками и идентификатором пользователя. Этот идентификатор передается в ссылке на саму игру. Его нужно сохранить на время, чтобы вернуть обратно с набранным количеством очков. Для этого пишется код в Frontend.

Понадобится сервер, с которого игроки будут подгружать игру и где будет размещаться Телеграм-бот. Также будет нужен SSL-сертификат, посколько Телеграм работает с играми по HTTPS-протоколу для безопасного общения. Такой сертификат, привязанный к домену или поддомену, можно получить у Let's Encrypt.

Сервера для разработки игр в Телеграм

Для игры не обязательно брать мощный сервер. Можно воспользоваться недорогим облачным вариантом, для решения небольших задач.

Топ-1 хостинг 2023

От расположения сервера зависит скорость доступа игроков из разных городов. Например, если предполагается, что ЦА — жители России, желательно выбирать сервера, которые находятся в Москве или Санкт-Петербурге. Операционную систему можно взять Ubuntu 20.04, либо выбрать другую или свой образ ISO или виртуальной машины.

  1. Если это игра с простой механикой, можно выбрать фиксированную конфигурацию с возможностью оплаты части ядра. Доля vCPU будет отражать производительность сервера. Она может оказаться выше заявленного, в зависимости от нагрузки на хост. Может хватить одного ядра или 50% этого ядра. Если не будет хватать мощности, можно сменить конфигурацию сервера.
  2. Выбрать размер диска. Так как не предполагается хранить много файлов, для операционки и кода можно взять до 5-10 Гб.
  3. Выбрать 1 публичный IP, запомнить пароль от root пользователя или загрузить публичный SSH-ключ. Далее нужно создать и установить сервер.
  4. Когда IP-адрес сервера будет получен, к нему можно подключиться по SSH. К серверу подключается домен. В настройках DNS-хостинга нужно указать A-запись на нужный домен или поддомен, значение в виде IP-адреса нового только что созданного сервера. Если домен новый и DNS-хостинга пока нет, можно подключить бесплатный DNS на панели управления.
  5. Подключиться к серверу по SSH, либо через консоль, настроить ngnix — веб-сервер, который будет работать с SSL.
  6. Запустить ngnix, перейти в папку с конфигурацией сервера, создать файл конфигурации, открыть его в текстовом редакторе и добавить в него настройки сервера.
  7. Сохранить файл. Таким образом ngnix будет перенаправлять запросы к домену на 3 000 порт, по которому отвечает backend.
  8. Проверить, что в конфигурации нет ошибок, сгенерировать бесплатный SSL-сертификат, чтобы игра была доступна по HTTPS.
  9. Воспользоваться утилитой Certbot и установить игру.
  10. Сгенерировать сертификат. Он будет отвечать по HTTPS. Затем нужно настроить и запустить его.

Создание Телеграм-бота для игры

Чтобы создать бота, нужно запустить botfather в Телеграме, вызвать в меню команду newbot, далее по инструкциям получить токен доступа. Этот токен нужно сохранить в конфиденциальном месте, не показывать третьим лицам во избежание того, что кто-то может представиться вашим ботом. Далее потребуется включить возможность делиться игрой с друзьями через inline-запросы.

Затем нужно вызвать команду newgame и создать игру. Понадобится принять условия работы. Если нарушить эти правила — игру удалят с платформы. Запрещено:

  • размещать рекламу, любые внешние ссылки;
  • взимать оплату с игроков;
  • использовать личные данные пользователей для рассылок, делиться ими с другими сторонними сервисами;
  • устанавливать cookie в игре.

Этапы работы с ботом:

  1. Добавить название, описание, обложку 640х360, превью-гифку такого же размера. Гифка не является обязательной составляющей, но лучше загрузить ее, чтобы игра выглядела более привлекающей внимание.
  2. Настроить сервер, объединить составляющие.
  3. Установить систему Docker для создания контейнеров для кода. Это облегчит работу, позволит не устанавливать node.js, npm и зависимости.
  4. Взять из репозитория env.example, Dockerfile, index.json и package.json. Их нужно скопировать на сервер.
  5. Открыть env.example, подставить в него токен, ссылку на фронтенд, доступный из интернета, ID игры, который был сообщен BotFather; env.example нужно переименовать в .env (mv env.example .env).
  6. В Frontend-коде настроить отправку очков на нужный домен.
  7. Создать Docker-образ приложения и запустить приложение.

Тестирование

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

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

Участвовали в проекте, связанном с геймификацией в бизнесе?

Кейс Библиотеки Программиста: создание игрового Telegram-бота

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

Сначала бот должен был давать задачи, их можно было пропускать, постоянно вызывая одну и ту же команду. Нашелся выход: сохранение текущей команды в базе: получая команду /get, бот дает задачу и сохраняет команду. Затем, перед тем как отреагировать на сообщения в чате, бот сравнивает команду, которую получил прямо сейчас, с последней командой в базе. Если они совпадают, бот никак не реагирует и вдобавок удаляет команду пользователя, чтобы она не висела в чате.

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

Для написания бота использовались Composer — стандарт при разработке на PHP, библиотека telegram-bot-sdk, symfony/dotenv для парсинга .env-файла. Composer позволяет скачивать сторонние библиотеки на проект и предоставляет механизм по автозагрузке классов. Вся работа с Composer происходит через консоль и в файле composer.json.

Файл app.php — точка входа в приложение, где вешается веб-хук. Это значит, что бот не будет постоянно опрашивать сервер на наличие обновлений; он их будет получать только тогда, когда они будут.

Затем нужно создать объекты всех нужных классов, проверить, в каком вы чате — приватном или супергруппе. Код можно разделить на независимые части. Настройки хранятся в файле .env, что позволяет пользователи вводить свои, и бот будет работать после создания всех нужных таблиц.

Кейс Selectel: создание игры с постройком башни из серверов

В кейсе команда Selectel создала игру, механика которой — построить башню из серверов. Цель — PR и реклама: среди клиентов-игроков проводился конкурс, те, кто построят от 100 этажей, участвуют в розыгрыше призов с мерчем.

В игре не была задействована физика, при которой пришлось бы подумать, как будут раскачиваться блоки на кране и башня. В качестве усложнения игры был добавлен летающий тиранозавр — брендовый персонаж Selectel.

Было отрисовано 3 персонажа и 3 локации. Стройка башни начиналась под землёй, затем шла в городе и после 50 блоков-этажей продолжалась в космосе. Фон был 23 000 пикселей: его пришлось разделять на 4 части, так как Android-смартфоны не справились с отрисовкой.

Для движения крана применялась растровая графика. Движение было заанимировано отдельно и вставлена уже готовая анимация. Для этого команда Selectel использовала спрайты — картинки, кадры анимации и спрайт-листы — наборы всех элементов графики. Загружалась картинка с несколькими спрайтами, это было экономичнее по ресурсам, чем грузить несколько картинок каждую отдельным файлом. В качестве сервера Selectel использовал свой вариант Shared Line.

Как продвигать игру в Телеграм

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

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

Примеры таких каналов:

  • av_games — канал с новостями про игры, также здесь бывают раздачи, информация о скидках в сторах приложений;
  • EasyAPK — канал, где можно бесплатно скачивать APK-файлы приложений для Android;
  • theappbox — канал для владельцев iOS-устройств, на котором можно бесплатно устанавливать приложения;
  • egs_tg — канал Epic Games Store, который еженедельно дарит одну игру.

Основные способы продвижения, которые используют разработчики:

  • сарафанное радио, виральность — когда вокруг проекта создается хайп, об игре узнают лояльные и преданные представители ЦА;
  • продвижение на других платформах;
  • каталоги ботов, например Storebot.me, Telegrambots.info.
  • обзоры и подборки в Telegram-группах, каналах, посвященных развлекательной тематике.

Другая сложность с маркетингом заключается в том, что в Телеграме трудно отслеживать статистику по пользователям, их данные. Этот мессенджер поддерживает анонимность. Даже с помощью инструментов парсинга можно собрать информацию по людям только из своих чатов и каналов, но не из чужих. Поэтому трудно проанализировать активность игроков, поведение пользователей в игре.

Но есть бот, который ведет лог взаимодействий: игра находится на сервере, любое взаимодействие игрока — команда на сервер. Другие способы получить статистику: использовать обобщенные числовые показатели, собирать обратную связь от аудитории.

Локализация и работа с аудиторией

Телеграм — международный мессенджер. Игра должна быть понятна всем пользователям. Если в планах стоит создать топовый проект, нужно задуматься о локализации минимум на 5 языков. Лучше ориентироваться не только на распространенные европейские языки вроде английского, французского, немецкого или испанского, но добавить португальский, персидский, арабский, так как на них говорит значительно большая часть населения планеты.

Можно столкнуться со сложностью в части развития проекта. Если в игре будут постоянные обновления, внедрения новых механик, важно собирать обратную связь от аудитории. Для этого потребуется игровой чат. Все пользователи разные, среди них может быть много неадекватных людей, которые пользуются анонимностью в Telegram. В итоге чатом может быть сложно управлять.

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

Кейс Dev’s Battle: MMORPG для повышения hard skill разработчиков

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

В течение первых 3 недель команда анализировала конкурентов, аудиторию, тренды, определялась с сеттингом. Для анализа конкурентов были рассмотрены Java Rush, LeetCode, CodeWars, Habitika, Жабабот, Mimo, Яндекс Практикум, Light Bot. Из этих проектов разработчики взяли «лучшие практики» и фишки. Смотрели на то, что мотивирует пользователей делиться контентом и приглашать друзей, с какими проблемами они сталкиваются, какие у аудитории предпочтения.

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

Механики, которые придумала команда Dev’s Battle:

  • решение задач на языки программирования;
  • артефакты MMORPG: развитие персонажа, скиллы, игровая валюта, боссы, уровни прокачки;
  • мультиплеерные фишки: рейтинги, ачивки, баттлы.

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

На 6-15 неделе команда занималась разработкой MVP и основных механик. За 2 недели были собраны участники проекта: Middle Python Developer, опытный ментор-консультант. Использовали стек Python, Django, PostgreSQL, PyTelegrambotAPI, Nginx, grafana. Разработку вели по спринтам в Jira, первые 2-3 недели работали над базой данных.

После базы данных разработчики перешли к основным механикам, затем к онбордингу и дополнительным фишкам, которые решили запустить на стадии раннего MVP. На 10-й неделе уже была готовность к закрытому бета-тестированию, но выявилось много багов, которые устранялись в течение 5 последующих недель. Например, бесконечное количество карточек, падение крона, остановка бота, неверный расчет рейтинга.

Игра продвигалась с помощью посевов в ТГ-каналах, дополнительный PR шел через интервью с пользователями. В последующие недели разработчики внедряли новые фичи, делали расширенную аналитику, тестировали гипотезы, локализовали проект под бурж.

Результаты: 1269 зарегистрированных игроков спустя 3 недели с момента релиза. Всего на разработку и все этапы ушло 20 недель. Благодаря качественному онбордингу получилось 70% конверсии из входа в регистрацию и старт игры.

Эксперты отвечают

М Максим Газизов, разработчик мобильных приложений

В чем основные проблемы при разработке Телеграм-игр и как их можно решать?

Сложности связаны с платформой Bot API. У Telegram есть 2 системы для связи их ботов с вашим сервером: Long Polling и Webhooks. Long Polling: сервер будет с определенным интервалом опрашивать Telegram на предмет наличия новых запросов, и при наличии обрабатывать, возвращая ответ Bot API. Webhooks: сервер говорит Telegram «если у тебя появятся какие-то запросы – кидай их вот на этот адрес». Для реализации бота на Webhooks необходим постоянный IP адрес и обязательно SSL сертификат. У Long Polling есть проблема: бот начинает тормозить, постоянно перезапускаться, причиняет неудобства игрокам. Лучше делать проект на Webhooks.

Другие сложности появляются, когда проект набирет масштабы. Бот может начать «подтупливать» при получении запроса. С нагрузкой на сервер это не связано: бот упирается в лимит Bot API по количеству одновременных запросов. С этой проблемой можно справиться, написав в поддержку Телеграм, попросить увеличить лимиты. Чаще всего бот упирается в лимиты по типу запросов callback на inline-кнопки. В случае моего проекта пришлось перерабатывать интерфейс.

Третий вид проблем — в среде разработки и коде, конкретно, в Python 3 и в том, как он работает с потоками. Каждый новый поток в Python 3 создается вместе с переменными окружения, занимая большое количество памяти. В игре полно таймеров, и когда они запускались в отдельных потоках, возникала утечка памяти. По мере роста игры утечка достигла безумных масштабов, сжирая оперативную память и подкачивая оставшуюся память SSD сервера. Это было решено созданием очередей таймеров, обрабатывающихся в одном потоке для каждого типа.

Р Ростислав Бородин, Full-Stack веб-разработчик, куратор школы GeekON

Из каких этапов состоит создание текстового квеста?

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

Чтобы создать собственного бота, сперва его надо зарегистрировать с помощью @BotFather и далее следовать его инструкциям. После того, как мы введем название бота, @BotFather сообщит нам токен — пароль к нашему почтовому ящику.

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

Удобнее всего хранить все данные, которые привязаны к конкретному пользователю в словаре. Ключом в этом словаре будет id пользователя, а значением — произвольные данные. Нужно использовать разные переменные хранения слова, чтобы сообщения от разных пользователей не путались.

Следующий этап — добавить несколько кнопок к сообщению и реагировать на их нажатия. На финальном этапе собирается текстовый квест полностью.

Вывод

Игры в Телеграм не целесообразно рассматривать как конкурентов классических мобильных игр. Telegram-игры занимают свою отдельную нишу. Возможности ботов ограничены, не стоит ждать слишком продвинутого функционала и геймплея. В основном большинство игр направлены на то, чтобы скоротать время и создаются за 3-5 часов. Но при грамотном анализе трендов, аудитории можно создать масштабный популярный и востребованный проект.

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

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