Context
As I’ve recently decided to publish games at a faster pace, I decided that I needed to streamline the process of creating and integrating leaderboards. Previously, I created a new database and wrote new APIs for each game’s leaderboard. This approach is extremely tedious and wildly inefficient (display of my noobness). A solution to this problem is simply to have a third party handle leaderboards.
I also decided to implement facebook login into leaderboards. As such, the first place I searched was facebook for developers platform. Facebook provides a decent and well documented package for Unity. The tutorials are quite simple and it’s easy to write your own script to perform initialization and logins within a very short period of time. Previously, facebook offered a ‘Scores and Achievements API’ which would have filled my needs but its recently been deprecated. There currently exists a facebook Leaderboards API, but at the time of writing, this service seems to only be offered to Instant Games and not to Unity projects.
A little bit of searching around for an alternative then lead me to PlayFab. PlayFab provides an enormous amount of services to game developers supporting most development platforms. The look and feel of its web end is also gorgeous.
Once you create a free account, you simply login and set up the details for your game. The Unity tutorial walks you through downloading the sdk and making your first api call. Now onto some code. It is desired that a player first logs into facebook which is then received by the PlayFab SDK to get/create its own player model.
using System.Collections;
using System.Collections.Generic;
using PlayFab;
using PlayFab.ClientModels;
using UnityEngine;
using Facebook.Unity;
using LoginResult = PlayFab.ClientModels.LoginResult;
using System;
public class PlayFabFuncs : MonoBehaviour {
public bool IsRunning
{
get
{
return isRunning;
}
}
private static bool isLoaded = false;
private bool isRunning;
// Use this for initialization
void Awake () {
if (isLoaded)
{
Destroy(this.gameObject);
}
isLoaded = true;
DontDestroyOnLoad(gameObject);
FB.Init(OnFacebookInitialized);
}
void Start()
{
if (FB.IsLoggedIn)
{
GetTop20Leaderboard();
}
}
private void OnFacebookInitialized()
{
if (FB.IsLoggedIn)
{
PlayFabClientAPI.LoginWithFacebook(new PlayFab.ClientModels.LoginWithFacebookRequest
{
CreateAccount = true,
AccessToken = AccessToken.CurrentAccessToken.TokenString
}, OnPlayfabFBAuthComplete, OnPlayfabFBAuthFailed);
}
}
public void LoginWithFacebook()
{
isRunning = true;
FB.LogInWithReadPermissions(null, OnFacebookLoggedIn);
}
private void OnFacebookLoggedIn(ILoginResult result)
{
if(result == null || string.IsNullOrEmpty(result.Error)){
PlayFabClientAPI.LoginWithFacebook(new PlayFab.ClientModels.LoginWithFacebookRequest
{
CreateAccount = true, AccessToken = AccessToken.CurrentAccessToken.TokenString
}, OnPlayfabFBAuthComplete, OnPlayfabFBAuthFailed);
}
else{
DebugLog("Facebook Log In Failed: " + result.Error);
isRunning = false;
}
}
private void OnPlayfabFBAuthComplete(LoginResult result)
{
isRunning = false;
//Perform any other actions here
}
private void OnPlayfabFBAuthFailed(PlayFabError error)
{
isRunning = false;
//Debug error messages here
}
The code above follows a singleton pattern to prevent duplicate instances from being spawned. This script is attached to a GameObject in the main menu scene. The isLoaded private static variable prevents any duplicates from being created upon returning to the main menu scene. It appears that both the facebook sdk and PlayFab sdk use Coroutines or an equivalent for their api calls so it is ill advised to embed their methods in your own coroutines. This is also the reason why the isRunning variable is implemented, to check whether or not facebook or playfab is performing an operation. This becomes particularly useful to display a loading screen when waiting for facebook to login.
The application flow is straightforward. Upon awake, the facebook sdk is initialized. At completion, OnFacebookInitialized is run as it was provided as a callback. if FB.IsLoggedIn, the PlayFab sdk then initializes itself with the connected facebook account. This step in particular isn’t spoon fed to newcomers and certainly was a roadblock in my development process even though it should have been intuitive to me.
In PlayFab’s web backend, you then set up a leaderboard which spawns a database to hold your data (note: leaderboards are referred to as a statistic in PlayFab’s documentation). The snippet below shows sample code that gets the top 20 players on the statistic.
public void GetTop20Leaderboard()
{
isRunning = true;
PlayFabClientAPI.GetLeaderboard(
new GetLeaderboardRequest()
{
MaxResultsCount = 20,
StatisticName = "score",
StartPosition = 0
},
result => {
SaveLeaderboardData(result.Leaderboard);
isRunning = false;
},
error => {
DebugLog("Error with GetTop20Leaderboard " + error.GenerateErrorReport());
isRunning = false;
}
);
}
Most of PlayFab API calls follow the format of PlayFabClient.Action(new ActionRequest{……}) where result and error callback are to be set. The API documentation has everything that you need to get up and running in no time and the community is helpful.
Limitations
Being on a free account, I’m limited to 25 leaderboards and unlimited players which I think is pretty amazing (Full list of limits can be found in your account under Settings->Limits).
My one complaint is the inability to delete a leaderboard. During testing, I created a dummy table to run some experiments only to realize later on that I can’t delete that table. Meaning I’ve basically wasted 1/25 free leaderboards haha. I understand that in the backend, deleting a database table is quite a headache but from what I can tell, users have been complaining about not having this feature since 2016! Ouch!
As of time of writing, I am still just a hobbyist publishing small games for experience. With that being said, the free tier is ideal for me until I’ve moved up a bit in the world XD.
Alternatives
One alternative that is often compared with PlayFab is GameSparks. If you’re in the market for a professional backend, I do strongly suggest looking at both of these. In my case, building a central web application to manage data across all my casual game releases is also an option which I am strongly considering. That’s all for this post folks (Sorry for the long chunk of code XD).