Evelyn GameDev Logo
Published on

Add Ranking Function to Unity Games by using PlayFab. This is for free leaderboard!!

Authors
  • avatar
    Evelyn
Add Ranking Function to Unity Games by using PlayFab. This is for free leaderboard!!

Please share this article if you like!

Hello! Welcome to Evelyn GameDev Blog.

In this article, we'll use PlayFab to implement the ranking function.

The following functions need to be implemented It's a lot of work, but let's do it together.

  • Login
  • User name update
  • Send score
  • Get your rank
  • Get the top 10 rankings
PlayFab ranking view

It is also explained in a youtube video, so please check the video if you have trouble understanding the text information alone.


Table of Contents

Import PlayFab SDK to Unity Project

First, let's import the SDK into your Unity project.

PlayFab SDK Download Link

PlayFab website

And then, drag and drop two SDK files to your project.

PlayFab ranking view

Setup PlayFab dashboard

First, login to your PlayFab in the Unity project.

If you don't have an account, please create one. You can create one right away.

login to PlayFab in Unity Editor

There is an icon to the right of the PlayFab logo, click on it to go to the PlayFab website.

Log in to PlayFab's website as well.

login to PlayFab in Unity website

Create a new Title after logging in.

create a new title

The title creation screen is omitted.

After creating the title, go to the title setting screen and display the API Feature tab.

Then, enable the following two items and save the changes.

  • Allow client to post player statistics
  • Allow client to view ban reason duration
api feature setting

Go back to UnityEditor and select Studio ID and Title ID.

If you don't see them, try refreshing.

Studio is and title id

Login and Username function

Next, let's create the login function.

Then create three new C Sharp scripts for login and write the following code.

GameStatic.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class GameStatic
{
    public static bool IsLogined = false;
    public static string Username = "";
    public static readonly string LEADERBOARD_NAME = "HighScore";
}

Login.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using PlayFab;
using PlayFab.ClientModels;

public class Login : MonoBehaviour
{
    public Text StatusText;
    public Username Username;

    private bool isLoading = false;
    private bool shouldCreateNewAccount = false;
    private string customId = "";

    const string CUSTOM_ID_KEY = "CUSTOM_ID_KEY";

    private void Awake()
    {
        Auth();
    }

    public void Auth()
    {
        customId = PlayerPrefs.GetString(CUSTOM_ID_KEY);

        if (GameStatic.IsLogined)
        {
            StatusText.text = $"already logined as : {customId}";
            return;
        }

        if (isLoading) return;
        isLoading = true;
        StatusText.text = "now loading ...";

        shouldCreateNewAccount = string.IsNullOrEmpty(customId);
        if (shouldCreateNewAccount)
        {
            customId = System.Guid.NewGuid().ToString();
        }

        var req = new LoginWithCustomIDRequest { CustomId = customId, CreateAccount = shouldCreateNewAccount };
        PlayFabClientAPI.LoginWithCustomID(req, OnSuccess, OnFailure);
    }

    public void UseNewUser()
    {
        GameStatic.IsLogined = false;
        PlayerPrefs.DeleteAll();
        Auth();
        Username.DeleteUsername();
    }

    private void OnSuccess(LoginResult res)
    {
        isLoading = false;
        if (shouldCreateNewAccount && !res.NewlyCreated)
        {
            StatusText.text = "try again";
            Auth();
            return;
        }

        if (res.NewlyCreated)
        {
            PlayerPrefs.SetString(CUSTOM_ID_KEY, customId);
            PlayerPrefs.Save();
        }

        StatusText.text = $"customId: {customId}";
        GameStatic.IsLogined = true;
    }

    private void OnFailure(PlayFabError err)
    {
        isLoading = false;
        StatusText.text = $"{err.GenerateErrorReport()}";
    }
}

Username.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using PlayFab;
using PlayFab.ClientModels;

public class Username : MonoBehaviour
{
    public InputField Input;
    public GameObject SubmitButton;

    private bool isLoading = false;

    const string USER_NAME_KEY = "USER_NAME_KEY";

