This codelab will teach you how to extend an existing Unity game to run on an Android device and integrate Play Game Services. In this section, we will set up the Unity environment with all of the materials you will need to complete this codelab.

What you'll learn

What you'll need

Game Summary

For this codelab, we'll be using a simple and entertaining game, called "Lollygagger". The main game play is to travel along a path, atop a robot, shooting Lollipop "cannonballs" at the Androids that are lollygagging around. Key features of note are:

How will you use use this tutorial?

Read it through only Read it and complete the exercises

How would you rate your experience with building Unity apps?

Novice Intermediate Proficient

How would you rate your experience with building Android apps?

Novice Intermediate Proficient

How would you rate your experience with Google Play Game Services?

Novice Intermediate Proficient

Open a terminal window and clone the repository:

$ git clone https://github.com/googlecodelabs/playservices_unity.git

Then get the Google Play Game Services plugin by cloning it from GitHub also:

$ git clone https://github.com/playgameservices/play-games-plugin-for-unity.git

Next, we'll build the starter game.

First, we'll create a new Unity project, add the starter game and make sure it runs. From there, we'll add Play Game services.

Start Unity

  1. Start Unity by clicking on it in the Dock:

  1. Click Start Using Unity.
  1. Select New Project. Give it the project name Lollygagger. Keep 3D selected.
  2. Click Create project to close the the Welcome to Unity dialog.

Import the game assets

Import the sample game scenes and assets into your project:

  1. Click Assets > Import Package > Custom Package.
  2. Select the playservices_unity/assets/lollygagger_step0.unitypackage file.
  3. Click Import.

Configure the Android player

  1. Configure Unity to build an Android application:
  1. Add the game scenes to the build:

  1. Configure the Unity player settings:

  1. Set the Android Banner by expanding the Icon section

Configure Bundle and Code Signing

Still in the player settings, expand the "Other Settings" section by clicking on it.

Change the bundle identifier. This identifier needs to match the application configuration in the Play Console (we'll look at that in the next step).

  1. Enter the Bundle ID: com.google.io.lollygagger

Enter a unique Bundle ID, this follows .Net namespace (or Java package) naming rules. Typically this is of the form: com.<yourcompany>.<appname>. For this example use: com.google.io.lollygagger

  1. Configure the Android TV properties
  1. At the bottom of the Player Settings, expand the Publishing Settings section. Make sure "Use Existing Keystore" is checked.
  2. Click Browse Keystore and select the keystore for this project named playservices_unity/unity_codelab.keystore. The keystore is used to cryptographically sign the application. The fingerprint of the key and the bundle id uniquely identify the application when communicating with Play Game Services.

  1. Enter the keystore password: android
  2. Select the alias: androiddebugkey
  3. Enter the password: android

Save and Run

  1. Save your project! Better safe than sorry :)
  2. Click Build & Run under the File menu. When prompted for a name for the APK file, enter Lollygagger.apk.
  3. You can now run the app! Look for Lollygagger in the apps list on the phone.

Congratulations! If you can play the starter project game on your Android device, you are now ready to achievements, leaderboards, and other Play Game Services that will help engage and retain your players.

Troubleshooting

Even the most simple things can have gotchas! Here are a couple and what to do about it. If you're still having problems ask for help!

Issue

Solution

Issue: Error building Player: UnityException: Bundle Identifier has not been set up correctly

Solution: Set the bundle identifier to something other than the default. This is in the player settings > Other Settings section.

Create Your Game Project

Before your users can sign in and use Play Game Services features, you need to register your game with the Developer Console and link it to your Unity project. Usually every developer or organization of developers has their own account. But for this codelab, we'll use a shared account in read-only mode. We'll visit each item that needs to be configured so that when you build your own game, you are familiar with the steps. For a more detailed review of the Play Developer console you can visit: https://developers.google.com/games/services/console/enabling

Navigate to the Google Play Developer Console and sign in.

  1. Click Game Services on the left tabs, and then select the Lollygagger I/O Sample.
  2. On the Game Details page you can set the title, description, category and other details.
  3. Confirm that the Saved Games toggle is set to ON. This is a very important step, you will need to have this feature enabled to complete the extra credit section of this codelab.

