Skip to main content

Add leaderboard menu - All time leaderboard - (Unreal Engine module)

Last updated on October 24, 2024

What's on the menu

In this tutorial, you will learn how to prepare widgets that you will use to display leaderboards. The widgets are available in the Resources section and consist of the following files:

  • LeaderboardsWidget: A C++ class that displays buttons to select leaderboard types based on the Byte Wars game modes, which are Single Player, Elimination, and Team Deathmatch. You will use this class to select which leaderboard to be displayed.
    • Header file: /Source/AccelByteWars/TutorialModules/Engagement/LeaderboardEssentials/UI/LeaderboardsWidget.h
    • CPP file: /Source/AccelByteWars/TutorialModules/Engagement/LeaderboardEssentials/UI/LeaderboardsWidget.cpp
    • Blueprint widget: /Content/TutorialModules/Engagement/LeaderboardEssentials/UI/W_Leaderboards.uasset
  • W_LeaderboardPeriod: A widget Blueprint to display buttons and select the leaderboard time period.
    • Blueprint widget: /Content/TutorialModules/Engagement/LeaderboardEssentials/UI/W_LeaderboardPeriod.uasset
  • LeaderboardAllTimeWidget_Starter: A C++ class you will use to display the leaderboard rankings.
    • Header file: /Source/AccelByteWars/TutorialModules/Engagement/LeaderboardEssentials/UI/LeaderboardAllTimeWidget_Starter.h
    • CPP file: /Source/AccelByteWars/TutorialModules/Engagement/LeaderboardEssentials/UI/LeaderboardAllTimeWidget_Starter.cpp
    • Blueprint widget: /Content/TutorialModules/Engagement/LeaderboardEssentials/UI/W_LeaderboardAllTime_Starter.uasset
  • LeaderboardWidgetEntry: A C++ class you will use to display individual player leaderboard information, such as the player's rank and score.
    • Header file: /Source/AccelByteWars/TutorialModules/Engagement/LeaderboardEssentials/UI/LeaderboardWidgetEntry.h
    • CPP file: /Source/AccelByteWars/TutorialModules/Engagement/LeaderboardEssentials/UI/LeaderboardWidgetEntry.cpp
    • Blueprint widget: /Content/TutorialModules/Engagement/LeaderboardEssentials/UI/W_LeaderboardEntry.uasset

Take a look at more details on how these widgets are constructed.

Leaderboards widget

Below is the preview of the W_Leaderboards Blueprint widget. This widget display buttons to select leaderboard types based on the Byte Wars game modes, which are Single Player, Elimination, and Team Deathmatch.

Leaderboards widget Unreal Byte Wars all time leaderboard

The buttons above are declared in the LeaderboardsWidget class Header file.

protected:
// ...
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional, BlueprintProtected = true, AllowPrivateAccess = true))
UCommonButtonBase* Btn_SinglePlayer;

UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional, BlueprintProtected = true, AllowPrivateAccess = true))
UCommonButtonBase* Btn_Elimination;

UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional, BlueprintProtected = true, AllowPrivateAccess = true))
UCommonButtonBase* Btn_TeamDeathmatch;

When the buttons are clicked, it will call the function below. Essentially, the function will set the leaderboard types based on the game mode and then display the W_LeaderboardPeriod widget to select the leaderboard time period.

void ULeaderboardsWidget::OpenLeaderboardsPeriod(const FString InGameMode)
{
LeaderboardGameMode = InGameMode;

UAccelByteWarsGameInstance* GameInstance = StaticCast<UAccelByteWarsGameInstance*>(GetWorld()->GetGameInstance());
ensure(GameInstance);

UAccelByteWarsBaseUI* BaseUIWidget = GameInstance->GetBaseUIWidget();
ensure(BaseUIWidget);

BaseUIWidget->PushWidgetToStack(EBaseUIStackType::Menu, LeaderboardsPeriodWidgetClass);
}

To get the selected game mode, we will use the following helper function:

public:
static FString GetLeaderboardGameMode()
{
return LeaderboardGameMode;
}

Leaderboard Period widget

Below is the preview of the W_LeaderboardPeriod Blueprint widget. This widget displays buttons to select the leaderboard time period. The time period buttons are generated dynamically when you play the game, so you won't see any button on the editor. There are two types of leaderboard time periods: All-Time and Cycle. In this tutorial, we will implement the All-Time leaderboard period.

Leaderboard period widget Unreal Byte Wars all time leaderboard

All-Time Leaderboard widget

The All-Time Leaderboard widget has several states representing each state of the query status: loading, empty, and not empty (showing a list of rankings). These states are achieved using a custom Widget Switcher: UAccelByteWarsWidgetSwitcher. The list itself is done by using a List View that takes an entry widget class and generates the entry dynamically. This widget also contains one entry below the list view to display the current logged-in player's rank. Below is the preview of the W_LeaderboardAllTime_Starter Blueprint widget in its loading state.

All-time leaderboard widget Unreal Byte Wars all time leaderboard

The components above are declared in the LeaderboardAllTimeWidget_Starter class Header file.

protected:
// ...
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional, BlueprintProtected = true, AllowPrivateAccess = true))
UAccelByteWarsWidgetSwitcher* Ws_Leaderboard;

UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional, BlueprintProtected = true, AllowPrivateAccess = true))
UListView* Lv_Leaderboard;

UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional, BlueprintProtected = true, AllowPrivateAccess = true))
ULeaderboardWidgetEntry* PlayerRankPanel;

Changing the state of this widget is done by calling Ws_Leaderboard->SetWidgetState(). Here's an example on how to change the state to an empty state:

// ...
Ws_Leaderboard->SetWidgetState(EAccelByteWarsWidgetSwitcherState::Empty);