    private void Awake()
    {
        GameStatic.Username = PlayerPrefs.GetString(USER_NAME_KEY);
    }

    void Start()
    {
        Input.text = string.IsNullOrEmpty(GameStatic.Username) ? "no Name" : GameStatic.Username;
    }

    public void Validate()
    {
        bool validateError = false;
        string thisText = Input.text;

        if (thisText.Length == 0 || thisText.Length < 3 || thisText.Length > 25 || thisText == GameStatic.Username || string.IsNullOrWhiteSpace(thisText))
        {
            validateError = true;
        }

        SubmitButton.SetActive(!validateError);
    }

    public void DeleteUsername()
    {
        GameStatic.Username = "";
        PlayerPrefs.DeleteKey(USER_NAME_KEY);
        Input.text = string.IsNullOrEmpty(GameStatic.Username) ? "no Name" : GameStatic.Username;
    }

    private void OnSuccess(UpdateUserTitleDisplayNameResult res)
    {
        PlayerPrefs.SetString(USER_NAME_KEY, res.DisplayName);
        PlayerPrefs.Save();

        GameStatic.Username = res.DisplayName;
        Input.text = res.DisplayName;
        isLoading = false;
    }

    private void OnFailure(PlayFabError err)
    {
        Input.text = err.GenerateErrorReport();
        isLoading = false;
    }

    public void UpdateUsername()
    {
        if (!GameStatic.IsLogined) return;

        if (isLoading) return;
        isLoading = true;

        var req = new UpdateUserTitleDisplayNameRequest
        {
            DisplayName = Input.text
        };

        Input.text = "Now Updateing ...";
        PlayFabClientAPI.UpdateUserTitleDisplayName(req, OnSuccess, OnFailure);
    }
}

Add Login.cs and Username.cs to the Hierarchy game object, and assign UI Text and Input Field game objects to the necessary variables.

Furthermore, assign functions to the Click Event of the button and the Value Changed Event of the Input Field.

In the following image, the UI has been simplified quite a bit, so you can create your own UI as you like.

If you are not familiar with Ui creation, please watch the youtube video to see how it is done and try creating it together.

attach login and username to scene

Scene manager

The next step is to write the script for the screen transition.

Let's create a new script.

SceneSwitcher.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

public class SceneSwitcher : MonoBehaviour
{
    public void SwitchScene(string nextScene)
    {
        SceneManager.LoadScene(nextScene);
    }
}

This is a simple screen transition, but if you want to add a loading screen to match the screen transition, please read this article.

Create three scenes and add them to the Build Setting.

three scenes

The methods for screen transitions are then tied to the UI of each screen.

Tie it to the screen

High score function

Then, we will create the script and screen for score submission.

Score.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using PlayFab;
using PlayFab.ClientModels;

public class Score : MonoBehaviour
{

    public Text HighScoreText;
    public Text ScoreText;
    public GameObject SubmitButton;

    private int highScore = 0;
    private int thisScore = 0;
    private bool isLoading = false;

    const string HIGH_SCORE_KEY = "HIGH_SCORE_KEY";

    private void Awake()
    {
        highScore = PlayerPrefs.GetInt(HIGH_SCORE_KEY);
    }

    void Start()
    {
        ScoreText.text = 0.ToString();
        HighScoreText.text = highScore.ToString();
    }

    public void UpdatePlayerStatistics()
    {
        if (!GameStatic.IsLogined) return;

        if (isLoading) return;
        isLoading = true;

        var req = new UpdatePlayerStatisticsRequest
        {
            Statistics = new List<StatisticUpdate>
            {
                new StatisticUpdate
                {
                    StatisticName = GameStatic.LEADERBOARD_NAME,
                    Value = thisScore,
                }
            }
        };

        ScoreText.text = "now sending highscore ...";
        PlayFabClientAPI.UpdatePlayerStatistics(req, OnSuccess, OnFailure);
    }

    public void ChangeThisSccore(bool increaseFlag)
    {
        if (increaseFlag)
        {
            thisScore++;
        }
        else
        {
            thisScore--;
        }

        ScoreText.text = thisScore.ToString();
        SubmitButton.SetActive(thisScore > highScore);
    }

