Leaderboards - StansAssets/com.stansassets.android-native GitHub Wiki

This guide shows you how to use leaderboards APIs in an Android application to create visual leaderboards, record a player's score, and compare the score against the player's score from previous game sessions.

If you haven't already done so, you might find it helpful to review the leaderboards game concepts.

To start using the leaderboards API, your game must first obtain a AN_LeaderboardsClient object. You can do this by calling the AN_Games.GetLeadeboardsClient() method.

Updating the player's score

When the player's score changes (for example, when the player finishes the game), your game can update their score on the leaderboard by calling AN_LeaderboardsClient.SubmitScore(), and passing in the leaderboard ID and the raw score value. The following code snippet shows how your app can update the player’s score:

using SA.Android.GMS.Games;
...

string leaderboardsId = "YOUR_LeaderboardsId_HERE";
var leaderboards = AN_Games.GetLeaderboardsClient();
leaderboards.SubmitScore(leaderboardsId, 250);

You may also use the SubmitScoreImmediate method. This form of the API will attempt to submit the score to the server immediately within the callback, returning a AN_ScoreSubmissionData on success with information about the submission. See the snippet below:

using SA.Android.GMS.Games;
...

 var leaderboards = AN_Games.GetLeaderboardsClient();
 leaderboards.SubmitScoreImmediate(leaderboardId: leaderboardsId, score: 200, scoreTag: "Tag", callback: result => {
     if(result.IsSucceeded) {
         var scoreSubmissionData = result.Data;
         Debug.Log("SubmitScoreImmediate completed");
         Debug.Log($"scoreSubmissionData.PlayerId: {scoreSubmissionData.PlayerId}");
         Debug.Log($"scoreSubmissionData.PlayerId: {scoreSubmissionData.LeaderboardId}");
         foreach (var span in (AN_Leaderboard.TimeSpan[])System.Enum.GetValues(typeof(AN_Leaderboard.TimeSpan))) {
             var scoreSubmissionResult = scoreSubmissionData.GetScoreResult(span);
             Debug.Log($"scoreSubmissionData.FormattedScore: {scoreSubmissionResult.FormattedScore}");
             Debug.Log($"scoreSubmissionData.NewBest: {scoreSubmissionResult.NewBest}");
             Debug.Log($"scoreSubmissionData.RawScore: {scoreSubmissionResult.RawScore}");
             Debug.Log($"scoreSubmissionData.ScoreTag: {scoreSubmissionResult.ScoreTag}");
         }
    } else {
        Debug.LogError($"Failed to Submit Score Immediate {result.Error.FullMessage}");
    }
});

Displaying a leaderboard

To display leaderboard, call AN_LeaderboardsClient.GetLeaderboardIntent() to get an Intent to create the default leaderboard user interface. Your game can then bring up the UI by calling StartActivityForResult. The following code snippet shows how your app can display the default leaderboards user interface.

using SA.Android.App;
using SA.Android.GMS.Games;
...

var leaderboards = AN_Games.GetLeaderboardsClient();
leaderboards.GetAllLeaderboardsIntent(result => {
    if (result.IsSucceeded) {
        var intent = result.Intent;
        var proxy = new AN_ProxyActivity();
        proxy.StartActivityForResult(intent, intentResult => {
            proxy.Finish();
            //TODO you might want to check is user had sigend out with that UI
        });
    } else {
        Debug.LogError($"Failed to Get leaderboards Intent {result.Error.FullMessage}");
    }
});

An example of the default leaderboards UI is shown below.

Leaderboards

Creating In-Game leaderboards UI

If instead of using the default Google Play UI, you may build your own leaderboards in-game UI. In order to do so, you are going to need to load the leaderboards metadata.

Note: You would not be able to load the leaderboard metadata in case user haven't set his profile as public. Unfortunately, Google Play API does not provide a way to get this state. See the official google play support replay below:

I checked into it and the Play Console doesn’t currently support detecting player profile status (public/private). Luckily, we place a high value on developer feedback, and I’ll be sure to pass along your specific feedback to our product team. We’re continually adding new features and functionality, so please stay tuned.

So looks like it might be possible in future at least to give the user note to make the profile public, as it's currently done inside google play native UI

Leaderboards2

So back to the score retrieving code:

using SA.Android.GMS.Games;
...

