毎週のリーダーボードメニューを追加する - 毎週のリーダーボード - (Unreal Engine モジュール)
What's on the menu
In this tutorial, you will learn how to prepare widgets that you will use to display weekly leaderboards. The widgets are available in the Resources section and consist of the following:
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. This is the same class you used in All time leaderboard.- 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
- Header file:
W_LeaderboardPeriod
: A Blueprint widget to display buttons to select the leaderboard time period. This is the same widget you used in All time leaderboard.- Blueprint widget:
/Content/TutorialModules/Engagement/LeaderboardEssentials/UI/W_LeaderboardPeriod.uasset
- Blueprint widget:
LeaderboardWeeklyWidget_Starter
: A C++ class you will use to display the leaderboard weekly rankings.- Header file:
/Source/AccelByteWars/TutorialModules/Engagement/PeriodicLeaderboard/UI/LeaderboardWeeklyWidget_Starter.h
- CPP file:
/Source/AccelByteWars/TutorialModules/Engagement/PeriodicLeaderboard/UI/LeaderboardWeeklyWidget_Starter.cpp
- Blueprint widget:
/Content/TutorialModules/Engagement/PeriodicLeaderboard/UI/W_LeaderboardWeekly_Starter.uasset
- Header file:
LeaderboardWidgetEntry
: A C++ class you will use to display the individual player leaderboard information, such as the player's rank and score. This is the same class you use in All time leaderboard.- 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
- Header file:
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.
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 those buttons are clicked, it will call the function below. Essentially, it will set the leaderboard type 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, you 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 display buttons to select the leaderboard time period. The time period buttons are generated dynamically when you play the game. In this widget, there are two types of leaderboard time periods: All-Time and Weekly. In this tutorial, you will implement the Weekly leaderboard period.
Weekly Leaderboard widget
The Weekly Leaderboard widget has several states representing each state of the query status: loading, empty, and not empty (showing a list of the rankings). These states are achieved by 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_LeaderboardWeekly_Starter
Blueprint widget in its loading state.
The components above are declared in the LeaderboardWeeklyWidget_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 a loading state:
// ...
Ws_Leaderboard->SetWidgetState(EAccelByteWarsWidgetSwitcherState::Loading);
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 LeaderboardWeeklyWidget_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 currently logged-in player's rank in the Weekly Leaderboard widget. This widget shows the individual player leaderboard information, such as the display name, rank, and score. Below is the preview of the W_LeaderboardEntry
Blueprint widget.
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. That has been set up 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.
Open the
LeaderboardWeeklyWidget_Starter
class Header file. Then, declare the following functions:protected:
// ...
void GetWeeklyRankings();
// ...
void GetPlayerWeeklyRanking();
// ...
void DisplayPlayerWeeklyRank(const ULeaderboardRank* PlayerRank);Open the
LeaderboardWeeklyWidget_Starter
class CPP file. Create the definition for theGetWeeklyRankings()
function. You will use this function to get and display leaderboard weekly rankings around a certain range (e.g., from rank 0 to 10). For now, just leave it empty.void ULeaderboardWeeklyWidget_Starter::GetWeeklyRankings()
{
// ...
}Still in the same file, create the definition for the
GetPlayerWeeklyRanking()
function. You will use this function to get the logged-in player's weekly rank in case the player is not included in the list retrieved by theGetWeeklyRankings()
function (e.g., the player is not included in the top 10 players). For now, just leave it empty.void ULeaderboardWeeklyWidget_Starter::GetPlayerWeeklyRanking()
{
// ...
}Create the definition for the
DisplayPlayerWeeklyRank()
function. You will use this function to display the logged-in player's weekly rank specifically on the entry below the list.void ULeaderboardWeeklyWidget_Starter::DisplayPlayerWeeklyRank(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);
}In the
NativeOnActivated()
function, add the code below. This code clears the leaderboard entry list panel and shows the empty state.void ULeaderboardWeeklyWidget_Starter::NativeOnActivated()
{
// ...
// Reset widgets.
PlayerRankPanel->SetVisibility(ESlateVisibility::Collapsed);
Lv_Leaderboard->ClearListItems();
Ws_Leaderboard->SetWidgetState(EAccelByteWarsWidgetSwitcherState::Loading);
// ...
}Build your project and open it in the Unreal Engine Editor. In the Editor, go to
/Content/TutorialModules/Engagement/PeriodicLeaderboard/
. You will find a data asset calledDA_PeriodicLeaderboard
. Open it and enable theIs Starter Mode Active
. Then, save the data asset again. This will activate the widgets so you can navigate through them when you play the game.Play the game in the Editor, log in, and you will be able to navigate to Leaderboard > Single Player > Weekly if your implementation was successful.
Resources
- The files used in this tutorial section are available in the Unreal Byte Wars GitHub repository.
- AccelByteWars/Content/TutorialModules/Engagement/PeriodicLeaderboard/DA_PeriodicLeaderboard.uasset
- AccelByteWars/Content/TutorialModules/Engagement/LeaderboardEssentials/UI/W_Leaderboards.uasset
- AccelByteWars/Source/AccelByteWars/TutorialModules/Engagement/LeaderboardEssentials/UI/LeaderboardsWidget.h
- AccelByteWars/Source/AccelByteWars/TutorialModules/Engagement/LeaderboardEssentials/UI/LeaderboardsWidget.cpp
- AccelByteWars/Content/TutorialModules/Engagement/LeaderboardEssentials/UI/W_LeaderboardPeriod.uasset
- AccelByteWars/Content/TutorialModules/Engagement/PeriodicLeaderboard/UI/W_LeaderboardWeekly_Starter.uasset
- AccelByteWars/Source/AccelByteWars/TutorialModules/Engagement/PeriodicLeaderboard/UI/LeaderboardWeeklyWidget_Starter.h
- AccelByteWars/Source/AccelByteWars/TutorialModules/Engagement/PeriodicLeaderboard/UI/LeaderboardWeeklyWidget_Starter.cpp
- AccelByteWars/Content/TutorialModules/Engagement/LeaderboardEssentials/UI/W_LeaderboardEntry.uasset
- AccelByteWars/Source/AccelByteWars/TutorialModules/Engagement/LeaderboardEssentials/UI/LeaderboardWidgetEntry.h
- AccelByteWars/Source/AccelByteWars/TutorialModules/Engagement/LeaderboardEssentials/UI/LeaderboardWidgetEntry.cpp