    private void OnSuccess(UpdatePlayerStatisticsResult res)
    {
        PlayerPrefs.SetInt(HIGH_SCORE_KEY, thisScore);
        PlayerPrefs.Save();

        highScore = thisScore;
        HighScoreText.text = highScore.ToString();
        ScoreText.text = highScore.ToString();

        isLoading = false;
    }

    private void OnFailure(PlayFabError err)
    {
        ScoreText.text = err.GenerateErrorReport();
        isLoading = false;
    }
}

Then create a game screen and tie it to a script about the score.

When incorporating it into your game, use it to extract the sending part of the score.

game ui

My rank function

Next, we will work on the ranking screen.

You can use the following script to get your rank.

MyRank.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using PlayFab;
using PlayFab.ClientModels;


public class MyRank : MonoBehaviour
{

    public Text MyRankText;

    void Start()
    {
        GetMyRank();
    }

    private void GetMyRank()
    {
        if (!GameStatic.IsLogined) return;

        var req = new GetLeaderboardAroundPlayerRequest
        {
            StatisticName = GameStatic.LEADERBOARD_NAME,
            MaxResultsCount = 1,
        };

        MyRankText.text = "now getting my rank...";
        PlayFabClientAPI.GetLeaderboardAroundPlayer(req, OnSuccess, OnFailure);
    }

    private void OnSuccess(GetLeaderboardAroundPlayerResult res)
    {
        foreach (var entry in res.Leaderboard)
        {
            MyRankText.text = (entry.Position + 1).ToString();
        }
    }

    private void OnFailure(PlayFabError err)
    {
        MyRankText.text = err.GenerateErrorReport();
    }
}

Then tie the script to the UI.

my rank

Ranking function

Finally, we will create the ranking script and UI.

RankingRow.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;

public class RankingRow : MonoBehaviour
{
    public Text RankNumText;
    public Text HighScoreText;
    public Text UsernameText;

    public void UpdateRow(int rank, int highScore, string username)
    {
        RankNumText.text = (rank + 1).ToString();
        HighScoreText.text = highScore.ToString();
        UsernameText.text = string.IsNullOrEmpty(username) ? "No Name" : username;
    }
}

Ranking.cs

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using PlayFab;
using PlayFab.ClientModels;

public class Ranking : MonoBehaviour
{
    public GameObject ViewArea;
    public GameObject RowPrefab;
    public Text Headline;

    void Start()
    {
        GetLeaderBoard();
    }

    public void GetLeaderBoard()
    {
        if (!GameStatic.IsLogined) return;

        var req = new GetLeaderboardRequest
        {
            StatisticName = GameStatic.LEADERBOARD_NAME,
            StartPosition = 0,
            MaxResultsCount = 10, // max 100
        };

        Headline.text = "now getting ranking ...";
        PlayFabClientAPI.GetLeaderboard(req, OnSuccess, OnFailure);
    }

    private void OnSuccess(GetLeaderboardResult res)
    {
        foreach (Transform n in ViewArea.transform)
        {
            GameObject.Destroy(n.gameObject);
        }

        Headline.text = "Ranking";

        foreach (var entry in res.Leaderboard)
        {
            GameObject rankingChild = Instantiate(RowPrefab, ViewArea.transform.position, Quaternion.identity, ViewArea.transform);
            RankingRow thisRankingRow = rankingChild.GetComponent<RankingRow>();
            thisRankingRow.UpdateRow(entry.Position, entry.StatValue, entry.DisplayName);
        }
    }

    private void OnFailure(PlayFabError err)
    {
        Headline.text = err.GenerateErrorReport();
    }
}

After the implementation so far, the ranking is now displayed successfully.

PlayFab ranking view

Summary of this article

What did you think?

The blog post would have been too long if I went into too much detail, so I left out the detailed explanation of the UI creation and scripting.

If there is anything you don't understand, please watch the video on youtube to see the whole process.

Thank you for reading to the end.

If you liked this article, I hope you will read the other articles as well.

Please share this article if you like!