Здравствуй, Хабр! Ух! Давно же я не писал здесь. Итак, начну пожалуй с небольшой предыстории и заодно приведу скриншот получившейся игры.

TOTAL100
Скриншот игрового процесса

Примечание: статья для новичков, однако, если вы гуру и увидели ошибку в суждениях/коде автора, то просьба писать об этом в ЛС или в комментариях. А я их добавлю в статью.


Предыстория


Весь последний год я работал веб-программистом на языке Python. Не скажу, что мне это не нравилось, однако душа желала творчества/независимости/перемен/успеха (подчеркните своё, инди разработчики игр). И было время писать что-то своё по вечерам, но до чего-то хоть немного значимого это так и не дорастало (ввиду банальной усталости и желания провести время отдельно от компьютера).
Но вдруг, на горизонте замаячила возможность. Я и ещё пара друзей решили сделать свой проект. Идея была расписана, делались презентации, рисовались графики, среда разработки была запущена, но не хватало только одного — инвестора. Денег надо было не очень много (по обычным меркам), но мы так и не смогли найти заинтересованного человека «при деньгах». Что ж, подумал я, раз так, тогда пора бы освободить своё воображение и пустить его в разработку какой-нибудь маленькой, но гордой игры. Об этом и дальнейшая статья.

Идея


Я намеренно старался не брать чью-то идею или просто копировать уже готовое. Изначальная идея была в том, чтобы просто бросать шарики разного цвета на стенки того же цвета и вести счёт. Но сделав первый вариант игры я понял, что она скучная и ни разу не затягивает. Тогда-то мне пришла мысль сделать цифры с разными знаками (плюс, минус), вместо шариков и добавить «ненавистный нуль» (с), обнуляющий все очки игрока.
Потом я понял, что игрока нужно как-то ограничивать и добавил таймер. Затем, добавил уровни (хотя, изначально хотел сделать просто таблицу рекордов). Уровни должны были как-то усложняться, поэтому я добавил препятствия в виде стенок и платформ. Уже ближе к концу разработки я подумал, что нулю нужно дать особые права и сделал его неуязвимым для стенок и платформ, что очень злило моих «домашних тестеров» и крайне забавляло меня.

image
Скриншот главного меню игры

Сроки


Поскольку, у меня в любой момент могло «кончиться» свободное время, я решил поставить себе цель — написать игру за неделю. Цель эту я достиг. Игра, безусловно, ещё сыровата, но всё же уже в маркете и меня это радует.

Реализация


Для реализации своих идей я выбрал свой любимый фреймворк libGDX, который хорошо интегрирован с физическим движком box2D. Вообще, libGDX прекрасен. У него действительно хорошая документация, которая выручала меня в 80% случаев, а в 20% помогал stackoverflow. Также, он сейчас прекрасно интегрируется с Android Studio (раньше не мог), что опять же добавляет ему плюс. Получившиеся приложения получаются весьма и весьма лёгкими (в отличие о того же Unity3D) и довольно стабильными (если руки не кривые, как у меня :) ).

Проблемы


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

  1. Физический мир. Честно, я не знаю, как я мог пропустить этот момент в документации (он описан в коде), но долго не мог понять, почему мои физические тела такие медленные. Проблема была в том, что я указал размеры камеры равные размеру экрана:
    // Я писал так
    box2DCamera = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
    
    // А надо было например так. 14 -- это число, которое меня устроило. scrWidth и scrHeight -- это размеры экрана. Такая формула позволяет запускать данный код на любом экране и всё растянется пропорционально
    box2dCamera = new OrthographicCamera(14 * (scrWidth / scrHeight), 14);
    

  2. Спрайты/Изображения. Если работаешь с физическим движком, то размеры изображений и их позиции нужно задавать исходя из нескольких параметров:
    sprite = new Sprite("your_sprite");
    sprite.setBounds(body.getPosition().x / 2f, body.getPosition().y / 2f, radius, radius); // в моём примере я тело было круглым, поэтому здесь два раза повторяется radius.
    sprite.setOrigin(sprite.getWidth() / 2f, sprite.getHeight() / 2f);
    

  3. Вращение объектов и спрайтов. Если вы хотите вращать физическое тело, то просто передав значение угла спрайту вы ничего хорошего не получите. Необходимо перевести значение из радианов в градусы:
    sprite.setRotation(MathUtils.radiansToDegrees * body.getAngle());
    

  4. Ещё были моменты с dispose() у объектов текстур и прочей графики. Дело в том, что (и это описано в документации, но я её плохо читал) если вы пользуетесь AssetManager, то ни в коем случае не делайте dispose() отдельной текстуры, полученной из менеджера, так как он её удалит и впоследствии вы увидите чёрное пятно вместо объекта графики.
  5. Ещё было много матов с удалением объекта из физического мира. Решение гуглится, но я всё таки приведу пример здесь:
    Iterator<GameObject> i = gameObjects.iterator();
    while (i.hasNext()) {
        GameObject object = i.next();
        if (!world.isLocked()) { // ВАЖНО! Если не сделать эту проверку, то получите ошибку. Так мы проверяем, можно ли удалить объект или он как-то используется в мире (коллизии и т.п.)
            object.getBody().setActive(false);
            if (mouseJoint == null) { // Это проверка на касание объекта. mouseJoint -- это захваченное тело при событии TouchDown
                world.destroyBody(object.getBody());
                i.remove();
            }
        }
    }
    


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