var leaderboards = AN_Games.GetLeaderboardsClient();
leaderboards.LoadLeaderboardMetadata(false, result => {
    if (result.IsSucceeded) {
        Debug.Log($"Load Leaderboards Metadata Succeeded, count: {result.Leaderboards.Count}");
        foreach (var leaderboard in result.Leaderboards) {
            Debug.Log("------------------------------------------------");
            Debug.Log($"leaderboard.LeaderboardId: {leaderboard.LeaderboardId}");
            Debug.Log($"leaderboard.Description: {leaderboard.DisplayName}");
            Debug.Log($"leaderboard.Name: {leaderboard.IconImageUri}");
            Debug.Log($"leaderboard.UnlockedImageUri: {leaderboard.LeaderboardScoreOrder}");
            Debug.Log($"leaderboard.Variants.Count: {leaderboard.Variants.Count}");
            foreach (var variant in leaderboard.Variants) {
                Debug.Log("***************************");
                Debug.Log($"variant.Collection: {variant.Collection}");
                Debug.Log($"variant.DisplayPlayerRank: {variant.DisplayPlayerRank}");
                Debug.Log($"variant.DisplayPlayerScore: {variant.DisplayPlayerScore}");
                Debug.Log($"variant.NumScores: {variant.NumScores}");
                Debug.Log($"variant.PlayerRank: {variant.PlayerRank}");
                Debug.Log($"variant.PlayerScoreTag: {variant.PlayerScoreTag}");
                Debug.Log($"variant.RawPlayerScore: {variant.RawPlayerScore}");
                Debug.Log($"variant.TimeSpan: {variant.TimeSpan}");
                Debug.Log($"variant.HasPlayerInfo: {variant.HasPlayerInfo}");
            }
        }
    } else {
        Debug.LogError($"Load Leaderboards Failed: {result.Error.FullMessage}");
    }
});

As you may notice the AN_Leaderboard object contains IconImageUri property. The URL will be formatted similarly to the example below:

content://com.google.android.gms.games.background/images/b4d1b8fd/2956

This means you can't use UnityWebRequest to download the image using this URL. Since google play stores all the images locally. In order to obtain an image that you can use in your game, you need to use Image Manager.

Once you able to build your own leaderboards UI. You may also want to load leaderboards scores content in order to display it inside your game. And you able to do it with the following methods of AN_LeaderboardsClient object:

void LoadPlayerCenteredScores(string leaderboardId, int maxResults, Action<AN_LinkedObjectResult<AN_LeaderboardScores>> callback);
void LoadPlayerCenteredScores(string leaderboardId, AN_Leaderboard.TimeSpan span, AN_Leaderboard.Collection leaderboardCollection, int maxResults, bool forceReload, Action<AN_LinkedObjectResult<AN_LeaderboardScores>> callback);

void LoadTopScores(string leaderboardId, int maxResults, Action<AN_LinkedObjectResult<AN_LeaderboardScores>> callback);
void LoadTopScores(string leaderboardId, AN_Leaderboard.TimeSpan span, AN_Leaderboard.Collection leaderboardCollection, int maxResults, bool forceReload, Action<AN_LinkedObjectResult<AN_LeaderboardScores>> callback);

void LoadMoreScores(AN_LeaderboardScoreBuffer buffer, int maxResults, AN_PageDirection pageDirection, Action<AN_LinkedObjectResult<AN_LeaderboardScores>> callback);

Let's, for example, use the LoadTopScores method to load top leaderboards scores:

using SA.Android.GMS.Games;
...

var leaderboards = AN_Games.GetLeaderboardsClient();
leaderboards.LoadTopScores(leaderboardId: leaderboardsId, maxResults: 20, callback: result => {
    if(result.IsSucceeded) {
        var scores = result.Data;
        var buffer = scores.Scores;
        Debug.Log($"scores.Leaderboard.DisplayName: {scores.Leaderboard.DisplayName}");
        Debug.Log($"Loaded scores Count: {buffer.Scores.Count}");
        foreach (var score in buffer.Scores) {
            Debug.Log($"score.DisplayRank: {score.DisplayRank}");
            Debug.Log($"score.DisplayScore: {score.DisplayScore}");
            Debug.Log($"score.Rank: {score.Rank}");
            Debug.Log($"score.RawScore: {score.RawScore}");
            Debug.Log($"score.ScoreHolder: {score.ScoreHolder}");
            Debug.Log($"score.ScoreHolderDisplayName: {score.ScoreHolderDisplayName}");
            Debug.Log($"score.ScoreHolderIconImageUri: {score.ScoreHolderIconImageUri}");
            Debug.Log($"score.ScoreHolderHiResImageUri: {score.ScoreHolderHiResImageUri}");
            Debug.Log($"score.ScoreTag: {score.ScoreTag}");
            Debug.Log($"score.TimestampMillis: {score.TimestampMillis}");
            Debug.Log("------------------------------------------------");
        }
    } else {
        Debug.LogError("Failed to Load Top Scores " + result.Error.FullMessage);
    }
});