Link Your Android App

  1. Click on the Linked Apps tab in the left sidebar, then click Android. Note: If you don't see a ‘Linked Apps' button, resize your window to fullscreen or click the ‘hamburger' button on the left-hand side.
  2. Click on the game we are working on, Lollygagger I/O Sample.
  3. Under Package Name, is the Bundle Identifier we used when setting up the Unity project (which you can find by opening File>Build Settings and clicking Player Settings). Make sure you use the same string in both places. For this codelab it is: com.google.io.lollygagger.

Authorize Your Android App

Your application is digitally signed using a specific key. This key needs to be associated with the bundle id on the server in order to authorize access to the game services. Since this is already configured, we just need to review the information:

  1. Click on Game details in the list on the left.
  2. Scroll the page all the way to the bottom to the "API CONSOLE PROJECT" section:
  3. Click on the link to the API console project: 'Lollygagger I/O Sample. This will open the Google API Console.
  4. On the left, click "Credentials". This shows all the application clients that are configured for the application. Click on "Android client 1" to view our information. (If you were setting up your own app, you would enter information here).

  1. Verify that the keystore being used for signing the application is the same as the one configured by comparing the certificate fingerprint. To get the fingerprint of the local certificate, open a terminal window and run:
keytool -list -v -keystore playservices_unity/unity_codelab.keystore -alias androiddebugkey -storepass android -keypass android
  1. Now close the tab for the Credentials and go back to the play console. Click the Testing tab in the left sidebar. This page lists all the accounts that are testers for the game. In order to play the game on your Android device before the game is published, you need to sign in as a tester. Since this game is already published, anyone can sign in and play.

There is only one leaderboard for this game that tracks the number of targets hit in a single level.

  1. Navigate back to the Lollygagger project in the Google Play Developer Console and click on the Leaderboards tab.
  2. Review the leaderboard configuration by clicking on "Targets Hit In One Level". Here there are the settings for formatting the score, and the ordering.
  3. Go back to the Leaderboard list.

Now that you have created a game project in the Developer Console, you are ready to configure your Unity project to interact with Play Game Services.

Import the Play Game Services plugin

  1. Open Unity and import the Play Game Services plugin for Unity, click Assets > Import Package > Custom Package and select playservices_unity/GooglePlayGamesPlugin-0.9.33.unitypackage.
  2. Make sure all the files are selected and click Import.

Setup the plugin for the Application

  1. Open the project in Unity and click Window > Google Play Games > Setup > Android Setup....
  2. Enter the full name of the C# class to store the IDs for the game resources. This class we'll reference in the code in order to perform actions like submitting scores and unlocking achievements. Use GPGSIds for the "constants class name". In a larger project we would normally use a namespace to organize the classes.
  3. Switch back to the Play Game console, and go to the list of leaderboard resources (you should still be there...). Click on Get Resources in the middle of the page, and copy the contents for Android to the clipboard.
  4. Paste the contents of the clipboard into the Resources Definition text area.
  5. You can leave the other settings and the web client Id empty.
  6. Click Setup.
  7. There will be a confirmation that it is setup successfully, click Setup.

Now that you have registered your game in the Developer Console, you are ready to start integrating Play Game Services into your app. In this section, we will add a sign-in button to your game's main menu and authenticate the user for Google Play Games.

Initialize Play Game Services

We are going to start by adding sign-in functionality to the game's main menu. First open the MainMenu.unity scene in the Unity editor. If you press Play, you should see the following:

In the Hierarchy, click on Main Camera. In the Inspector view on the right-hand side, scroll down to find the ‘Main Menu Events' script component that is attached to Main Camera. Double click the script to open it in the editor. To initialize Play Game Services, we will need to add a Start() method, like this:

using System.Collections;
using GooglePlayGames;
using GooglePlayGames.BasicApi;
using UnityEngine;

public class MainMenuEvents : MonoBehaviour {

    // ... other code here... 
    public void Start() {
       GameObject startButton = GameObject.Find("startButton");
       EventSystem.current.firstSelectedGameObject = startButton;


        //  ADD THIS CODE BETWEEN THESE COMMENTS

        // Create client configuration
        PlayGamesClientConfiguration config = new 
            PlayGamesClientConfiguration.Builder()
            .Build();

        // Enable debugging output (recommended)
        PlayGamesPlatform.DebugLogEnabled = true;
        
        // Initialize and activate the platform
        PlayGamesPlatform.InitializeInstance(config);
        PlayGamesPlatform.Activate();
       // END THE CODE TO PASTE INTO START
    }

