Мы с вами установили IDE Eclipse и создали в ней свой первый проект. Но пришла пора заняться чем-то посерьезней! Поскольку обучение легче всего происходит в игровой форме, предлагаю вашему внимаю небольшую консольную игру. Крестики-нолики, так же известную как tic-tac-toe:-).
Теперь нам необходимо определиться с тем, как мы собственно будем писать нашу игру? Прежде всего нам нужно игровое поле. Пусть это будет двумерный символов размером 3×3 (почитать про разные ). Если в какой-то клетке игрового поля у нас ничего нет, то ставим туда например плюсик, если в ячейке нолик пусть это будет буква «О» если крестик то буква «Х». Начнем с задания самого поля:
// Игровое поле public static char field = { { "+", "+", "+" }, { "+", "+", "+" }, { "+", "+", "+" } };
Наше игоровое поле представляет собой двумерный символов Field, все значения в котором задаются при его создании. О том, что этот массив двумерный говорят две квадратные скобочки после описания типа char. При этом сначала у нас везде стоят плюсики — т.е. все поле свободно. Следующее, что мы сделаем — это организуем ход пользователя:
// Ход человека public static void HumanMove() throws IOException { int x , y; System.out.println("Enter y (1..3):"); BufferedReader br = new BufferedReader(new InputStreamReader(System.in)); x = Integer.parseInt(br.readLine())-1; System.out.println("Enter x (1..3):"); y = Integer.parseInt(br.readLine())-1; while (field[x][y] == "0" || field[x][y] == "X" || x < 0 || x > 2 || y < 0 || y > 2) { System.out.println("Enter x:"); x = Integer.parseInt(br.readLine())-1; System.out.println("Enter y:"); y = Integer.parseInt(br.readLine())-1; } field[x][y] = "X"; }
Итак, что же здесь происходит? Первая строка — это описание матода, который реализует ход человека. О методах и их описании этом мы поговорим попозже. Во второй строке объявляются две переменные x и y, это будут координаты, куда поставит крестик игрок. Затем, с помощью конструкции System.out.println() мы выводим на экран приглашение ввести координату по оси Y. В следующей строке создается буфферизированный поток br с помошью которого можно считывать из консоли вводимые пользователем строки.
В строке 7 конструкция х=Integer.parseInt(String p) преобразует строковый параметр p в целочисленное значение и это значение мы записываем в переменную х.
Думаю две следующие строки, думаю, понятны по аналогии 🙂 А вот дальше мы проверяем в цикле с предусловием во-первых, не попал ли ход игрока на уже занятое поле, во-вторых, не выходят ли введенные пользователем цифры за границы нашего игрового поля. Если хоть одно из этих условий не выполняется, тогда мы заново просим ввести позицию Y и X. Ну а если все нормально, то цикл не выполнится и мы запишем на игровое поле ход игрока.
Теперь думаем что делать со вторым игроком. Поскольку заморачиваться на стратегии игры мне совсем не хотелось то бот ходит просто случайно. Алгоритм очень прост и код сильно напоминает предидущий кусок:
// Ход компьютера (random-бот) public static void CompMove() { int x = (int) (Math.random() * 3), y = (int) (Math.random() * 3); while (field[x][y] == "0" || field[x][y] == "X") { x = (int) (Math.random() * 3); y = (int) (Math.random() * 3); } field[x][y] = "0"; }
Здесь Math.random() генерирует случайное число в интервале от 0 до 1, затем полученное число мы умножаем на три и округляем до целого. В итоге получаем числа X и Y в итервале от нуля до двух включительно. Проверяем, может ли бот сделать ход на полученные координаты, и если не может, то точно так же генерируем два новых числа и проверяем их. Алгоритм прост и реализация, как мне кажется не должна вызывать вопросов.
Следующий метод определяет остались ли еще на игровом поле свободные клетки.
Public static boolean CanMove() { boolean p = false; for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { if (field[i][j] == "+") { p = true; break; } } if (p = true) { break; } } return p; }
В переменной p изначально хранится значение false (ложь). То есть сначала считаем, что свободных клеток не осталось. А потом начинаем проверять, есть ли они на самом деле или их нет. Мы проходим по каждой клетке игрового поля (два вложенных друг в друга цикла for) и если () где-то встречаем хоть одну свободную клетку, то записываем в p значение true (истина) и прерываем циклы. Затем при любом раскладе мы возващаем значение p. Получается что если мы встретили хоть одно пустое поле, то мы вернем истину, а если свободных клеточек больше не осталось, то вернем ложь.
Следующий метод просто выводит на экран содержимое игрового поля:
// Вывод игрового поля на экран public static void PrintField() { for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { System.out.print(field[i][j]); } System.out.println(); } }
В этой статье будет рассказано про крестики-нолики на Java под Android за 30 строк кода пять с половиной тысяч строк кода, и зачем потребовалось так много кода на такую простую игру.Ровно год назад, 9 декабря я выложил свою игру на Google Play. Теперь я хочу рассказать про то, что произошло за этот год, как росла популярность игры, что сработало, а что - нет.Вы увидите чистую статистику загрузок и удалений за год существования игры, цифры. Узнаете, сколько пользователей можно собрать с Google Play, как создавалась игра, как тестировалась. Вы узнаете, возможно ли создать инди-игру с нулевым бюджетом, какие трудности могут возникнуть у небольшой игры в большом мире.Кому интересно, добро пожаловать.
Введение
Я давно пробовал делать игрушки, в основном простые. После изучения Java решил попробовать сделать что-то полезное на этом языке. Узнав, что можно на Java под Android игры писать, я решил попробовать сделать что-то простое, чтобы научиться делать приложения под смартфоны.Идея
Теперь нужна идея, слишком простая, чтобы не было жалко времени в случае неудачи, и слишком уникальная, чтобы приложение не осталось просто очередным названием в многомиллионном списке приложений.Я выбрал крестики-нолики. Слишком просто? Таких игр много? Вот теперь нужно было придумать что-то уникальное. Почему сейчас все компьютерные крестики-нолики работают по принципу кликнул – поставил? Вот и решил я, что пусть фигуры рисуют, а игра сама определит, что нарисовано.Теперь, как сделать реализацию? Варианты:- Каждая клетка – растровое изображение. Недостаток: нельзя рисовать за границей, иначе выглядит криво, расход памяти. Достоинства: простота. Аналог такого уже есть в Интернете, но не для мобильного.
- Всё поле – растровое изображение. Недостаток: вот и ищи фигуры по всему изображению, наверное печатный текст проще распознать, чем кривые фигуры найти, проблема разъединения склеенных фигур, большая нагрузки на ЦП. Достоинство: можно рисовать крестик, наезжая на соседнюю клетку.
- Фигуры – векторные. Недостатки: возможно перерисовка долгая (но решить можно с помощью буферизации). Достоинства: можно разделять наехавшие друг на друга фигуры, легко можно изменить положение отдельных фигур.
Реализации
UPD: Особенности игры, которые требовалось реализовать:- Рисование фигур игроком, распознавание нарисованных фигур
- Разный размер игрового поля: от 3x3 до 12x12 (можно и больше, но ограничения накладывают размеры экрана многих устройств)
- Соответственно, игра не только 3 в ряд, но и 4, 5, 6 в ряд
Выбор среды разработки и общего плана создания
Пока я искал на чём писать под Android, скачивался Eclipse, изучалась документация, я решил начать на том что было установлено у меня - на NetBeans. Я подумал, что в андроиде Java такая же, как и простая Java, они должны быть почти одинаковы, значит логику (движок) можно писать отдельно.По моему плану игра должна была разделяться на два пакета: Engine и GUI. Engine - движок игры, игровая логика, этот пакет почти не зависит от реализации GUI и ОС, имеет интерфейс взаимодействия с GUI: приём входящих событий, и вывод. GUI - зависит от ОС. Для портирования на Андроид нужно заменить только GUI, не трогая Engine, или почти не трогая. Такой был мой план.Идея была хорошая, но в момент перевода под Android возникла проблема с адаптацией (описано дальше).Разработка игры
Цикл разработки программы
Чтобы точно знать, что делать, я решил записать по пунктам, что моя игра должна делать, что нужно реализовать. Сначала я взял листок, на котором записал основные разделы: Движок, ИИ, Графика, Баги и т. п., затем по каждой категории расписывал проблемы, которые нужно решить. По мере решения я отмечал галочками, что было сделано, по мере бездельниченья пополнял списки новыми идеями, по мере отладки увеличивал раздел «баги» и иногда другие разделы. Потом у меня закончился второй листок, но двух листов вполне хватило.Так как разработка и поддержка планировались не за пару дней, а на длительный период, для планирования и лучшей поддержки, использовались не только листы с пунктами, также было решено хорошо комментировать код (см Javadoc).Разработка игры была разделена на 2 этапа: сделать версию под PC, перенести на Android.Первая версия (альфа) была сделана под PC. Было реализовано по этапам:- простой GUI, рисование линий мышкой, клетки. Распознавание линий как крестиков и ноликов. (Раскрашивание фигур, в соответствии с распознанной фигурой было сделано для отладки распознавания фигур, затем, так как это получилось красиво, это было оставлено в игре)
- правила победы, игра человек с человеком.
- игровой ИИ, режим игры с компьютером.
- составление перечня основных требований
- программирование
- проверка результата и отладка. При выявлении ошибок, несовместимых с жизнью работой программы, переход на пункт 1)
- составление перечня проблем
- программирование
- проверка результата и отладка. Теперь искалось что можно улучшить.
- Проверка игры: запуск на эмуляторе с разными размерами экрана, игра.
- Составление списка проблем
- Исправление проблем
Как ИИ писался
Разработка Бота (в игре для сокращения применялся термин ИИ) для простых крестиков ноликов выглядит несложной задачей. Но я хотел, чтобы этот ИИ был универсальным: работал на поле любого размера, и не только в игре 3 в ряд, но и n-в ряд. Некоторые реализации ИИ работали хорошо на большом поле, но легко проигрывали на маленьком поле, или наоборот.Так как каждая реализация ИИ требовала проверки не только на какую-то работоспособность, но и на возможность победить в игре, то сначала мне приходилось тестировать ИИ вручную - просто играть с ним. Но, это было слишком медленно, и оценка успеха была субъективна, поэтому я нашёл другой способ тестировать ИИ. ИИ был целиком реализован ввиде класса, поэтому была сделана отдельная программа по тестированию ИИ: запускались два разных класса ИИ, которые играли на виртуальном игровом поле, данные по результатам выводились в консоль (кто победил, за сколько ходов). Так же, если было нужно, выводились данные по каждому ходу в текстовом формате (игровая ситуация, что ИИ думает о выгодности каждой клетки).За эталон хорошо играющего противника был взять open-source ИИ из игры 5 в ряд, которую нашёл на launchpad. Тесты проводились несколько раз, чтобы уменьшить влияние случайности.Так было сделано 2 ИИ: нормальный и сложный. Они сильно отличались по реализации: сложный ИИ работал по принципу трассировок возможных путей, а средний по простому принципу: перебор клеток, куда поставить чтобы победить, или не проиграть, или хотя-бы близко что-то стояло, иначе random. По этому, пока я не оптимизировал алгоритм анализа победы (версия 1.5), сложный ИИ был во много раз быстрее, чем средний и лёгкий, в играх с полем больше чем 3x3. После того, как из среднего ИИ было выкинуто не лишнее, появился лёгкий уровень сложности.Код
Кратко про код игры на Java: всего чисто исходники занимают 275 кБ, из них 75% Engine. Код разбит на три пакета, использовано около 22 классов. Всего 5670 строк кода, но много комментариев, закомментированных частей и пустых строк, поэтому чистого кода около 4000, в среднем по 250 строк на 1 класс (файл). Основной движок писался за пару недель, можно было ускорить и до одной недели.При написании кода, опасные места, где могла бы возникнуть ошибка (например, конструкция получилась слишком запутанная), я помечал комментариями // FIXME и // TODO. Концентрация комментариев: один FIXME на 400 строк кода и около 1 TODO на 60 строк кода. Когда в процессе тестирования выявлялись недостатки я либо сразу понимал что исправить, либо ошибки находились именно в этих строках.Также, перед каждым релизом, я тестировал игру, играя по 5-10 раз с разными настройками.Спойлер про тест
При шаманстве тестировании мультитача вместо багов в игре нашёл баг в Android, повторить возможно, используя все 10 пальцев, совершая сложные движения по экрану. Для восстановления работоспособности устройства после этого требуется перезагрузка.
В результате получилось надёжное приложение, о чём свидетельствует отчёт «Сбои и ANR».
Однако, есть ещё объяснения этому: использовались try - catch блоки, что не очень хорошо, но в некоторых случаях при сбое, приложение автоматом должно отключать «экспериминтальные» функции и переходить на их более старые версии; либо у Google эта страница не работает; или слишком мало людей используют игру.
Релизы и переводы
Перевод приложений для Android делается очень просто: все строки хранятся в strings.xml файле, который находится в папке values. По умолчанию язык Английский. Чтобы добавить Русский язык (и другие), нужно создать папку values-ru, и создать копию файла strings.xml, в котором будут находиться переведённые замены строк. Все строки в приложении получаются через API.Для ускорения перевода можно пользоваться электронными переводчиками, например, я использовал Google Translator. До перевода игры я не был уверен в своём знании Английского языка, после перевода неуверенность в знании Английского перешла к Google Translator. При переводе, как минимум, пробуйте перевести полученные предложения на исходный язык. А лучше, дополнительно переведите по словам сами и сравните с тем, как перевёл переводчик. Были случаи, когда компьютерный переводчик слишком сильно искажал смысл и принимал некоторые слова, как другие по значению. Приложение было переведено на английский язык, таким образом была поддержка двух языков. Про влияние переводов на загрузки я расскажу дальше.Первый релиз игры был вечером 9 декабря 2012 года. Уже на следующий день в статистике я увидел, что в первый день было 1 скачивание.Перед релизом я думал, какой номер дать первой версии: 0.99 или 1.0? Так как я решил, что на эмуляторе почти всё работало и я мог на нём играть, то я имею право дать номер 1.0. Я тогда сильно ошибался, т. к. многие пользователи жаловались, что они не могли играть в эту игру.Пользователи жаловались на то, что у них были большие тормоза в игре, другие на неправильное отображение графики. И они были правы, на 90% реальных устройств играть было невозможно.Проблема с тормозами была из-за того, что графика рисовалась посредством перерисовки всего холста Drawable, а на это тратилось очень много ресурсов. Пришлось быстро искать решение, и оно было найдено. Нет, не через OpenGL. Перерисовку можно осуществлять как всего холста (repaint(), onPaint()), так и фрагментами (repaintCliping(), onPaint(rect)). Пришлось учить игру определять нужные области перерисовки, и заранее планировать зоны перерисовки (объединять пересекающиеся зоны, разделять разнесённые зоны перерисовки). Все эти улучшения и советы некоторых людей были собраны в новой версии, которая вышла через неделю.Во время каждого обновления я думал, что каждая предыдущая версия была плохая и в неё невозможно было играть, а новая - лучшая, и в ней нет ни одного недостатка.Тестирование релизов производились сначала только на эмуляторе. Настоящее устройство мне пригодилось только для двух целей: 1) осознать как криво рисуется, что эмулятор не показывал; 2) тестировать мультитач.Пока я так долго разрабатывал и тестировал игру, я привык рисовать ровные фигуры, и не замечал, что не все игроки рисуют такие ровные фигуры фигуры, поэтому часто фигуры не распознавались. По этому, когда я дал поиграть знакомым, я удивился, что программа почти не понимала их рисунки. Пришлось улучшать распознавание ещё раз.Так как список изменений есть на странице об игре, перечислю, какие основные проблемы решали обновления.Версия 1.1: так как поверхность реализована в виде перегруженного View, и перерисовывался весь холст (Canvas), графика тормозила. Реализована поддержка PaintClipping(), что позволяло перерисовывать не весь экран, а только изменяющуюся часть, что значительно ускорило рисование.Следующие обновления: устранил проблемы с анимацией перемещения, отключив её; дизайн; мультитач; рекорды. Первые оптимизации: заметил, что случайно закопипастил 2 раза отрисовку, рисовал по 2 раза одно и то же; оптимизация с помощью кэшей.Ошибки компилятора? Они бывают?
Где-то я читал статью про то, что ошибки компилятора - на самом деле ошибки программиста. Но я столкнулся с реальными ошибками, конечно не самими ошибками компилятора, а ошибками SDK и плагинов:- Эмулятор эмулирует «идеальные» устройства. При тестировании графика в эмуляторе выглядела нормально. На некоторых устройствах тоже выглядела нормально. Но на большинстве реальных устройствах при анимации фигур графика выглядела ужасно: фигуры раздваивались и съезжались (предположительно причина в применении матриц трансформации Matrix, для Java это AffineTransform).
- Ошибка компилятора? Не мало часов потратил на отладку вывода времени игры: время игры выводилось внутри кнопки, как её название, а не в текстовое поле. Решение: оказывается надо было перед компиляцией нажать кнопку «очистить проект» и тогда всё починилось (в официальной документации от Google рекомендовано жать эту кнопку каждый раз перед сборкой apk, но кто её читает?). Возможно это связано с обновлением SDK, но напутать имена ресурсов - это можно отнести к ошибкам компилятора.
- Так же были ошибки API, некоторые устаревшие (deprecated) функции, опять, в эмуляторе вели себя как положено, а на реальном устройстве возвращали непонятные значения.
Графика
Для рисования графики использовались: GIMP - растровый редактор, и Inkscape - векторный редактор.На первый взгляд GIMP мне показался намного хуже фотошопа, некоторых функцй в нём нет (или я не нашёл). Сначала он кажется очень неудобным, и создаётся ощущение, что ты не сможешь на нём даже линию нарисовать. Но со временем привыкаешь, и понимаешь что это как впервые открыть фотошоп, когда до этого видел только Paint. В GIMP можно рисовать.Inkscape тоже проще CorelDraw, но мне от него большего и не нужно было. Достаточно простой, понятный редактор.Удачный дизайн получился не сразу.Ещё картинки
Статистика и маркетинг
Я не надеялся с помощью игры получить деньги, поэтому я ни где не рекламировал её. Так же, решил собрать реальную статистику в условии отсутствия рекламы, поэтому, иногда даже не продвигал её, но некоторые попытки продвижения всё-же были.Продвижение
В первую неделю я попробовал написать про игру на сайте 4PDA. Писал в некоторые ветки форума (прибавка к скачиванию +15 - +40), не прочитав их правила, за что был забанен на пару дней. Затем писал на ветки их форума для разработчиков, откуда получил ценные советы, пару лишних установок (+10), и несколько хороших отзывов в Google Play (+2). У них был проект по поддержке геймдевов из стран СНГ, он заключался в том, что пишешь обзор игры, а они у себя его бесплатно размещают, говорят сейчас они закрыли этот проект. Но меня почему-то не приняли в этот проект, то-ли им не понравился сайт с «.com», то-ли не нашли мой меил на сайте.Отзывы в Google Play
Говорят, что не нужно беспокоится про одиночные отзывы и оценки в Google Play. Это так - люди разные, разные мнения, кто-то ожидает совсем другое, чем вы думаете. Не читают описание игры, тем самым скачивая то, что кому-то не нужно, или пропускают интересную игру.Однако, если несколько человек пишут, что «невозможно играть», а то и более подробно описывают «несуществующие» баги («крестик рисуется выше см на 2»), то это не просто так. Эмулятор может вас обманывать, ваше устройство тоже может действовать не так как другие. В этом случае не стоит пропускать подобные отзывы, а попробуйте выяснить что происходит на устройствах пользователей и разобраться с этим.Хочу отметить, что за год, при более чем 5000 загрузках и 1000 пользователях на e-mail пришло всего 5 писем: 4 из них - спам (предлагали мне прорекламировать мою игру и накликать хороший рейтинг, за это они просили от 100$ до 60000$). И одно письмо от Opera Mobile Store (apps.opera.com), где сообщалось, что можно бесплатно размещать в их магазине приложения, но я решил пока остаться только на Google Play.
Конкуренция и SEO
Конкуренция за первые позиции высока, особенно в таком жанре игр, как «крестики-нолики». Их тысячи, тысячи одинаковых крестиков-ноликов с почти одинаковыми названиями. Их так много, потому что их чуть сложнее написать, чем «Hello world». Понятно, что пользователи не будут утруждаться листать более чем за двадцатую вторую страницу в поисках лучшей игры, а страниц всего более чем (3000/20=100...).Конкуренция среди тысяч крестиков ноликов… Моя игра находится в первой двадцатке страниц (на 20 странице), это не так плохо, как у более чем 70% других конкурентов.Стоит отметить, что как и в поисковиках, позиция игры определяется не только выбранной категории, но и в поиске по разным ключевым запросам. Так, по запросу «крестики-нолики» моя игра на 20 странице, а по запросу «крестики-нолики рисуй» на первой, среди десятка конкурентов, но мало кто так набирает. Однако, по запросу «крестики нолики на двоих», который появляется в подсказке при наборе словосочетания «крестики нолики» конкуренция всего среди двух страниц, и это набирают часто.Результатом добавления ключевого слова «на двоих» в описание игры стало увеличение загрузки русскоязычных пользователей в 3,636 раза (на основе базиса загрузок англоязычной части пользователей).Стоит отметить, что не нужно спамить всеми возможными ключевыми словами, так как если вы в напишите то, что игроки ожидают увидеть, но не увидят в игре, то они не просто удалят игру, ещё они добавят плохой отзыв.Как некоторые, возможно догадались, раз на поиск так влияет конкретные словосочетания, то на разных языках крестики-нолики будут называться по разному. Возникает вопрос: на сколько языков нужно перевести приложение? Основное количество пользователей установило игру со следующими языками: русский (58%), английский (США 20% + Великобритания 11% + другие английские 2% = 33%), испанский (3%), остальные 6%. Поэтому можно сделать вывод, что обязательно должен быть английский язык; язык, которым вы хорошо владеете; далее языки по популярности, которые знают ваши знакомые.На графике зелёным показаны русскоязычные пользователи, остальные две линии - англоязычные. Точка резкого подъёма русскоязычных пользователей - добавление «на двоих» в описание игры.Средняя статистика по использованию языка в разделе «Головоломки» (предоставляется в консоли разработчика Google Play):Как люди попадают на страницу с игрой, кто её скачивает и кто оставляет игру? Это покажет следующая картинка.
Видео
Так как некоторые минусующие писали комментарии примерно такого содержания «можно играть и на бумаге», то я сделал вывод, что многие, кто устанавливают игру не читают её описание. Картинки (скриншоты) плохо объясняют особенность этой игры - рисование. По этому я решил сделать видео. Не для того, чтобы привлечь новых игроков, а чтобы показать геймплей и отсеять тех, кому игра не понравится (чтобы не портили рейтинг игры).Как и предлагалось в документации к google play, я сделал видео, показывающее особенность игры. Старался сделать видео без особых спец эффектов, так как предполагал, что его не много будут смотреть. Но я в 1,5 минут так и не смог урезать 15 минут видео, захваченного с экрана с помощью ffmpeg. А зря.Результат видео был неоднозначный. Приблизительно 2 просмотра в день, 1 просмотр длился 48 секунд (недосматривают). Из этого можно сделать вывод, что с учётом времени, потраченного на перематывании видео лучшая длительность видео 1 минуты. Изменения колличества удалений/установок были незначительны.Статистика загрузок
Общая статистика за год: установок 5113, удалений 4017 (78%), осталось пользователей 1096. За первые 10 дней (первая версия): 56 загрузок, 22 удалений, 34 остались (+3,4 пользователя в день). Такая хорошая статистика из за того, что в первые недели игра обсуждалась на 4PDA.В разные периоды загрузки и удаления колебались равномерно пропорционально. Загрузок и удалений летом менее 10 в день, с января более 20 в день.Хабраэффект будет замерен и выложен. Предположительно будет резкое увеличение загрузок, затем такое же увеличение удалений.UPD: Статья через 2 дня собрала 13000 просмотров, далее расскажу про «хабраэффект».Если коротко: из всех 13000 просмотров заинтересовались игрой и скачали лишь менее 1% человек, зато добавили немало хороших отзывов к игре.Подробнее:Количество загрузок игры за два дня увеличилось на +180 (1,38% от просмотров статьи). В основном были устройства с Android 4.1 и 4.2. Удаления тоже выросли, их было по 50 в дни публикации статьи. В среднем, в эти дни удаляли 43% от всех установок (40% удалений читателей статьи, 70% от других пользователей).Количество пользователей игры за пару дней увеличилось с 1110 до 1230, прирост составил 120 (из них доля людей, читавших статью, оказалась 0,8% от просмотров статьи). Для сравнения, обычный рост за пару дней составляет 3-4 пользователя.Через пару дней после публикации статьи, все показатели стали приближаться к обычным.Как читатели повлияли на загрузки, в графиках
Установки
Удаления
Прирост пользователей
Заметил, что если некоторых пользователей привлекать к продукту личным общением (ветки в форумах, статьи), то количество комментариев и оценок возрастает. За счёт публикации этой статьи появилось много отзывов в Google Play на игру, и отзывы были положительные, не смотря на критику реально существующих недостатков, которые нужно будет исправить.
Средняя оценка приложения выросла с 2,13 до 3,81.
Просмотров видео прибавилось всего на 7 в день, все просмотры с мобильных устройств. Как ни странно, больше просматривали страничку на моём сайте про игру, чем видео.На e-mail пришли первые два письма от тех, кто пробовал установить игру. До этого приходил только спам.
Список программ, используемых для создания игры и других материалов
Среды разработки:- NetBeans
- Eclipse (+Android SKD)
- GIMP - растровый графический редактор
- Inkscape - векторный редактор
- OpenShot - видеоредактор
- ffmpeg - использовал для захвата видео с экрана
Затраты
0 (ноль) за разработку, графику, софт.Более ~$30 за поддержку сайта, банковские операции, и оплату аккаунта разработчика GooglePlay.Что получил: 0 рублей, опыт разработки приложения для Android, статистику по установкам игры на Google Play, хорошую статью.В заключение
Можно, имея компьютер, 30$ и время сделать простую и хорошую игру. Для хорошей игры нужен и геймплей (идея) и красивая реализация (графика) одновременно. Чтобы заработать получить много пользователей, нужно сделать то, что нужно пользователям, пусть они даже не подозревают о существовании этого, и то, чего ещё нет, так же делать в менее конкурентной сфере, чем тысячи крестиков-ноликов. Сейчас игра бесплатна, без рекламы , не требует никаких дополнительных разрешений (например сбор личных данных, отправка платных смс, и т.п.). (кликабельно, на страничку игры на Google Play)Теги: Добавить метки
godAlex 9 декабря 2013 в 23:09
Нетривиальная реализация крестиков-ноликов под Android
- Разработка игр
В этой статье будет рассказано про крестики-нолики на Java под Android за 30 строк кода пять с половиной тысяч строк кода, и зачем потребовалось так много кода на такую простую игру.Ровно год назад, 9 декабря я выложил свою игру на Google Play. Теперь я хочу рассказать про то, что произошло за этот год, как росла популярность игры, что сработало, а что - нет.Вы увидите чистую статистику загрузок и удалений за год существования игры, цифры. Узнаете, сколько пользователей можно собрать с Google Play, как создавалась игра, как тестировалась. Вы узнаете, возможно ли создать инди-игру с нулевым бюджетом, какие трудности могут возникнуть у небольшой игры в большом мире.Кому интересно, добро пожаловать.
Введение
Я давно пробовал делать игрушки, в основном простые. После изучения Java решил попробовать сделать что-то полезное на этом языке. Узнав, что можно на Java под Android игры писать, я решил попробовать сделать что-то простое, чтобы научиться делать приложения под смартфоны.Идея
Теперь нужна идея, слишком простая, чтобы не было жалко времени в случае неудачи, и слишком уникальная, чтобы приложение не осталось просто очередным названием в многомиллионном списке приложений.Я выбрал крестики-нолики. Слишком просто? Таких игр много? Вот теперь нужно было придумать что-то уникальное. Почему сейчас все компьютерные крестики-нолики работают по принципу кликнул – поставил? Вот и решил я, что пусть фигуры рисуют, а игра сама определит, что нарисовано.Теперь, как сделать реализацию? Варианты:- Каждая клетка – растровое изображение. Недостаток: нельзя рисовать за границей, иначе выглядит криво, расход памяти. Достоинства: простота. Аналог такого уже есть в Интернете, но не для мобильного.
- Всё поле – растровое изображение. Недостаток: вот и ищи фигуры по всему изображению, наверное печатный текст проще распознать, чем кривые фигуры найти, проблема разъединения склеенных фигур, большая нагрузки на ЦП. Достоинство: можно рисовать крестик, наезжая на соседнюю клетку.
- Фигуры – векторные. Недостатки: возможно перерисовка долгая (но решить можно с помощью буферизации). Достоинства: можно разделять наехавшие друг на друга фигуры, легко можно изменить положение отдельных фигур.
Реализации
UPD: Особенности игры, которые требовалось реализовать:- Рисование фигур игроком, распознавание нарисованных фигур
- Разный размер игрового поля: от 3x3 до 12x12 (можно и больше, но ограничения накладывают размеры экрана многих устройств)
- Соответственно, игра не только 3 в ряд, но и 4, 5, 6 в ряд
Выбор среды разработки и общего плана создания
Пока я искал на чём писать под Android, скачивался Eclipse, изучалась документация, я решил начать на том что было установлено у меня - на NetBeans. Я подумал, что в андроиде Java такая же, как и простая Java, они должны быть почти одинаковы, значит логику (движок) можно писать отдельно.По моему плану игра должна была разделяться на два пакета: Engine и GUI. Engine - движок игры, игровая логика, этот пакет почти не зависит от реализации GUI и ОС, имеет интерфейс взаимодействия с GUI: приём входящих событий, и вывод. GUI - зависит от ОС. Для портирования на Андроид нужно заменить только GUI, не трогая Engine, или почти не трогая. Такой был мой план.Идея была хорошая, но в момент перевода под Android возникла проблема с адаптацией (описано дальше).Разработка игры
Цикл разработки программы
Чтобы точно знать, что делать, я решил записать по пунктам, что моя игра должна делать, что нужно реализовать. Сначала я взял листок, на котором записал основные разделы: Движок, ИИ, Графика, Баги и т. п., затем по каждой категории расписывал проблемы, которые нужно решить. По мере решения я отмечал галочками, что было сделано, по мере бездельниченья пополнял списки новыми идеями, по мере отладки увеличивал раздел «баги» и иногда другие разделы. Потом у меня закончился второй листок, но двух листов вполне хватило.Так как разработка и поддержка планировались не за пару дней, а на длительный период, для планирования и лучшей поддержки, использовались не только листы с пунктами, также было решено хорошо комментировать код (см Javadoc).Разработка игры была разделена на 2 этапа: сделать версию под PC, перенести на Android.Первая версия (альфа) была сделана под PC. Было реализовано по этапам:- простой GUI, рисование линий мышкой, клетки. Распознавание линий как крестиков и ноликов. (Раскрашивание фигур, в соответствии с распознанной фигурой было сделано для отладки распознавания фигур, затем, так как это получилось красиво, это было оставлено в игре)
- правила победы, игра человек с человеком.
- игровой ИИ, режим игры с компьютером.
- составление перечня основных требований
- программирование
- проверка результата и отладка. При выявлении ошибок, несовместимых с жизнью работой программы, переход на пункт 1)
- составление перечня проблем
- программирование
- проверка результата и отладка. Теперь искалось что можно улучшить.
- Проверка игры: запуск на эмуляторе с разными размерами экрана, игра.
- Составление списка проблем
- Исправление проблем
Как ИИ писался
Разработка Бота (в игре для сокращения применялся термин ИИ) для простых крестиков ноликов выглядит несложной задачей. Но я хотел, чтобы этот ИИ был универсальным: работал на поле любого размера, и не только в игре 3 в ряд, но и n-в ряд. Некоторые реализации ИИ работали хорошо на большом поле, но легко проигрывали на маленьком поле, или наоборот.Так как каждая реализация ИИ требовала проверки не только на какую-то работоспособность, но и на возможность победить в игре, то сначала мне приходилось тестировать ИИ вручную - просто играть с ним. Но, это было слишком медленно, и оценка успеха была субъективна, поэтому я нашёл другой способ тестировать ИИ. ИИ был целиком реализован ввиде класса, поэтому была сделана отдельная программа по тестированию ИИ: запускались два разных класса ИИ, которые играли на виртуальном игровом поле, данные по результатам выводились в консоль (кто победил, за сколько ходов). Так же, если было нужно, выводились данные по каждому ходу в текстовом формате (игровая ситуация, что ИИ думает о выгодности каждой клетки).За эталон хорошо играющего противника был взять open-source ИИ из игры 5 в ряд, которую нашёл на launchpad. Тесты проводились несколько раз, чтобы уменьшить влияние случайности.Так было сделано 2 ИИ: нормальный и сложный. Они сильно отличались по реализации: сложный ИИ работал по принципу трассировок возможных путей, а средний по простому принципу: перебор клеток, куда поставить чтобы победить, или не проиграть, или хотя-бы близко что-то стояло, иначе random. По этому, пока я не оптимизировал алгоритм анализа победы (версия 1.5), сложный ИИ был во много раз быстрее, чем средний и лёгкий, в играх с полем больше чем 3x3. После того, как из среднего ИИ было выкинуто не лишнее, появился лёгкий уровень сложности.Код
Кратко про код игры на Java: всего чисто исходники занимают 275 кБ, из них 75% Engine. Код разбит на три пакета, использовано около 22 классов. Всего 5670 строк кода, но много комментариев, закомментированных частей и пустых строк, поэтому чистого кода около 4000, в среднем по 250 строк на 1 класс (файл). Основной движок писался за пару недель, можно было ускорить и до одной недели.При написании кода, опасные места, где могла бы возникнуть ошибка (например, конструкция получилась слишком запутанная), я помечал комментариями // FIXME и // TODO. Концентрация комментариев: один FIXME на 400 строк кода и около 1 TODO на 60 строк кода. Когда в процессе тестирования выявлялись недостатки я либо сразу понимал что исправить, либо ошибки находились именно в этих строках.Также, перед каждым релизом, я тестировал игру, играя по 5-10 раз с разными настройками.Спойлер про тест
При шаманстве тестировании мультитача вместо багов в игре нашёл баг в Android, повторить возможно, используя все 10 пальцев, совершая сложные движения по экрану. Для восстановления работоспособности устройства после этого требуется перезагрузка.
В результате получилось надёжное приложение, о чём свидетельствует отчёт «Сбои и ANR».
Однако, есть ещё объяснения этому: использовались try - catch блоки, что не очень хорошо, но в некоторых случаях при сбое, приложение автоматом должно отключать «экспериминтальные» функции и переходить на их более старые версии; либо у Google эта страница не работает; или слишком мало людей используют игру.
Релизы и переводы
Перевод приложений для Android делается очень просто: все строки хранятся в strings.xml файле, который находится в папке values. По умолчанию язык Английский. Чтобы добавить Русский язык (и другие), нужно создать папку values-ru, и создать копию файла strings.xml, в котором будут находиться переведённые замены строк. Все строки в приложении получаются через API.Для ускорения перевода можно пользоваться электронными переводчиками, например, я использовал Google Translator. До перевода игры я не был уверен в своём знании Английского языка, после перевода неуверенность в знании Английского перешла к Google Translator. При переводе, как минимум, пробуйте перевести полученные предложения на исходный язык. А лучше, дополнительно переведите по словам сами и сравните с тем, как перевёл переводчик. Были случаи, когда компьютерный переводчик слишком сильно искажал смысл и принимал некоторые слова, как другие по значению. Приложение было переведено на английский язык, таким образом была поддержка двух языков. Про влияние переводов на загрузки я расскажу дальше.Первый релиз игры был вечером 9 декабря 2012 года. Уже на следующий день в статистике я увидел, что в первый день было 1 скачивание.Перед релизом я думал, какой номер дать первой версии: 0.99 или 1.0? Так как я решил, что на эмуляторе почти всё работало и я мог на нём играть, то я имею право дать номер 1.0. Я тогда сильно ошибался, т. к. многие пользователи жаловались, что они не могли играть в эту игру.Пользователи жаловались на то, что у них были большие тормоза в игре, другие на неправильное отображение графики. И они были правы, на 90% реальных устройств играть было невозможно.Проблема с тормозами была из-за того, что графика рисовалась посредством перерисовки всего холста Drawable, а на это тратилось очень много ресурсов. Пришлось быстро искать решение, и оно было найдено. Нет, не через OpenGL. Перерисовку можно осуществлять как всего холста (repaint(), onPaint()), так и фрагментами (repaintCliping(), onPaint(rect)). Пришлось учить игру определять нужные области перерисовки, и заранее планировать зоны перерисовки (объединять пересекающиеся зоны, разделять разнесённые зоны перерисовки). Все эти улучшения и советы некоторых людей были собраны в новой версии, которая вышла через неделю.Во время каждого обновления я думал, что каждая предыдущая версия была плохая и в неё невозможно было играть, а новая - лучшая, и в ней нет ни одного недостатка.Тестирование релизов производились сначала только на эмуляторе. Настоящее устройство мне пригодилось только для двух целей: 1) осознать как криво рисуется, что эмулятор не показывал; 2) тестировать мультитач.Пока я так долго разрабатывал и тестировал игру, я привык рисовать ровные фигуры, и не замечал, что не все игроки рисуют такие ровные фигуры фигуры, поэтому часто фигуры не распознавались. По этому, когда я дал поиграть знакомым, я удивился, что программа почти не понимала их рисунки. Пришлось улучшать распознавание ещё раз.Так как список изменений есть на странице об игре, перечислю, какие основные проблемы решали обновления.Версия 1.1: так как поверхность реализована в виде перегруженного View, и перерисовывался весь холст (Canvas), графика тормозила. Реализована поддержка PaintClipping(), что позволяло перерисовывать не весь экран, а только изменяющуюся часть, что значительно ускорило рисование.Следующие обновления: устранил проблемы с анимацией перемещения, отключив её; дизайн; мультитач; рекорды. Первые оптимизации: заметил, что случайно закопипастил 2 раза отрисовку, рисовал по 2 раза одно и то же; оптимизация с помощью кэшей.Ошибки компилятора? Они бывают?
Где-то я читал статью про то, что ошибки компилятора - на самом деле ошибки программиста. Но я столкнулся с реальными ошибками, конечно не самими ошибками компилятора, а ошибками SDK и плагинов:- Эмулятор эмулирует «идеальные» устройства. При тестировании графика в эмуляторе выглядела нормально. На некоторых устройствах тоже выглядела нормально. Но на большинстве реальных устройствах при анимации фигур графика выглядела ужасно: фигуры раздваивались и съезжались (предположительно причина в применении матриц трансформации Matrix, для Java это AffineTransform).
- Ошибка компилятора? Не мало часов потратил на отладку вывода времени игры: время игры выводилось внутри кнопки, как её название, а не в текстовое поле. Решение: оказывается надо было перед компиляцией нажать кнопку «очистить проект» и тогда всё починилось (в официальной документации от Google рекомендовано жать эту кнопку каждый раз перед сборкой apk, но кто её читает?). Возможно это связано с обновлением SDK, но напутать имена ресурсов - это можно отнести к ошибкам компилятора.
- Так же были ошибки API, некоторые устаревшие (deprecated) функции, опять, в эмуляторе вели себя как положено, а на реальном устройстве возвращали непонятные значения.
Графика
Для рисования графики использовались: GIMP - растровый редактор, и Inkscape - векторный редактор.На первый взгляд GIMP мне показался намного хуже фотошопа, некоторых функцй в нём нет (или я не нашёл). Сначала он кажется очень неудобным, и создаётся ощущение, что ты не сможешь на нём даже линию нарисовать. Но со временем привыкаешь, и понимаешь что это как впервые открыть фотошоп, когда до этого видел только Paint. В GIMP можно рисовать.Inkscape тоже проще CorelDraw, но мне от него большего и не нужно было. Достаточно простой, понятный редактор.Удачный дизайн получился не сразу.Ещё картинки
Статистика и маркетинг
Я не надеялся с помощью игры получить деньги, поэтому я ни где не рекламировал её. Так же, решил собрать реальную статистику в условии отсутствия рекламы, поэтому, иногда даже не продвигал её, но некоторые попытки продвижения всё-же были.Продвижение
В первую неделю я попробовал написать про игру на сайте 4PDA. Писал в некоторые ветки форума (прибавка к скачиванию +15 - +40), не прочитав их правила, за что был забанен на пару дней. Затем писал на ветки их форума для разработчиков, откуда получил ценные советы, пару лишних установок (+10), и несколько хороших отзывов в Google Play (+2). У них был проект по поддержке геймдевов из стран СНГ, он заключался в том, что пишешь обзор игры, а они у себя его бесплатно размещают, говорят сейчас они закрыли этот проект. Но меня почему-то не приняли в этот проект, то-ли им не понравился сайт с «.com», то-ли не нашли мой меил на сайте.Отзывы в Google Play
Говорят, что не нужно беспокоится про одиночные отзывы и оценки в Google Play. Это так - люди разные, разные мнения, кто-то ожидает совсем другое, чем вы думаете. Не читают описание игры, тем самым скачивая то, что кому-то не нужно, или пропускают интересную игру.Однако, если несколько человек пишут, что «невозможно играть», а то и более подробно описывают «несуществующие» баги («крестик рисуется выше см на 2»), то это не просто так. Эмулятор может вас обманывать, ваше устройство тоже может действовать не так как другие. В этом случае не стоит пропускать подобные отзывы, а попробуйте выяснить что происходит на устройствах пользователей и разобраться с этим.Хочу отметить, что за год, при более чем 5000 загрузках и 1000 пользователях на e-mail пришло всего 5 писем: 4 из них - спам (предлагали мне прорекламировать мою игру и накликать хороший рейтинг, за это они просили от 100$ до 60000$). И одно письмо от Opera Mobile Store (apps.opera.com), где сообщалось, что можно бесплатно размещать в их магазине приложения, но я решил пока остаться только на Google Play.
Конкуренция и SEO
Конкуренция за первые позиции высока, особенно в таком жанре игр, как «крестики-нолики». Их тысячи, тысячи одинаковых крестиков-ноликов с почти одинаковыми названиями. Их так много, потому что их чуть сложнее написать, чем «Hello world». Понятно, что пользователи не будут утруждаться листать более чем за двадцатую вторую страницу в поисках лучшей игры, а страниц всего более чем (3000/20=100...).Конкуренция среди тысяч крестиков ноликов… Моя игра находится в первой двадцатке страниц (на 20 странице), это не так плохо, как у более чем 70% других конкурентов.Стоит отметить, что как и в поисковиках, позиция игры определяется не только выбранной категории, но и в поиске по разным ключевым запросам. Так, по запросу «крестики-нолики» моя игра на 20 странице, а по запросу «крестики-нолики рисуй» на первой, среди десятка конкурентов, но мало кто так набирает. Однако, по запросу «крестики нолики на двоих», который появляется в подсказке при наборе словосочетания «крестики нолики» конкуренция всего среди двух страниц, и это набирают часто.Результатом добавления ключевого слова «на двоих» в описание игры стало увеличение загрузки русскоязычных пользователей в 3,636 раза (на основе базиса загрузок англоязычной части пользователей).Стоит отметить, что не нужно спамить всеми возможными ключевыми словами, так как если вы в напишите то, что игроки ожидают увидеть, но не увидят в игре, то они не просто удалят игру, ещё они добавят плохой отзыв.Как некоторые, возможно догадались, раз на поиск так влияет конкретные словосочетания, то на разных языках крестики-нолики будут называться по разному. Возникает вопрос: на сколько языков нужно перевести приложение? Основное количество пользователей установило игру со следующими языками: русский (58%), английский (США 20% + Великобритания 11% + другие английские 2% = 33%), испанский (3%), остальные 6%. Поэтому можно сделать вывод, что обязательно должен быть английский язык; язык, которым вы хорошо владеете; далее языки по популярности, которые знают ваши знакомые.На графике зелёным показаны русскоязычные пользователи, остальные две линии - англоязычные. Точка резкого подъёма русскоязычных пользователей - добавление «на двоих» в описание игры.Средняя статистика по использованию языка в разделе «Головоломки» (предоставляется в консоли разработчика Google Play):Как люди попадают на страницу с игрой, кто её скачивает и кто оставляет игру? Это покажет следующая картинка.
Видео
Так как некоторые минусующие писали комментарии примерно такого содержания «можно играть и на бумаге», то я сделал вывод, что многие, кто устанавливают игру не читают её описание. Картинки (скриншоты) плохо объясняют особенность этой игры - рисование. По этому я решил сделать видео. Не для того, чтобы привлечь новых игроков, а чтобы показать геймплей и отсеять тех, кому игра не понравится (чтобы не портили рейтинг игры).Как и предлагалось в документации к google play, я сделал видео, показывающее особенность игры. Старался сделать видео без особых спец эффектов, так как предполагал, что его не много будут смотреть. Но я в 1,5 минут так и не смог урезать 15 минут видео, захваченного с экрана с помощью ffmpeg. А зря.Результат видео был неоднозначный. Приблизительно 2 просмотра в день, 1 просмотр длился 48 секунд (недосматривают). Из этого можно сделать вывод, что с учётом времени, потраченного на перематывании видео лучшая длительность видео 1 минуты. Изменения колличества удалений/установок были незначительны.Статистика загрузок
Общая статистика за год: установок 5113, удалений 4017 (78%), осталось пользователей 1096. За первые 10 дней (первая версия): 56 загрузок, 22 удалений, 34 остались (+3,4 пользователя в день). Такая хорошая статистика из за того, что в первые недели игра обсуждалась на 4PDA.В разные периоды загрузки и удаления колебались равномерно пропорционально. Загрузок и удалений летом менее 10 в день, с января более 20 в день.Хабраэффект будет замерен и выложен. Предположительно будет резкое увеличение загрузок, затем такое же увеличение удалений.UPD: Статья через 2 дня собрала 13000 просмотров, далее расскажу про «хабраэффект».Если коротко: из всех 13000 просмотров заинтересовались игрой и скачали лишь менее 1% человек, зато добавили немало хороших отзывов к игре.Подробнее:Количество загрузок игры за два дня увеличилось на +180 (1,38% от просмотров статьи). В основном были устройства с Android 4.1 и 4.2. Удаления тоже выросли, их было по 50 в дни публикации статьи. В среднем, в эти дни удаляли 43% от всех установок (40% удалений читателей статьи, 70% от других пользователей).Количество пользователей игры за пару дней увеличилось с 1110 до 1230, прирост составил 120 (из них доля людей, читавших статью, оказалась 0,8% от просмотров статьи). Для сравнения, обычный рост за пару дней составляет 3-4 пользователя.Через пару дней после публикации статьи, все показатели стали приближаться к обычным.Как читатели повлияли на загрузки, в графиках
Установки
Удаления
Прирост пользователей
Заметил, что если некоторых пользователей привлекать к продукту личным общением (ветки в форумах, статьи), то количество комментариев и оценок возрастает. За счёт публикации этой статьи появилось много отзывов в Google Play на игру, и отзывы были положительные, не смотря на критику реально существующих недостатков, которые нужно будет исправить.
Средняя оценка приложения выросла с 2,13 до 3,81.
Просмотров видео прибавилось всего на 7 в день, все просмотры с мобильных устройств. Как ни странно, больше просматривали страничку на моём сайте про игру, чем видео.На e-mail пришли первые два письма от тех, кто пробовал установить игру. До этого приходил только спам.
Список программ, используемых для создания игры и других материалов
Среды разработки:- NetBeans
- Eclipse (+Android SKD)
- GIMP - растровый графический редактор
- Inkscape - векторный редактор
- OpenShot - видеоредактор
- ffmpeg - использовал для захвата видео с экрана
Затраты
0 (ноль) за разработку, графику, софт.Более ~$30 за поддержку сайта, банковские операции, и оплату аккаунта разработчика GooglePlay.Что получил: 0 рублей, опыт разработки приложения для Android, статистику по установкам игры на Google Play, хорошую статью.В заключение
Можно, имея компьютер, 30$ и время сделать простую и хорошую игру. Для хорошей игры нужен и геймплей (идея) и красивая реализация (графика) одновременно. Чтобы заработать получить много пользователей, нужно сделать то, что нужно пользователям, пусть они даже не подозревают о существовании этого, и то, чего ещё нет, так же делать в менее конкурентной сфере, чем тысячи крестиков-ноликов. Сейчас игра бесплатна, без рекламы , не требует никаких дополнительных разрешений (например сбор личных данных, отправка платных смс, и т.п.). (кликабельно, на страничку игры на Google Play)Теги:
- gamedev
- google play
- Java
- инди
- indy games