Since the leaderboard ranks all of your players, you probably want to limit the leaderboard rank to be displayed. The default limit to be displayed is 10, but you can modify it in the LeaderboardAllTimeWidget_Starter class Header file.

protected:
// ...
UPROPERTY(EditDefaultsOnly, BlueprintReadOnly)
int32 ResultLimit = 10;

Leaderboard Entry widget

This is used as the entry widget for the list and the current logged-in player's rank in the All-Time Leaderboard widget. This widget shows individual player leaderboard information, such as their display name, rank, and score. Below is the preview of the W_LeaderboardEntry Blueprint widget.

Leaderboard entry widget Unreal Byte Wars all time leaderboard

The components above are declared in the LeaderboardWidgetEntry class Header file.

protected:
// ...
UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional, BlueprintProtected = true, AllowPrivateAccess = true))
UTextBlock* Tb_Rank;

UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional, BlueprintProtected = true, AllowPrivateAccess = true))
UTextBlock* Tb_DisplayName;

UPROPERTY(BlueprintReadOnly, meta = (BindWidgetOptional, BlueprintProtected = true, AllowPrivateAccess = true))
UTextBlock* Tb_Score;

The List View requires the entry widget to implement the IUserObjectListEntry interface. If you look at the parent of this widget, UAccelByteWarsWidgetEntry, you can see that it has the IUserObjectListEntry implemented. For the widget to work properly as an entry widget, it needs to implement the NativeOnListItemObjectSet. This function is the setup function. This is where all the user interface (UI) setup needs to be done. This has been done for you, so you can simply use it for any List View or call the NativeOnListItemObjectSet function to set it up manually.

void ULeaderboardWidgetEntry::NativeOnListItemObjectSet(UObject* ListItemObject)
{
Super::NativeOnListItemObjectSet(ListItemObject);

const ULeaderboardRank* LeaderboardRank = Cast<ULeaderboardRank>(ListItemObject);
if (!LeaderboardRank)
{
return;
}

const bool bUnranked = LeaderboardRank->Rank <= 0;

// Display the player's rank. If the player is not ranked, display it as #?.
Tb_Rank->SetText(bUnranked ? FText::FromString(TEXT("?")) : FText::AsNumber(LeaderboardRank->Rank));

// Display the player's display name.
Tb_DisplayName->SetText(FText::FromString(LeaderboardRank->DisplayName));

// Display the player's score. If the player is not ranked, display it as empty.
Tb_Score->SetText(bUnranked ? FText::FromString(TEXT("")) : FText::AsNumber(LeaderboardRank->Score));
}

Ready the UI

In this section, you will learn how to prepare the widgets.

  1. Open the LeaderboardAllTimeWidget_Starter class Header file. Then, declare the following functions:

    protected:
    // ...
    void GetRankings();
    // ...
    void GetPlayerRanking();
    // ...
    void DisplayPlayerRank(const ULeaderboardRank* PlayerRank);
  2. Open the LeaderboardAllTimeWidget_Starter class CPP file. Create the definition for the GetRankings() function. You will use this function to get and display leaderboard rankings around a certain range (e.g., from rank 0 to 10). For now, just leave it empty.

    void ULeaderboardAllTimeWidget_Starter::GetRankings()
    {
    // ...
    }
  3. Still in the same file, create the definition for the GetPlayerRanking() function. You will use this function to get the logged-in player's rank in case the player is not included in the list retrieved by the GetRankings() function (e.g., the player is not included in the top 10 players). For now, just leave it empty.

    void ULeaderboardAllTimeWidget_Starter::GetPlayerRanking()
    {
    // ...
    }
  4. Create the definition for the DisplayPlayerRank() function. You will use this function to display the logged-in player's rank specifically on the one entry below the list.

    void ULeaderboardAllTimeWidget_Starter::DisplayPlayerRank(const ULeaderboardRank* PlayerRank)
    {
    // Display player rank information.
    const bool bIsRanked = (PlayerRank && PlayerRank->Rank > 0);
    ULeaderboardRank* PlayerRankToDisplay = NewObject<ULeaderboardRank>();
    PlayerRankToDisplay->Init(
    bIsRanked ? PlayerRank->UserId : nullptr,
    bIsRanked ? PlayerRank->Rank : -1,
    bIsRanked ? RANKED_MESSAGE.ToString() : UNRANKED_MESSAGE.ToString(),
    bIsRanked ? PlayerRank->Score : -1);

    PlayerRankPanel->SetLeaderboardRank(PlayerRankToDisplay);
    PlayerRankPanel->SetVisibility(ESlateVisibility::HitTestInvisible);
    }
  5. In the NativeOnActivated() function, add the code below. This function calls the GetPlayerRanking() function when the W_LeaderboardAllTime_Starter is displayed.

    void ULeaderboardAllTimeWidget_Starter::NativeOnActivated()
    {
    // ...
    Super::NativeOnActivated();

    // Reset widgets.
    PlayerRankPanel->SetVisibility(ESlateVisibility::Collapsed);
    Ws_Leaderboard->SetWidgetState(EAccelByteWarsWidgetSwitcherState::Empty);
    Lv_Leaderboard->ClearListItems();

    // Get leaderboard rankings.
    GetRankings();
    }
  6. Build your project and open it in the Unreal Engine Editor. In the Editor, go to /Content/TutorialModules/Engagement/LeaderboardEssentials/. You will find a data asset called DA_LeaderboardEssentials. Open it and enable the Is Starter Mode Active. Then, save the data asset. This will activate the widgets so you can navigate through them when you play the game.

    Activate Tutorial Module Data Asset starter mode Unreal Byte Wars

  7. Play the game in the Editor, log in, and you will be able to navigate to Leaderboard > Single Player > All time if the implementation was successful.

Resources