Немного советов


  1. Обфускация и минификация. До этого, я никогда не обфусцировал код, а тут решил попробовать. И знаете, понравилось! До обфускации игра весила 4,8 мб, а после её вес уменьшился до 3,7 мб. Делайте выводы сами. Тем более, делается это просто, ведь сейчас ProGuard поставляется по умолчанию с Android SDK и включается парой строк кода:

    Файл android/build.gradle
    android {
        ...
    
        buildTypes {
            release {
                minifyEnabled true
                proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-project.txt'
            }
        }
    }
    

    Файл android/project.properties
    // Раскомментируйте эту строчку
    proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
    

  2. Не используйте фильтр Nearest (это я про текстуры). По умолчанию, TexturePacker применяет фильтр Nearest, Nearest. Лучше заменить его на Linear, Linear или MipMap, MipMap. Так всё будет плавнее, даже если с размерами картинок не угадаете.
  3. Ещё про текстуры. Не нужно делать их максимально большими, а потом уменьшать с помощью setSize() или setScale(). На выходе может получится смазанное изображение.


Графика и звук


Основной шрифт я взял в Google Fonts, остальные элементы либо рисовал сам в Inkscape, либо брал бесплатные иконки и немного их правил.
Что же касается звуков, то что-то я взял с freesound, что-то сделал сам в LMMS. Получилось вполне сносно. Кстати, в следующем обновлении хочу добавить фоновую музыку, которую как раз намерился делать в LMMS. Программа понравилась. Сильно напомнила Fruity Loops Studio.

TOTAL100
Скриншот экрана уровней

Монетизация


Я пока решил выложить одну бесплатную версию с «межстраничными» объявлениями Admob. Потом, если игра понравится публике, введу возможность для отключения рекламы, а также дополнительные уровни за «коины».

Продвижение


Это самое скучное и не интересное занятие из всех, поэтому я решил, что опубликую на 5-10 ресурсах и хватит. Может, если продукт интересный, он сам найдёт свою аудиторию? (мечты...). Хотел бы почитать в комментариях, как лучше (и желательно недорого) продвигать свой продукт. А то большинство статей на эту тему либо заказные, либо попросту устарели.

Итог


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

Через неделю-две обновлю статью и приложу графики скачиваний/прибыли от рекламы. Спасибо за прочтение!

Комментарии (11)


  1. PapaBubaDiop
    31.08.2015 23:56
    +1

    Хороший шрифт, дружит ли он с русским языком?


    1. newca9h
      01.09.2015 01:39
      +2

      Забыл написать название шрифта ( Luckiest Guy ). На счёт русского языка — увы, но нет, не дружит.


  1. sim-dev
    01.09.2015 08:23

    Оставил в PlayMarket отзыв с замечаниями, более подробно напишу здесь.
    Я столкнулся с тем, что «поймать» летящую цифру пальцем очень сложно. Возможно, на планшете это легко (наверняка там все крупнее), но на смартфоне зацепить пальцем быстролетящую цифру удается с 4-й или 5-й попытки, чаще все мимо.
    Ну и, пожалуй, уровни должны отличаться не только всякими преградами, но и скоростью полета цифр. Поначалу для привыкания пусть летят не очень быстро…


    1. newca9h
      01.09.2015 08:51

      Спасибо за отзыв! На счёт «поймать» цифру — у моих знакомых сначала это тоже получалось не с первой попытки, но потом они приловчились :) Вообще, мне кажется, что это какая-то особенность box2D, так как пример захвата физического объекта я брал из документации. Может кто-нибудь подскажет, как это лучше сделать? Сейчас это реализовано через queryAABB(). На счёт уровней. Это всё реализуется в будущих обновлениях, главное, что вас игра хоть немного, но «зацепила». Ещё раз благодарю за отзыв и критику!


      1. Coverbacker
        03.09.2015 13:36
        +1

        Знакомые могут быть бета-тестерами только на очень ранних этапах. Вводи системы сбора данных об игре, читай отзывы и старайся понять реальных игроков. Тем более, в твоем случае у знакомых ТОЖЕ не получалось в начале поймать цифру, но они продолжали потому, что ты их попросил. Игрок продолжать не будет, он уйдет, потому что твоя игра не последняя в мире — есть огромный выбор проектов. На одном только LibGDX игр более 2 000, насколькоя знаю.


        1. newca9h
          03.09.2015 14:05

          Согласен. Буду улучшать геймплей)


  1. Rumlin
    01.09.2015 14:01

    На 4pda или Yandex.Store или просто выложить apk не можете? Нет возможности ставить с маркета.


    1. newca9h
      01.09.2015 19:17
      +1

      На 4pda выложил. Правда там старый apk файл. Внезапно кончилось время( Через пару дней постараюсь обновить ветку.


  1. Mishok2000
    01.09.2015 18:10

    Пожалуйста, повторите ссылку на игру в конце страницы, а то многие статью просто пролистывают в поиске самой игры.


    1. newca9h
      01.09.2015 19:24

      Готово. Надеюсь, Хабр не разгневается на меня за это) Спасибо за совет!


  1. Afganec
    07.09.2015 21:55
    +1

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