Оправдание
Размышлял, стоит ли писать на сам Хабр! о такой Android-поделке. В итоге решил, что кому интересно — прочтут, а кому нет — пролистают мимо. И плохо в итоге никому не будет. Я специально почти весь пост спрятал под кат, чтобы тем, кому это не интересно, еще больше казалось, что этого поста здесь нет.
Игру я делал еще пару недель назад (написал за 1 выходной день), но сейчас появилось свободное время довести ее до ума и выложить в Play Market.
Все повествование разделено на описание игры, описание реализации и описание нюансов, непосредственно к игре не относящихся.
1. Суть игры
Это логическая головоломка, с помощью поворотов окружностей и смещения фишек в пустую ячейку необходимо выставить фишки одного цвета в один ряд. Есть возможность выбирать разное количество цветов и разное количество окружностей, чем больше — тем сложнее. С увеличением сложности решаемой головоломки увеличивается множитель очков. Итоговые очки зависят от сложности головоломки и количества сделанных ходов.
2. Некоторые технические моменты
2.1 Графика
Игра реализована на чистом Canvas'e, без использования движков и даже без использования bitmap'ов.
Архитектурно это CustomView, который содержит в себе список всех фишек. Так же он содержит список окружностей, каждая из которых ссылается на те фишки, которые рисуются на ней. CustomView ловит все события нажатия и передает их вниз по иерархии (окружностям и фишкам).
Вся отрисовка довольно банальная, кроме разве что поворотов окружностей — здесь пришлось через arctg выяснять необходимый угол поворота.
И все таки она вертится!
2.2 Сохранение
Сохранение игры так же максимально быстро было реализовано с помощью настроек (тех, которые Prefferences). Понятно, что можно было использовать БД или файловый кеш, но так как сделано — действительно быстрее. Решение без гугла пишется за минут 5 по памяти. Вот кстати оно:
public class PrefsManager {
private static final String PREFS_TAG = "prefs_tag";
public static void save(Context c, String tag, String val) {
SharedPreferences p = c.getSharedPreferences(PREFS_TAG, Context.MODE_PRIVATE);
Editor e = p.edit();
e.putString(tag, val);
e.apply();
}
public static String get(Context c, String tag, String defVal) {
SharedPreferences p = c.getSharedPreferences(PREFS_TAG, Context.MODE_PRIVATE);
return p.getString(tag, defVal);
}
public static void delete(Context c, String tag) {
SharedPreferences p = c.getSharedPreferences(PREFS_TAG, Context.MODE_PRIVATE);
Editor e = p.edit();
e.remove(tag);
e.apply();
}
}
2.3 Диалог рейтинг поднимающий
Небольшая хитрость, правда давно уже используемая. При энном запуске приложения появляется диалог, отображающий RatingBar (он представляет собой 5 звезд) и просьба пользователя оценить приложение. И дальше есть 2 варианта:
- Пользователь выбрал 5 — отображаем диалог с просьбой повторить это в Play Market'e.
- Пользователь выбрал 4 или меньше — просим пользователя написать на email саппорта в чем, собственно, дело.
Количество запусков приложения хранится все в тех же Preferens'ах, для отправки пользователя в Market || Email используются просто intent'ы.
3. Интересности
Т.к. сама реализация приложения довольно простая, я решил воспользоваться двумя новыми технологиями:
- Playhaven;
- Scoreloop.
Т.к. игра не потребила должного количества человеко-часов, то и встраивать в нее рекламу было бы неправильно. Тоже самое, ествественно, относится и к платной версии в еще большей степени. Именно поэтому я решил смотреть в сторону альтернативных видов монетизации и нашел Playhaven. Они кроме стандартной рекламы предлагают установить виджет More games. Пользователь, видя эту кнопку, с большой вероятностью не воспримет ее за рекламу, а, следовательно, и настроение у всех останется замечательным.
Интеграция данной рекламной партнерки вообще очень замечательная в плане количества кода, но я не сразу пример этого кода нашел, если честно.
/*
* Вызывается заранее, в onCreate или в onResume, чтобы при нажатии на кнопку не было задержки.
*/
private void prepareMoreGamesRequest() {
moreGamesRequest = new PHPublisherContentRequest(this, MORE_GAMES_PLACEMENT);
moreGamesRequest.preload();
}
/*
* Вешаем событие, которое отображает список и сразу же готовит новый, если пользователь захочет нажать на кнопку второй раз.
*/
findViewById(R.id.moreGames).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
moreGamesRequest.send();
prepareMoreGamesRequest();
}
});
В общем и целом всем эта площадка радует, разве что в плане дохода оценить пока что никак — приложение с самого начала оказалось в таком низу, что установили его только я да я, да вся моя семья.
Scoreloop порадовал меня не так сильно. С одной стороны — они предоставляют бесплатный сервер с БД. С другой — я хотел бы интегрировать что-то более готовое, комплексное. Поясню. Раньше я часто наблюдал приложения со Scoreloop, которые выглядели следующим образом:
Т.е. это довольно стандартизированный вид. И в интернете еще остались примеры реализации Leaderboards Activity. Всего лишь один вызов intent'a и в Вашем приложении есть комплексная доска рекордов. Но в новом SDK этой Activity нет. Как итог, приходится городить свой собственный ListView, писать запросы, показывать ProgressBar'ы и т. д. и т. п. Совершенно не понимаю, зачем было это делать. Но наверное немцам виднее.
Что еще не понравилось в Scoreloop — чтобы отобразить нормальный список пользователей с набранными очками и позицией в рейтинге — необходимо сделать 2 запроса. В одном получить список пользователей, а в другом получить Rank (позицию в рейтинге) для какого-то одного из пользователей. После того, как я таким образом реализовал Leaderboard:
Мне стало вдвойне не понятно, зачем было убирать из SDK готовую Activity. Но… немцам виднее.
P. S.
Если вдруг кому-то интересны еще какие-то детали реализации — спрашивайте. Не просто же так я все это тут затеял.
Автор: JaLoveAst1k