With Google Play Games Services, you can build a range of features into your Android apps, including leaderboards, achievements, multiplayer gameplay, cloud storage, and Google+ sign-in.
In this tutorial we will work through the steps you need to take to add achievements to a simple Android game. We will prepare the development environment to use Google Play Game Services, define an achievement in the Developer Console and implement the achievement interaction in the game.
1. Prepare Your IDE
Step 1
To utilize the Google Play Game Services tools, we need to prepare our IDE. As well as using the Google Play Services library—which you need for all Google services—we will use the BaseGameUtils resource, which contains a number of classes that are particularly useful when developing games.
Start by creating a new app in your IDE. The sample code of this tutorial contains a simple game in which the user has to guess a number chosen at random. You can use that project to start developing with Google Play Game Services if you like. Create a new Android project and choose names and settings for it.
If you're not using the sample app in the download, you may wish to implement your gameplay at this point, bearing in mind what you are going to use an achievement for. For the sample app, we will simply award an achievement when the user chooses a correct answer.
Step 2
In this step, we get the IDE and our project ready to use Google Play Games Services and the utilities. Open your Android SDK Manager, which you can find under the Window menu in Eclipse. Scroll down until you see the Extras folder, expand it, and select Google Play Services and the Google Repository. You may also need the Google APIs Platform if you plan on testing on the emulator, so select that as well. You can find the latter in the directories for recent versions of the Android platform. Install the selected packages, accepting any licenses as necessary.
Step 3
We also need to include a couple of resources in the actual workspace so that we can reference them in the app, starting with the Google Play Services Library. You should find it at /extras/google/google_play_services/libproject/google-play-services_lib/ in your SDK folder. Make a copy of the library and paste it in another location on your computer.
Back in Eclipse, import the library by choosing Import > Android > Import Existing Android Code into Workspace from the File menu. Browse to the location you copied the library into, select the library, and import it. The library should appear as a project in your Eclipse Package Explorer and workspace.
Right-click the library project in Eclipse, select Properties and browse to the Android section. Select a Google APIs build target and ensure Is Library is checked. The library should now be ready to reference in your app.
Step 4
Let's now get the BaseGameUtils resource into your IDE as well. Download it from the Sample Games section of Google's developer portal. Since the code is hosted on GitHub, you can browse it and access its guides on GitHub.
Import the BaseGameUtils resource into Eclipse using the same technique you used for the Play Services Library by selecting Import > Android > Import Existing Android Code into Workspace from the File menu. Right-click the BaseGameUtils project in your Package Explorer and make sure Is Library is checked.
We can now reference both the Google Play Services Library and BaseGameUtils resources in our app.
Step 5
Select your game app in the Eclipse Package Explorer, right-click it, and choose Properties as you did for the imported resources. In the Android section, this time click Add in the Library area. Select both Google Play Services library and BaseGameUtils to add as libraries to your project.
That's the IDE set up for developing with Games Services.
2. Prepare Your Game in the Developer Console
Step 1
In order to use achievements in your game, your need to add the game to the Google Play Developer Console. Log into the Developer Console, click the Games Services button to the left of the console, and choose Set up Google Play game services if you haven't used them before.
Click to add a new game, select I don't use any Google APIs in my game yet, and choose a name and category for your game. Click Continue to go to the next step.
In the Game Details section, all you need to add to test your app is your game's title.
Step 2
Click Linked Apps to the left of your game listing in the Developer Console. Select Android from the Linked Apps list.
Enter your app details, including the package name you chose when you created it.
Click Save and continue at the top and choose Authorize your app now. You will be prompted to enter branding information. All you need for the moment is your app's name. In the Client ID Settings screen, select Installed application as the type, Android as the installed application type, and enter your package name.
You then need to generate a signing certificate fingerprint for authorization. You will need to run the keytool utility on your computer to do this. Open a terminal or command prompt and use the following command, but make sure to alter it to suit the location if necessary. You can use the debug certificate while testing.
keytool -exportcert -alias androiddebugkey -keystore ~/.android/debug.keystore -list -v
The keytool should write out the certificate fingerprint. Select and copy what appears after SHA1 and paste it into the Developer Console under Signing Certificate Fingerprint. Click Create Client and copy the application ID you see in the listing for your game in the Developer Console, which should be displayed next to the game name at the top of the page. Save the application ID for use later in your app.
3. Create an Achievement
Step 1
Still in the Developer Console, click the Achievements button on the left of the game listing and click Add achievement.
Before you continue, you may want to check out the Achievements page on the Developer Guide to ensure you understand the concept of an achievement in Google Play Games. Enter a name, a description, and an icon for your achievement and choose a state, points, and list order. For our sample game, we use Guessed Correctly as the name, Picked a correct number as the description, and a simple star image as the icon. Click Save to save the achievement.
Copy the achievement ID, which you can see next to the achievement in the Developer Console.
Step 2
If you navigate to the Testing section for your game, you can set email addresses for people who will have test access to the game. By default, the Developer Console will insert your own Google account email, so you should be able to use that straight away. Add any other test emails you need, then you can log out of your Google account.
4. Prepare Your Game for Accessing Games Services
Step 1
In Eclipse, we can get the app ready to access Games Services. We are going to use the technique outlined in Implementing Sign-in on Android to handle getting users signed in and out of their Google accounts. This will involve using buttons to sign in and out, so add these to your app's layout as follows:
<!-- sign-in button --> <com.google.android.gms.common.SignInButton android:id="@+id/sign_in_button" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <!-- sign-out button --> <Button android:id="@+id/sign_out_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Sign Out" android:visibility="gone" />
Step 2
Alter your main Activity to extend BaseGameActivity
. This will let us automate certain parts of the sign-in process for your users. Also make the Activity
class handle clicks:
public class MainActivity extends BaseGameActivity implements View.OnClickListener
You will need the following imports:
import com.google.android.gms.games.Games; import com.google.example.games.basegameutils.BaseGameActivity;
Now retrieve references to the buttons in onCreate
:
findViewById(R.id.sign_in_button).setOnClickListener(this); findViewById(R.id.sign_out_button).setOnClickListener(this);
We will respond to button taps in onClick
as you can see below:
@Override public void onClick(View view) { if (view.getId() == R.id.sign_in_button) { beginUserInitiatedSignIn(); } else if (view.getId() == R.id.sign_out_button) { signOut(); findViewById(R.id.sign_in_button).setVisibility(View.VISIBLE); findViewById(R.id.sign_out_button).setVisibility(View.GONE); } }
We use methods from the BaseGameActivity
class we are extending to handle sign-in (beginUserInitiatedSignIn
and signOut
), updating the user interface accordingly. When the app starts, it will attempt to automatically log in the user, but they will also be able to use the buttons to sign in and out.
We now need to add two callbacks to our Activity
class:
public void onSignInSucceeded() { findViewById(R.id.sign_in_button).setVisibility(View.GONE); findViewById(R.id.sign_out_button).setVisibility(View.VISIBLE); } @Override public void onSignInFailed() { findViewById(R.id.sign_in_button).setVisibility(View.VISIBLE); findViewById(R.id.sign_out_button).setVisibility(View.GONE); }
You could add more code to these if necessary. You may also choose to save player progress even if they are not signed in, but this depends on your game. In the sample application, we take the simple approach of checking that we have a connection to Google Services before we attempt to work with the achievement.
Step 3
Before you start coding the detail of using achievements in your app, you need to add some data to it. Start by opening or creating your res/values/ids.xml file and add string resources for the app and achievement IDs you copied from the Developer Console:
<string name="app_id">abcdefghij</string> <string name="correct_guess_achievement">abcdefghijkl</string>
Update the content to reflect your ID values. Now open the project's Manifest and add the following inside the application element:
<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" />
We reference the app ID we added to the ids file and the Play Services version. This is all you need to get started coding with your achievement.
5. Implement Your Achievement
Step 1
All that remains now is for you to unlock the achievement when the game player meets the achievement's requirements. Naturally this will depend on the purpose of your own game, but if you want to carry out the process using the sample app of this tutorial, then you can use the following code. We start with the main layout, which includes the sign-in and sign-out buttons we added earlier:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" tools:context="com.example.fungame.MainActivity" > <LinearLayout android:id="@+id/sign_in_buttons" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:orientation="horizontal" > <!-- sign-in button --> <com.google.android.gms.common.SignInButton android:id="@+id/sign_in_button" android:layout_width="wrap_content" android:layout_height="wrap_content" /> <!-- sign-out button --> <Button android:id="@+id/sign_out_button" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Sign Out" android:visibility="gone" /> <!-- show achievements --> <Button android:id="@+id/show_achievements" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Achievements" /> </LinearLayout> <RelativeLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_below="@id/sign_in_buttons" > <TextView android:id="@+id/guess_text" android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:text="Guess the number!" android:textSize="30sp" android:textStyle="bold" /> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_below="@id/guess_text" android:orientation="vertical" > <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:orientation="horizontal" > <Button android:id="@+id/btn7" android:layout_width="0dp" android:layout_height="match_parent" android:layout_margin="1dp" android:layout_weight="1" android:background="#ff000033" android:gravity="center" android:onClick="btnPressed" android:padding="5dp" android:tag="7" android:text="7" android:textColor="#ffffffff" android:textSize="30sp" android:textStyle="bold" /> <Button android:id="@+id/btn8" android:layout_width="0dp" android:layout_height="match_parent" android:layout_margin="1dp" android:layout_weight="1" android:background="#ff000033" android:gravity="center" android:onClick="btnPressed" android:padding="5dp" android:tag="8" android:text="8" android:textColor="#ffffffff" android:textSize="30sp" android:textStyle="bold" /> <Button android:id="@+id/btn9" android:layout_width="0dp" android:layout_height="match_parent" android:layout_margin="1dp" android:layout_weight="1" android:background="#ff000033" android:gravity="center" android:onClick="btnPressed" android:padding="5dp" android:tag="9" android:text="9" android:textColor="#ffffffff" android:textSize="30sp" android:textStyle="bold" /> </LinearLayout> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1" android:orientation="horizontal" > <Button android:id="@+id/btn4" android:layout_width="0dp" android:layout_height="match_parent" android:layout_margin="1dp" android:layout_weight="1" android:background="#ff000033" android:gravity="center" android:onClick="btnPressed" android:padding="5dp" android:tag="4" android:text="4" android:textColor="#ffffffff" android:textSize="30sp" android:textStyle="bold" /> <Button android:id="@+id/btn5" android:layout_width="0dp" android:layout_height="match_parent" android:layout_margin="1dp" android:layout_weight="1" android:background="#ff000033" android:gravity="center" android:onClick="btnPressed" android:padding="5dp" android:tag="5" android:text="5" android:textColor="#ffffffff" android:textSize="30sp" android:textStyle="bold" /> <Button android:id="@+id/btn6" android:layout_width="0dp" android:layout_height="match_parent" android:layout_margin="1dp" android:layout_weight="1" android:background="#ff000033" android:gravity="center" android:onClick="btnPressed" android:padding="5dp" android:tag="6" android:text="6" android:textColor="#ffffffff" android:textSize="30sp" android:textStyle="bold" /> </LinearLayout> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1" android:orientation="horizontal" > <Button android:id="@+id/btn1" android:layout_width="0dp" android:layout_height="match_parent" android:layout_margin="1dp" android:layout_weight="1" android:background="#ff000033" android:gravity="center" android:onClick="btnPressed" android:padding="5dp" android:tag="1" android:text="1" android:textColor="#ffffffff" android:textSize="30sp" android:textStyle="bold" /> <Button android:id="@+id/btn2" android:layout_width="0dp" android:layout_height="match_parent" android:layout_margin="1dp" android:layout_weight="1" android:background="#ff000033" android:gravity="center" android:onClick="btnPressed" android:padding="5dp" android:tag="2" android:text="2" android:textColor="#ffffffff" android:textSize="30sp" android:textStyle="bold" /> <Button android:id="@+id/btn3" android:layout_width="0dp" android:layout_height="match_parent" android:layout_margin="1dp" android:layout_weight="1" android:background="#ff000033" android:gravity="center" android:onClick="btnPressed" android:padding="5dp" android:tag="3" android:text="3" android:textColor="#ffffffff" android:textSize="30sp" android:textStyle="bold" /> </LinearLayout> <LinearLayout android:layout_width="fill_parent" android:layout_height="wrap_content" android:layout_weight="1" android:orientation="horizontal" > <Button android:id="@+id/btn0" android:layout_width="0dp" android:layout_height="match_parent" android:layout_margin="1dp" android:layout_weight="1" android:background="#ff000033" android:gravity="center" android:onClick="btnPressed" android:padding="5dp" android:tag="0" android:text="0" android:textColor="#ffffffff" android:textSize="30sp" android:textStyle="bold" /> <Button android:id="@+id/btnAgain" android:layout_width="0dp" android:layout_height="match_parent" android:layout_margin="1dp" android:layout_weight="1" android:background="#ffffff00" android:enabled="false" android:gravity="center" android:onClick="btnPressed" android:padding="5dp" android:tag="-1" android:text="Again" android:textColor="#ffffff00" android:textSize="30sp" android:textStyle="bold" /> </LinearLayout> </LinearLayout> </RelativeLayout> </RelativeLayout>
Notice that we also include an Achievements button next to the buttons for signing in and out. We will implement that button later. We won't go into too much detail on the sample game, if you have completed even simple apps before, this shouldn't be too difficult.
The game selects a random number between 0 and 9, and the player can choose a number button to make a guess. The game updates the text field to reflect whether or not the user guessed correctly. If a correct guess is made, the achievement is unlocked.
Step 2
Switch back to your Activity
class and add the following instance variables:
private Button button0, button1, button2, button3, button4, button5, button6, button7, button8, button9, buttonAgain; private int number; private Random rand; private TextView info;
These represent the buttons, number, random number generator, and text field. Add the following to your onCreate
method:
findViewById(R.id.show_achievements).setOnClickListener(this); button0=(Button)findViewById(R.id.btn0); button1=(Button)findViewById(R.id.btn1); button2=(Button)findViewById(R.id.btn2); button3=(Button)findViewById(R.id.btn3); button4=(Button)findViewById(R.id.btn4); button5=(Button)findViewById(R.id.btn5); button6=(Button)findViewById(R.id.btn6); button7=(Button)findViewById(R.id.btn7); button8=(Button)findViewById(R.id.btn8); button9=(Button)findViewById(R.id.btn9); buttonAgain=(Button)findViewById(R.id.btnAgain); info=(TextView)findViewById(R.id.guess_text); rand=new Random(); number=rand.nextInt(10);
Now add a method named disableNumbers
, which we will call when the user makes a number selection:
private void disableNumbers(){ button0.setEnabled(false); button0.setTextColor(Color.parseColor("#ff000033")); button1.setEnabled(false); button1.setTextColor(Color.parseColor("#ff000033")); button2.setEnabled(false); button2.setTextColor(Color.parseColor("#ff000033")); button3.setEnabled(false); button3.setTextColor(Color.parseColor("#ff000033")); button4.setEnabled(false); button4.setTextColor(Color.parseColor("#ff000033")); button5.setEnabled(false); button5.setTextColor(Color.parseColor("#ff000033")); button6.setEnabled(false); button6.setTextColor(Color.parseColor("#ff000033")); button7.setEnabled(false); button7.setTextColor(Color.parseColor("#ff000033")); button8.setEnabled(false); button8.setTextColor(Color.parseColor("#ff000033")); button9.setEnabled(false); button9.setTextColor(Color.parseColor("#ff000033")); buttonAgain.setEnabled(true); buttonAgain.setTextColor(Color.parseColor("#ff000033")); }
Implement another method, enableNumbers
, which is invoked when the user has chosen to play again:
private void enableNumbers(){ button0.setEnabled(true); button0.setTextColor(Color.WHITE); button1.setEnabled(true); button1.setTextColor(Color.WHITE); button2.setEnabled(true); button2.setTextColor(Color.WHITE); button3.setEnabled(true); button3.setTextColor(Color.WHITE); button4.setEnabled(true); button4.setTextColor(Color.WHITE); button5.setEnabled(true); button5.setTextColor(Color.WHITE); button6.setEnabled(true); button6.setTextColor(Color.WHITE); button7.setEnabled(true); button7.setTextColor(Color.WHITE); button8.setEnabled(true); button8.setTextColor(Color.WHITE); button9.setEnabled(true); button9.setTextColor(Color.WHITE); buttonAgain.setEnabled(false); buttonAgain.setTextColor(Color.parseColor("#ffffff00")); }
Now add the method we set as onClick
attribute for the buttons:
public void btnPressed(View v){ int btn = Integer.parseInt(v.getTag().toString()); if(btn<0){ //again btn number=rand.nextInt(10); enableNumbers(); info.setText("Guess the number!"); } else{ //number button if(btn==number){ info.setText("Yes! It was "+number); if(getApiClient().isConnected()) Games.Achievements.unlock(getApiClient(), getString(R.string.correct_guess_achievement)); } else{ info.setText("No! It was "+number); } disableNumbers(); } }
We call the Games Achievements utility to unlock the achievement if the user's guess was correct, first checking that we have a connection. We refer to the achievement using the string resource we created.
Last but not least, let's allow the user to view their achievements for the game. This will happen when they click the Achievements button we added. Extend the code in the onClick
method, adding an additional else if
:
else if (view.getId() == R.id.show_achievements){ startActivityForResult(Games.Achievements.getAchievementsIntent( getApiClient()), 1); }
We use the getAchievementsIntent
method with an arbitrary integer to display the user achievements within the game. Hitting the back button will bring the player back to the game. For more on the achievements methods, see the Achievements in Android page on the Developer Guide.
Step 3
You should be able to run your app at this point. When the app runs, it will start the user authorization and sign-in process, prompting the user to grant the necessary permissions.
Once signed in, the user will see a confirmation.
The user can choose to sign out and back in whenever they like. When the user selects a correct number, the achievement is unlocked and is displayed on top of the game screen.
The player can then continue as normal. Clicking the Achievements button will display their achievements. Tapping the back button will bring the player back to the game.
Conclusion
In this tutorial, we have explored a practical example of using achievements in an Android application. The sample app we used is simple, but the same principles apply to any game you are working with. Try adding another achievement to the Developer Console and implement it in your game to ensure you understand the concepts and processes.
Comments