    // ...
}

Now we need to declare these new classes we are using, so add these using statements at the top of the file with the others:

using GooglePlayGames.BasicApi;
using GooglePlayGames;

The code above will initialize the Play Games platform in your script with the saved games feature enabled.

Add the sign-in UI

Add a button to the GUI by right-clicking on Project at the bottom of your screen and selecting the Prefabs folder.

In the Prefabs folder find the signInButton prefab and drag it onto the Panel element of the hierarchy, like below. It should be a child element of Panel, so if you collapse Panel, you should not be able to see signInButton:

Now add the authStatus prefab to the hierarchy with the same click-and-drag method. Don't worry if there is no visual result, the content of authStatus is currently the empty string, we will update the content in code. When you have added authStatus you should have the following hierarchy:

Add sign-in functionality

Re-open the MainMenuEvents script (attached to the ‘Main Camera' object) where we activated the Play Games platform. Add a new SignIn function like below:

public void SignIn() {
        Debug.Log("signInButton clicked!");
}

Now we have to link this function to the OnClick event of the button:

These steps are illustrated in the clip below:

The final result should look like this:

To ensure that you linked the event correctly, click Play in the Unity Editor and click the signinButton when the main menu loads. If you added the button correctly, you should see messages appear in the debug logs.

Press play again to exit this mode.

Now we will make the button actually useful. First we need to add some boilerplate to access the signInButton and authStatus elements from your code. Open the MainMenuEvents script and add the following lines:

First add member variables to reference the Text elements on the UI, paste them in the MainMenuEvents class at the top

using UnityEngine.UI;

public class MainMenuEvents : MonoBehaviour {
    
     // ADD THESE TWO LINES
    private Text signInButtonText;
    private Text authStatus;
}

Next, add the code that assigns values to these variables by pasting these lines at the top of the Start() method:

using UnityEngine.UI;

public class MainMenuEvents : MonoBehaviour {
    
    private Text signInButtonText;
    private Text authStatus;

    public void Start() {

        // ADD THESE LINES
        // Get object instances
        signInButtonText =
            GameObject.Find("signInButton").GetComponentInChildren<Text>();
        authStatus = GameObject.Find("authStatus").GetComponent<Text>();

        // ...
    }
    // ...
}

Next, add a function called SignInCallback. This will be called when the authentication is completed. The parameter indicates if the sign-in was successful or not.

public void SignInCallback(bool success) {
        if (success) {
            Debug.Log("(Lollygagger) Signed in!");
            
            // Change sign-in button text
            signInButtonText.text = "Sign out";
            
            // Show the user's name
            authStatus.text = "Signed in as: " + Social.localUser.userName;
        } else {
            Debug.Log("(Lollygagger) Sign-in failed...");
            
            // Show failure message
            signInButtonText.text = "Sign in";
            authStatus.text = "Sign-in failed";
        }
    }

Now call authenticate when the Sign in button is clicked. Modify the SignIn function so that it matches the code below:

    public void SignIn() {
        if (!PlayGamesPlatform.Instance.localUser.authenticated) {
            // Sign in with Play Game Services, showing the consent dialog
            // by setting the second parameter to isSilent=false.
            PlayGamesPlatform.Instance.Authenticate(SignInCallback, false);
        } else {
            // Sign out of play games
            PlayGamesPlatform.Instance.SignOut();
            
            // Reset UI
            signInButtonText.text = "Sign In";
            authStatus.text = "";
        }
    }

The code above implements both sign-in and sign-out, depending on the user's state. However the code above only triggers sign-in when the user presses the sign-in button. We'd like to have returning users silently signed in when they open the app. Add the following line to Start() to attempt silent sign-in when the app is opened:

public void Start() {
        // ...

        // PASTE THESE LINES AT THE END OF Start()
        // Try silent sign-in (second parameter is isSilent)
        PlayGamesPlatform.Instance.Authenticate(SignInCallback, true);
}

Test signing in

Now let's test the sign-in process. This step requires you to run the game on your Android device.

  1. Go to File > Build & Run the app. Replace the Lollygagger.apk with this new version.
  2. Run the Lollygagger app on the phone.
  3. When the app starts, click the ‘Sign in' button.

Now that your users are signed in with access to Play Game Services, it is time to start adding awesome features to your game. In this section, we will add achievements to the game for hitting enemies and a UI for users to view their progress.

Create Achievements in the Developer Console

There are two achievements for this game. One that rewards the user for shooting her first target, and another that rewards the user for shooting 10 total targets. The latter will be an "incremental" achievement, which means the user needs to take multiple steps to unlock it.

  1. Navigate back to the Lollygagger project in the Google Play Developer Console and click on the Achievements tab. The achievements are already configured, but let's review them:
  2. Click the "Sharpshooter" achievement. Here is where the properties of the achievement are set. This achievement is an incremental achievement, there are 10 steps before it is unlocked.
  3. Go back to the Achievements list. You should now be at the Achievements screen, which will display the IDs of the two achievements you just created:

View Achievements

Now that your game has achievements in the Developer Console, your players may want to be able to check their progress on all of the achievements in your game and see which achievements they have not yet completed. Let's add a button to the main menu that brings up the achievements list UI.

First, let's add the code to show achievements. Open the MainMenuEvents script and add the following function:

public void ShowAchievements() {
        if (PlayGamesPlatform.Instance.localUser.authenticated) {
            PlayGamesPlatform.Instance.ShowAchievementsUI();
        }
        else {
          Debug.Log("Cannot show Achievements, not logged in");
        }
    }

Now create an Achievements button in the MainMenu scene by adding the achButton prefab to the hierarchy in the same way that you added the signInButton prefab earlier:

Finally, link the On Click event of the button to the ShowAchievements() method in the MainMenuEvents script, using the same method as you used to link the Sign In button to the SignIn() method:

Add a variable to the script that points to the achievement button, and initialize it in Start():

public class MainMenuEvents : MonoBehaviour {
    
    // ...
    private GameObject achButton;

    public void Start() {
        // ...
        // Get object instances
        // ...
        achButton = GameObject.Find("achButton");

        // Try silent sign-in (second parameter is isSilent)
        // ...
    }
    // ... 
 }

Finally, add a method called Update() which is called by Unity on every frame. In here we'll show or hide the achievement button depending on the player's authenticated state:

    public void Update() {
         achButton.SetActive(Social.localUser.authenticated);
    }

Build and run

Now save your progress and build and run the game.

Test achievements

When you sign in at the main menu you your UI should look like this:

And after clicking ‘Achievements', you should see a screen like this:

Now your users can check the status of their achievements at any time! If you add more achievements via the Developer Console, they will show up on this screen.

Trigger Achievements

Now that you can check the progress of your achievements, we need to add code to trigger them when the user hits targets in the game.

Open the DroidController.cs script from the scripts folder and modify it to match the code below.

Remember to also add the using statement at the top since we're referencing a new class:

using GooglePlayGames;
public class DroidController : MonoBehaviour {

    void OnCollisionEnter (Collision col)
    {
        // if we are alive and hit by a projectile, then die.
        // and turn off the constraint to stand up so we bounce around.
        if (!isDead && col.gameObject.tag.Equals ("Projectile")) {
             Debug.Log("(Lollygagger) Droid hit!");
            Rigidbody rb = GetComponent<Rigidbody> ();
            rb.constraints = RigidbodyConstraints.None;
            rb.useGravity = true;
            Die ();
        
            //START CODE TO COPY FOR ACHIEVEMENT TRACKING
            
            // Only do achievements if the user is signed in
            if (Social.localUser.authenticated) {
               // Unlock the "welcome" achievement, it is OK to
               // unlock multiple times, only the first time matters.
                PlayGamesPlatform.Instance.ReportProgress(
                    GPGSIds.achievement_welcome_to_lollygagger,
                    100.0f, (bool success) => {
                           Debug.Log("(Lollygagger) Welcome Unlock: " +
                                 success);
                });

                // Increment the "sharpshooter" achievement
               PlayGamesPlatform.Instance.IncrementAchievement(
                      GPGSIds.achievement_sharpshooter,
                      1,
                      (bool success) => {
                        Debug.Log("(Lollygagger) Sharpshooter Increment: " +
                           success);
               });
            } // end of isAuthenticated
          
            // END CODE TO COPY



       } // end of is not dead and a projectile hit
   } // end of OnCollisionEnter
} // end of class

Build and run

Now save your progress and build and run the game.

Test unlocking achievements

At the main menu, first sign in then begin a game. When you hit your first (and later, 10th) target you will see an ‘Achievement Unlocked' dialog appear at the top of the screen.

Congratulations!, you just got your first Play Game Services achievement!

Once you have finished adding achievements to your game, leaderboards are the natural next step. In this section, we will add a global high score leaderboard to the game and a UI for users to view their scores.

We added the leaderboard to the Play Console already, so we don't need to do any additional configuration, and we can jump right into the coding!

View Leaderboards

Let's add a button to the main menu that brings up the leaderboards list UI, just like the Achievements button we added earlier.

First, let's add the code to bring up the leaderboards UI. Open the MainMenuEvents script and add the following function:

    public void ShowLeaderboards() {
        if (PlayGamesPlatform.Instance.localUser.authenticated) {
            PlayGamesPlatform.Instance.ShowLeaderboardUI();
        }
        else {
          Debug.Log("Cannot show leaderboard: not authenticated");
        }
    }

Now create a button in the main menu scene by adding the ldrButton prefab to the hierarchy in the same way that you added the achButton and signInButton prefabs:

Finally, link the On Click event of the button to the ShowLeaderboards() method in the MainMenuEvents script, using the same method as you used to link the Achievements button to the ShowAchievements() method:

The last step is to configure the button not to display unless the user is signed in with Play Game Services. Modify MainMenuEvents to add the following code, mimicking the code used for the Achievements button:

  1. Declare the member variable ldrButton
  2. Initialize ldrButton by calling GameObject.Find()
  3. Initially set ldrButton to inactive
  4. Update the active state of ldrButton in Update()
public class MainMenuEvents : MonoBehaviour {
    
    // ...
    private GameObject ldrButton;

    public void Start() {
        // ...
        achButton = GameObject.Find("achButton");
        ldrButton = GameObject.Find ("ldrButton");

        // ...
        // Try silent sign-in (second parameter is isSilent)
        // This should always be the last line of Start()
        PlayGamesPlatform.Instance.Authenticate(SignInCallback, true);
    }

    public void Update() {

        // ... 

        // Hide or show the achievement and leaderboards buttons
        achButton.SetActive(Social.localUser.authenticated);
        ldrButton.SetActive(Social.localUser.authenticated);
    }

}

Build and run

Now save your progress and build and run the game.

Testing Leaderboards

When you sign in at the main menu you your UI should look like this:

And after clicking ‘Leaderboards' and then clicking on the ‘Targets Hit in One Level', you should see a screen like this:

Now your users can check the status of the leaderboards at any time! If you add more leaderboards via the Developer Console, they will show up on this screen.

Update Leaderboard Scores

We will update the user's score at the end of each level, rather than with each enemy killed in order to cut down on the number of requests we have to make to the leaderboards API. First, let's add some accounting to keep track of targets hit. Open GameManager from within the scripts folder and add the following code, modifying RestartLevel and NextLevel and adding IncrementHits:

public class GameManager : MonoBehaviour {

    // ...  existing code

    // number of hits scored.
    private int mHits;
    
    public GameManager() {
        // ... existing code 
        // start with no hits.
        mHits = 0;
    }

    // ... existing code
    public void RestartLevel() {
        // ... existing code
        // restarting the level, reset the hits
        mHits = 0;
    }

    public void NextLevel () {
        // ... existing code
        // moving to the next level, reset the hits
        mHits = 0;
    }

    // NEW function. Add this.
    public void IncrementHits() {
        mHits = mHits + 1;
    }
}

Then open DroidController and add a call to IncrementHits in the collision logic:

void OnCollisionEnter (Collision col)
    {
        // ...
        if (!isDead && col.gameObject.tag.Equals ("Projectile")) {
            GameManager.Instance.IncrementHits();
            // ...
        }
    }

Now that we are keeping track of the user's hits, we will add the code to update the leaderboard. Open GameManager, adding a call to ReportScore() in ShowEndMenu(). The leaderboard ID is declated in GPGSIds - which is the class generated by running the Setup menu item. Make sure to check the authenticated state before reporting the score.

using GooglePlayGames;

public class GameManager : MonoBehaviour {

    // ...

    public void ShowEndMenu() {
        if (EventSystem.current.currentSelectedGameObject == null)
        {
            EventSystem.current.SetSelectedGameObject(
                restartMenuButton.gameObject);
        }

        if (mEndMenu.activeSelf)
        {
            return;
        }
// ADD THIS ELSE CONDITION TO REPORT THE SCORE
        else
        {
            // Submit leaderboard scores, if authenticated
            if (PlayGamesPlatform.Instance.localUser.authenticated)
            {
                // Note: make sure to add 'using GooglePlayGames'
                PlayGamesPlatform.Instance.ReportScore(mHits,
                    GPGSIds.leaderboard_targets_hit_in_one_level,
                    (bool success) =>
                    {
                        Debug.Log("(Lollygagger) Leaderboard update success: " + success);
                    });
            }

        }
// END LEADERBOARD CODE

        mEndMenu.SetActive(true);
    }
}

Build and run

Now save your progress and build and run the game.

Test the leaderboard submission

Run the game on your Android device and play a level all the way through (make sure you hit a few targets!). This will submit a score to the leaderboard.

Go back to the main menu and hit the Leaderboards button to check your score and make sure the submission was successful!

Pat yourself on the back! You just added sign-in, achievements, and leaderboards to your Unity game. That's only the beginning of the cool features Play Game Services has to offer. This section will show you how to use the saved games API to persist game data to the cloud and share it across devices.

Enable Saved Games

Enabling saved games involves two steps: turning the feature on in the Developer Console, and enabling the feature when activating the platform in your code.

First, navigate back to the Lollygagger project in the Google Play Developer Console. In the Game Details tab, confirm that turn Saved Games is turned to ON and matches the image below (you should have done this earlier). Then click the blue Save button at the top of the screen.

Enable Saved Games API

Next, open the MainMenuEvents script and edit the Start method to enable saved games on your PlayGamesClientConfiguration:

public void Start() {
        // ...

        // Create client configuration with saved games enabled
        PlayGamesClientConfiguration config = new
            PlayGamesClientConfiguration.Builder()
            .EnableSavedGames()
            .Build();

        // ...
    }

Build and run

Now save your progress and build and run the game.

Save Your Score

Writing data to the saved games API is a two-step process. The first is opening the saved games ‘snapshot' where you would like to save the data. The second is writing to the file, and committing the update. Open GameManager and add the following code which adds the ReadSavedGame and WriteSavedGame functions:

using System;
using GooglePlayGames.BasicApi;
using GooglePlayGames.BasicApi.SavedGame;

public class GameManager : MonoBehaviour {

    // ...

    public void ReadSavedGame(string filename, 
                             Action<SavedGameRequestStatus, ISavedGameMetadata> callback) {
        
        ISavedGameClient savedGameClient = PlayGamesPlatform.Instance.SavedGame;
        savedGameClient.OpenWithAutomaticConflictResolution(
            filename, 
            DataSource.ReadCacheOrNetwork, 
            ConflictResolutionStrategy.UseLongestPlaytime, 
            callback);
    }
    
    public void WriteSavedGame(ISavedGameMetadata game, byte[] savedData, 
                               Action<SavedGameRequestStatus, ISavedGameMetadata> callback) {
        
        SavedGameMetadataUpdate.Builder builder = new SavedGameMetadataUpdate.Builder()
            .WithUpdatedPlayedTime(TimeSpan.FromMinutes(game.TotalTimePlayed.Minutes + 1))
            .WithUpdatedDescription("Saved at: " + System.DateTime.Now);
        
        // You can add an image to saved game data (such as as screenshot)
        // byte[] pngData = <PNG AS BYTES>;
        // builder = builder.WithUpdatedPngCoverImage(pngData);
        
        SavedGameMetadataUpdate updatedMetadata = builder.Build();
        
        ISavedGameClient savedGameClient = PlayGamesPlatform.Instance.SavedGame;
        savedGameClient.CommitUpdate(game, updatedMetadata, savedData, callback);
    }
}

Now let's modify ShowEndMenu to update the total number of targets hit at the end of each level by calling WriteUpdatedScore():

public void ShowEndMenu() {
        // ...
        // Only do these actions once (ShowEndMenu called on a loop)
        if (mEndMenu.activeSelf) {
            return;
        }
        else
        {
            if (PlayGamesPlatform.Instance.localUser.authenticated) {
                // Note: make sure to add a 'using GooglePlayGames'
                //  statement to this script
                PlayGamesPlatform.Instance.ReportScore(mHits,
                    TARGETS_HIT_ID, (bool success) => {
                    Debug.Log ("(Lollygagger) Leaderboard update success: " + success);
                });

// NEW: add this function call.
                // Read saved game data and update
                WriteUpdatedScore();
// END new code to add.
            }
        }

        mEndMenu.SetActive(true);
    }

Finally, we need to implement WriteUpdatedScore:

public void WriteUpdatedScore() {
        // Local variable
        ISavedGameMetadata currentGame = null;

        // CALLBACK: Handle the result of a write
        Action<SavedGameRequestStatus, ISavedGameMetadata> writeCallback = 
        (SavedGameRequestStatus status, ISavedGameMetadata game) => {
            Debug.Log("(Lollygagger) Saved Game Write: " + status.ToString());
        };

        // CALLBACK: Handle the result of a binary read
        Action<SavedGameRequestStatus, byte[]> readBinaryCallback = 
        (SavedGameRequestStatus status, byte[] data) => {
            Debug.Log("(Lollygagger) Saved Game Binary Read: " + status.ToString());
            if (status == SavedGameRequestStatus.Success) {
                // Read score from the Saved Game
                int score = 0;
                try {
                    string scoreString = System.Text.Encoding.UTF8.GetString(data);
                    score = Convert.ToInt32(scoreString);
                } catch (Exception e) {
                    Debug.Log("(Lollygagger) Saved Game Write: convert exception");
                }
                
                // Increment score, convert to byte[]
                int newScore = score + mHits;
                string newScoreString = Convert.ToString(newScore);
                byte[] newData = System.Text.Encoding.UTF8.GetBytes(newScoreString);
                
                // Write new data
                Debug.Log("(Lollygagger) Old Score: " + score.ToString());
                Debug.Log("(Lollygagger) mHits: " + mHits.ToString());
                Debug.Log("(Lollygagger) New Score: " + newScore.ToString());
                WriteSavedGame(currentGame, newData, writeCallback);
            }
        };

        // CALLBACK: Handle the result of a read, which should return metadata
        Action<SavedGameRequestStatus, ISavedGameMetadata> readCallback = 
        (SavedGameRequestStatus status, ISavedGameMetadata game) => {
            Debug.Log("(Lollygagger) Saved Game Read: " + status.ToString());
            if (status == SavedGameRequestStatus.Success) {
                // Read the binary game data
                currentGame = game;
                PlayGamesPlatform.Instance.SavedGame.ReadBinaryData(game, 
                                                    readBinaryCallback);
            }
        };

        // Read the current data and kick off the callback chain
        Debug.Log("(Lollygagger) Saved Game: Reading");
        ReadSavedGame("file_total_hits", readCallback);
    }

Now let's see if it all worked. Run the game on your device, and on your machine run:

adb logcat | grep "Lollygagger"

Play a level and hit some targets. At the end of the level, you should see some Logcat output like this:

I/Unity   ( 5911): (Lollygagger) Saved Game: Reading
I/Unity   ( 5911): (Lollygagger) Leaderboard update success: True
I/Unity   ( 5911): (Lollygagger) Saved Game Read: Success
I/Unity   ( 5911): (Lollygagger) Saved Game Binary Read: Success
I/Unity   ( 5911): (Lollygagger) Old Score: 0
I/Unity   ( 5911): (Lollygagger) mHits: 7
I/Unity   ( 5911): (Lollygagger) New Score: 7
I/Unity   ( 5911): (Lollygagger) Saved Game Write: Success

If you play again, you will see that the score increases over time (rather than re-setting every level). You may be thinking "big deal, all I did was persist an integer and I had to write a ton of code!". So far, you would be right. But now let's demonstrate the real power of Saved Games. Uninstall the game from your Android device, then re-install the game from Unity. After you sign in and play through a level, your scores will be intact! This will work across devices as well, as long as you sign in with the same Google account.

Exercise: Post High Scores

If you made it all the way here, you are well on your way to becoming a master of Play Game Services. This section will be an exercise for you to see what you have learned:

Create a new leaderboard called "All Time Hits", and update it every time you write a new score to the saved games API.

If you complete this task, you will be able to display all time hit counts for all of your users, even combining hits from multiple devices! Pretty cool, right?

Now that you've finished the code lab, there are a few more things you can do before you are ready to publish your awesome game. This section will describe what is left and point you to some resources where you can continue learning.

More Features

There are many more great features of Play Game Services that were not covered by this codelab such as: