
Введение
Многие разработчики игр хотят использовать сервис Google Play Game Services в своих играх. Я не был исключением, но знаний и навыков как быстро добавить поддержку GPGS в свою libgdx игру не было. В данной статье опишу процесс подключения таблицы рекордов и достижений. Исходные данные: Eclipse, настроенная консоль разработчика для работы с игровыми сервисами, android-проект, корневой проект.
Настройка
Не буду рассказывать, как настроить консоль разработчика для работы с GPGS, скажу лишь, что оттуда нам понадобятся ресурсы вида:
games-ids.xml
, где app_id – идентификатор вашего приложения, строки вида leaderboard_xxx и achievement_xxx указывают на конкретную таблицу рекордов и достижение соответственно. Следует создать ресурсный xml-файл с именем games-ids.xml в android-проекте своей игры и поместить туда ресурсы выше.<?xml version="1.0" encoding="utf-8"?> <!-- Google Play game services IDs. Save this file as res/values/games-ids.xml in your project. --> <resources> <string name="app_id">310266082735</string> <string name="achievement_take_10_levels">HgkIr62KmoQJEAIQBg</string> <string name="achievement_take_30_levels">HgkIr62KmoQJEAIQBw</string> <string name="achievement_take_50_levels">HgkIr62KmoQJEAIQCA</string> <string name="achievement_take_70_levels">HgkIr62KmoQJEAIQCg</string> <string name="achievement_take_100_levels">HgkIr62KmoQJEAIQCQ</string> <string name="achievement_beginner_cutter">HgkIr62KmoQJEAIQDw</string> <string name="achievement_advanced_cutter">HgkIr62KmoQJEAIQEA</string> <string name="achievement_master_cutter">HgkIr62KmoQJEAIQEQ</string> <string name="achievement_lucky">HgkIr62KmoQJEAIQEg</string> <string name="achievement_cheerful">HgkIr62KmoQJEAIQEw</string> <string name="achievement_exceptional_joyous">HgkIr62KmoQJEAIQFA</string> <string name="achievement_thrust">HgkIr62KmoQJEAIQFQ</string> <string name="achievement_very_persistent">HgkIr62KmoQJEAIQFg</string> <string name="achievement_the_most_resistant">HgkIr62KmoQJEAIQFw</string> <string name="achievement_1_000_000">HgkIr62KmoQJEAIQGA</string> <string name="achievement_2_000_000">HgkIr62KmoQJEAIQGQ</string> <string name="achievement_3_000_000">HgkIr62KmoQJEAIQGg</string> <string name="achievement_unlucky">HgkIr62KmoQJEAIQGw</string> <string name="achievement_loyal">HgkIr62KmoQJEAIQHA</string> <string name="achievement_fan">HgkIr62KmoQJEAIQHQ</string> <string name="achievement_leader_of_mars">HgkIr62KmoQJEAIQHg</string> <string name="achievement_leader_of_neptune">HgkIr62KmoQJEAIQHw</string> <string name="achievement_unhurried">HgkIr62KmoQJEAIQIA</string> <string name="achievement_final_push">HgkIr62KmoQJEAIQIQ</string> <string name="leaderboard_leaderboard">HgkIr62KmoQJEAIQAQ</string> <string name="leaderboard_pack_1">HgkIr62KmoQJEAIQCw</string> <string name="leaderboard_pack_2">HgkIr62KmoQJEAIQDA</string> </resources>
Для работы GPGS нужен проект-библиотека google-play-services_lib. Его путь:
<android-sdk>\extras\google\google_play_services\libproject\google-play-services_libПо умолчанию игровые сервисы не устанавливаются вместе с Android SDK, поэтому по этому пути ничего не будет. Чтобы это исправить нужно в Android SDK Manager установить два пакета: Google Repository и Google Play services.
Проект-библиотеку google-play-services_lib нужно импортировать в Eclipse. После чего установить в свойствах импортированного проекта галочку «Is library».
Теперь нужно связать между собой ваш android-проект и библиотеку google-play-services_lib. Для этого добавляем библиотеку в раздел Required projects on the build path. (Properties -> Java Build Path -> Projects).
На данном этапе можно было бы закончить настройку, но официальная документация Google настоятельно рекомендует использовать класс-помощник GameHelper. Этот класс сильно облегчает жизнь при работе с игровыми сервисами. Его установка аналогична установке google-play-services_lib (импортировать проект как библиотеку, связать проект-библиотеку с android-проектом). Скачать BaseGameUtils.
В AndroidManifest.xml добавляем два разрешения и мета-данные:
<uses-permission android:name="android.permission.INTERNET" /> <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
Мета-данные добавляются внутри тега application:
<meta-data android:name="com.google.android.gms.games.APP_ID" android:value="@string/app_id" /> <meta-data android:name="com.google.android.gms.version" android:value="@integer/google_play_services_version" />
Настройка закончена.
Код
В главной Activity реализуем два интерфейса GameHelperListener, ActionResolver:
public class MainActivity extends AndroidApplication implements GameHelperListener, ActionResolver
Интерфейс GameHelperListener выглядит следующим образом:
public interface GameHelperListener { /** * Вызывается при неудачной попытке входа. В этом методе можно показать * пользователю кнопку «Sign-in» для ручного входа */ void onSignInFailed(); /** Вызывается при удачной попытке входа */ void onSignInSucceeded(); }
Интерфейс ActionResolver создаем сами. Он нужен для вызова платформо-зависимого кода. Эта техника описана в официальной wiki libgdx. Пример интерфейса:
public interface ActionResolver { /** Узнать статус входа пользователя */ public boolean getSignedInGPGS(); /** Вход */ public void loginGPGS(); /** Отправить результат в таблицу рекордов */ public void submitScoreGPGS(int score); /** * Разблокировать достижение * * @param achievementId * ID достижения. Берется из файла games-ids.xml */ public void unlockAchievementGPGS(String achievementId); /** Показать Activity с таблицей рекордов */ public void getLeaderboardGPGS(); /** Показать Activity с достижениями */ public void getAchievementsGPGS(); }
Пример кода главной Activity:
public class MainActivity extends AndroidApplication implements GameHelperListener, ActionResolver { // помощник для работы с игровыми сервисами private GameHelper gameHelper; // класс нашей игры private TestGame game; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); // CLIENT_ALL указывет на использование API всех клиентов gameHelper = new GameHelper(this, GameHelper.CLIENT_ALL); // выключить автоматический вход при запуске игры gameHelper.setConnectOnStart(false); gameHelper.enableDebugLog(true); // запретить отключение экрана без использования дополнительных // разрешений (меньше разрешений – больше доверие к приложению) getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); // Входной параметр this является ActionResolver. Позволяет вызывать из // игрового цикла платформо-зависимые методы GPGS game = new TestGame(this); AndroidApplicationConfiguration config = new AndroidApplicationConfiguration(); initialize(game, config); gameHelper.setup(this); } // методы gameHelper’а: onStart(), onStop() вызываются для корректной работы // GPGS в жизненном цикле android-приложения @Override protected void onStart() { super.onStart(); gameHelper.onStart(this); } @Override protected void onStop() { super.onStop(); gameHelper.onStop(); } @Override protected void onDestroy() { super.onDestroy(); } @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); // здесь gameHelper принимает решение о подключении, переподключении или // отключении от игровых сервисов, в зависимости от кода результата // Activity gameHelper.onActivityResult(requestCode, resultCode, data); } @Override public boolean getSignedInGPGS() { // статус подключения return gameHelper.isSignedIn(); } @Override public void loginGPGS() { try { runOnUiThread(new Runnable() { @Override public void run() { // инициировать вход пользователя. Может быть вызван диалог // входа. Выполняется в UI-потоке gameHelper.beginUserInitiatedSignIn(); } }); } catch (Exception e) { e.printStackTrace(); } } @Override public void submitScoreGPGS(int score) { // отправить игровые очки в конкретную таблицу рекордов с ID // “HgkIr62KmoQJEAIQAQ” Games.Leaderboards.submitScore(gameHelper.getApiClient(), "HgkIr62KmoQJEAIQAQ", score); } @Override public void unlockAchievementGPGS(String achievementId) { // открыть достижение с ID achievementId Games.Achievements.unlock(gameHelper.getApiClient(), achievementId); } @Override public void getLeaderboardGPGS() { // вызвать Activity для всех зарегистрированных таблиц рекордов. Так же // можно вызывать Activity под конкретную таблицу startActivityForResult( Games.Leaderboards.getAllLeaderboardsIntent(gameHelper .getApiClient()), 100); } @Override public void getAchievementsGPGS() { // вызвать Activity с достижениями startActivityForResult( Games.Achievements.getAchievementsIntent(gameHelper .getApiClient()), 101); } @Override public void onSignInSucceeded() { } @Override public void onSignInFailed() { } }
Допустим, у нас в игре предусмотрено достижение – набрать 1 млн. игровых очков, то код реализующий это будет выглядеть так:
public static void checkTotalPoints(int points) { ActionResolver res = getActionResolver(); if (!res.getSignedInGPGS()) { return; } if (points >= 1000000) { res.unlockAchievementGPGS("HgkIr62KmoQJEAIQGA"); } }
То же самое и с таблицей рекордов, только еще легче: нужно просто вызвать метод submitScoreGPGS(int score) интерфейса ActionResolver.
P. S. Для тестирования игровых сервисов нужно экспортировать apk-файл с тем же сертификатом, что и в консоли разработчика. Так же нужно добавить аккаунты тестировщиков в консоли. Изменения в игровых сервисах вступают в силу через некоторое время.
Использованные источники
developers.google.com/games/services/android/quickstart
developer.android.com/intl/ru/google/play-services/setup.html
github.com/libgdx/libgdx/wiki