クイックプレイメニューを追加する - 専用サーバーでのクイックマッチ - (Unreal Engine モジュール)
To support both server modes (peer-to-peer (P2P) and dedicated server (DS)) at once, the menu widget and the widget that actually connects to the matchmaking services that will be shown inside the menu widget are separated. Those widgets are the Quick Play widget and Matchmaking DS widget. The widget that you're going to prepare is Matchmaking DS, but this tutorial will also explain what the Quick Play widget does.
About the Quick Play UI
In the Byte Wars project, Quick Play is a widget to play the game by using matchmaking. In this widget, there are two types of game modes to select: Elimination and Team Deathmatch. Elimination is a four-player free-for-all (FFA), while Team Deathmatch consists of two competing teams of two players.
The Quick Play widget is available in the Resources section and consists of following files:
- Header file:
/Source/AccelByteWars/TutorialModules/Play/MatchmakingEssentials/UI/QuickPlayWidget.h
- CPP file:
/Source/AccelByteWars/TutorialModules/Play/MatchmakingEssentials/UI/QuickPlayWidget.cpp
- Blueprint widget:
/Content/TutorialModules/Play/MatchmakingEssentials/UI/W_QuickPlay.uasset
This widget has different states to show the relevant user interface (UI) based on the matchmaking state. The states are:
- Select Game Mode: showing buttons to select a game mode.
- Select Server Type: showing buttons to select what type of server to use for matchmaking. In this module, you will spawn a button for matchmaking using a dedicated server.
- Success: showing a matchmaking success message.
- Loading: showing a spinner to show the current matchmaking status (e.g., matchmaking started, finding a match).
- Error: showing a matchmaking error message.
To change between those states, the Quick Play widget uses a combination of Unreal Motion Graphics's Widget Switcher and a Widget Switcher called AccelByteWarsWidgetSwitcher
. AccelByteWarsWidgetSwitcher
is a custom Widget Switcher with predefined states: empty, loading, error, and success. Here are the declarations of the mentioned components in the Header file:
private:
UPROPERTY(BlueprintReadOnly, meta = (BindWidget, BlueprintProtected = true, AllowPrivateAccess = true))
UWidgetSwitcher* Ws_ContentOuter;
UPROPERTY(BlueprintReadOnly, meta = (BindWidget, BlueprintProtected = true, AllowPrivateAccess = true))
UAccelByteWarsWidgetSwitcher* Ws_Processing;
To switch between states, the Quick Play widget has the following function:
void UQuickPlayWidget::SwitchContent(const EContentType State)
{
bool bShowBackButton = true;
UWidget* FocusTarget = Btn_SelectGameMode_Back;
UWidget* WidgetTarget = W_SelectGameMode;
UWidget* BackButtonTarget = Btn_SelectGameMode_Back;
EAccelByteWarsWidgetSwitcherState ProcessingState = EAccelByteWarsWidgetSwitcherState::Loading;
switch (State)
{
case EContentType::SELECTGAMEMODE:
bShowBackButton = true;
FocusTarget = Btn_Elimination;
WidgetTarget = W_SelectGameMode;
BackButtonTarget = Btn_SelectGameMode_Back;
CameraTargetY = 600.0f;
InitializeFTEUDialogues(true);
break;
case EContentType::SELECTSERVERTYPE:
bShowBackButton = true;
FocusTarget = Btn_SelectServerType_Back;
WidgetTarget = W_SelectServerType;
BackButtonTarget = Btn_SelectServerType_Back;
CameraTargetY = 750.0f;
break;
case EContentType::LOADING:
bShowBackButton = false;
FocusTarget = Ws_Processing;
WidgetTarget = W_ProcessingOuter;
BackButtonTarget = Btn_Processing_Back;
ProcessingState = EAccelByteWarsWidgetSwitcherState::Loading;
CameraTargetY = 800.0f;
DeinitializeFTUEDialogues();
break;
case EContentType::ERROR:
bShowBackButton = true;
FocusTarget = Ws_Processing;
WidgetTarget = W_ProcessingOuter;
BackButtonTarget = Btn_Processing_Back;
ProcessingState = EAccelByteWarsWidgetSwitcherState::Error;
CameraTargetY = 800.0f;
DeinitializeFTUEDialogues();
break;
case EContentType::SUCCESS:
bShowBackButton = false;
FocusTarget = Ws_Processing;
WidgetTarget = W_ProcessingOuter;
BackButtonTarget = Btn_Processing_Back;
ProcessingState = EAccelByteWarsWidgetSwitcherState::Not_Empty;
CameraTargetY = 800.0f;
break;
}
FocusTarget->SetUserFocus(GetOwningPlayer());
Ws_ContentOuter->SetActiveWidget(WidgetTarget);
Ws_Processing->SetWidgetState(ProcessingState);
BackButtonTarget->SetVisibility(bShowBackButton ? ESlateVisibility::Visible : ESlateVisibility::Collapsed);
bIsBackHandler = bShowBackButton;
}
Now that you understand how the Quick Play states are implemented, take a look at how each state in detail.
Select Game Mode state
This state displays buttons to select the game mode before matchmaking. There are two game modes: Elimination and Team Deathmatch.
The buttons above are declared in the Header file:
private:
UPROPERTY(BlueprintReadOnly, meta = (BindWidget, BlueprintProtected = true, AllowPrivateAccess = true))
UCommonButtonBase* Btn_Elimination;
UPROPERTY(BlueprintReadOnly, meta = (BindWidget, BlueprintProtected = true, AllowPrivateAccess = true))
UCommonButtonBase* Btn_TeamDeathMatch;
The selected game mode can be accessed through the function below. It will return either EGameModeType::FFA
for Elimination or EGameModeType::TDM
for Team Deathmatch.
EGameModeType UQuickPlayWidget::GetSelectedGameModeType() const
{
return SelectedGameModeType;
}
Select Server Type state
This state displays buttons to select a server type to use matchmaking with the selected game mode. By default, this state contains an empty container. You will use this container to generate a button to trigger matchmaking with a dedicated server later:
Success state
This state displays a message indicating the matchmaking is complete. When the matchmaking completes, your game will immediately travel to the match lobby of the dedicated server.
Loading state
This state displays a spinner and a message to show the current matchmaking processes.
To set the loading message text, the Quick Play widget has the function below. It replaces the message text and toggles to enable the cancel button or not. You will use the cancel button to trigger some events later. For now, you don't need to worry about it.
void UQuickPlayWidget::SetLoadingMessage(const FText& Text, const bool bEnableCancelButton) const
{
Ws_Processing->LoadingMessage = Text;
Ws_Processing->bEnableCancelButton = bEnableCancelButton;
}
Error state
This state displays the matchmaking error messages.
To set the error message text, the Quick Play widget has the function below. It replaces the message text and toggles to show the retry button or not. You will use the retry button to trigger some events later. For now, you don't need to worry about it.
void UQuickPlayWidget::SetErrorMessage(const FText& Text, const bool bShowRetryButton) const
{
Ws_Processing->ErrorMessage = Text;
Ws_Processing->bShowRetryButtonOnError = bShowRetryButton;
}
About the dedicated server selection UI
As we mentioned before, the Quick Play widget has the server selection state. You will generate a button to be added to that state, so your player can trigger to start matchmaking using a dedicated server. To do this, you will be working with the MatchmakingDSWidget_Starter
class, which is available in the Resources section and consists of the following files:
- Header file:
/Source/AccelByteWars/TutorialModules/Play/MatchmakingDS/UI/MatchmakingDSWidget_Starter.h
- CPP file:
/Source/AccelByteWars/TutorialModules/Play/MatchmakingDS/UI/MatchmakingDSWidget_Starter.cpp
- Blueprint widget:
/Content/TutorialModules/Play/MatchmakingDS/UI/W_MatchmakingDS_Starter.uasset
If you open the widget's Blueprint file, you will see how the widget is constructed.
As you can see, it is basically a button that you can use to trigger the start of matchmaking with a dedicated server. You can check the definition of that button in the Header file.
private:
UPROPERTY(BlueprintReadOnly, meta = (BindWidget, BlueprintProtected = true, AllowPrivateAccess = true))
UCommonButtonBase* Btn_StartMatchmakingDS;
Ready the UI
In this section, you are going to prepare the MatchmakingDSWidget_Starter
widget class.
Declare some functions to be called to trigger matchmaking events. Open the
MatchmakingDSWidget_Starter
Header file and add the following code:protected:
void StartMatchmaking() const;
void CancelMatchmaking() const;Open the
MatchmakingDSWidget_Starter
CPP file and define theStartMatchmaking()
function. Later, you will trigger to start the matchmaking, but for now, add the dummy function below. TheW_Parent
variable is a reference to the parent widget, which is the Quick Play widget. This way, you can switch the Quick Play's state.void UMatchmakingDSWidget_Starter::StartMatchmaking() const
{
// Show dummy loading with cancel button.
W_Parent->SetLoadingMessage(TEXT_FINDING_MATCH, true);
W_Parent->SwitchContent(UQuickPlayWidget::EContentType::LOADING);
// TODO: Start matchmaking using a dedicated server (DS)
}Define the
CancelMatchmaking()
function. Later, you will trigger to cancel the matchmaking, but for now, add the following dummy function:void UMatchmakingDSWidget_Starter::CancelMatchmaking() const
{
// Dummy cancel matchmaking and back to the server selection.
W_Parent->SetLoadingMessage(TEXT_CANCEL_MATCHMAKING, false);
W_Parent->SwitchContent(UQuickPlayWidget::EContentType::SELECTSERVERTYPE);
// TODO: Cancel matchmaking using a dedicated server (DS)
}Back to the
MatchmakingDSWidget_Starter
Header file. Declare some additional functions. These functions will handle the callback when the matchmaking events complete.protected:
void OnStartMatchmakingComplete(FName SessionName, bool bSucceeded) const;
void OnMatchmakingComplete(FName SessionName, bool bSucceeded) const;
void OnCancelMatchmakingComplete(FName SessionName, bool bSucceeded) const;Open the
MatchmakingDSWidget_Starter
CPP file and define theOnStartMatchmakingComplete()
function. This function handles the callback when the start matchmaking process completes to switch the Quick Play widget to a relevant state. TheOnlineSession
variable is a reference to the current active online session. More information about online sessions will be covered later.void UMatchmakingDSWidget_Starter::OnStartMatchmakingComplete(FName SessionName, bool bSucceeded) const
{
// Abort if not a game session.
if (!SessionName.IsEqual(OnlineSession->GetPredefinedSessionNameFromType(EAccelByteV2SessionType::GameSession)))
{
return;
}
// Show finding match loading message if starting matchmaking is successful.
if (bSucceeded)
{
W_Parent->SetLoadingMessage(TEXT_FINDING_MATCH, true);
W_Parent->SwitchContent(UQuickPlayWidget::EContentType::LOADING);
}
// Show start matchmaking error message if starting matchmaking is failed.
else
{
W_Parent->SetErrorMessage(TEXT_FAILED_FIND_MATCH, true);
W_Parent->SwitchContent(UQuickPlayWidget::EContentType::ERROR);
}
}Define the
OnMatchmakingComplete()
function. This function handles the callback when the matchmaking process completes to switch the Quick Play widget to a relevant state.void UMatchmakingDSWidget_Starter::OnMatchmakingComplete(FName SessionName, bool bSucceeded) const
{
// Abort if not a game session.
if (!SessionName.IsEqual(OnlineSession->GetPredefinedSessionNameFromType(EAccelByteV2SessionType::GameSession)))
{
return;
}
// Show joining session if matchmaking is successful.
if (bSucceeded)
{
W_Parent->SetLoadingMessage(TEXT_JOINING_MATCH, false);
W_Parent->SwitchContent(UQuickPlayWidget::EContentType::LOADING);
}
// Show error message if matchmaking is failed.
else
{
W_Parent->SetErrorMessage(TEXT_FAILED_FIND_MATCH, true);
W_Parent->SwitchContent(UQuickPlayWidget::EContentType::ERROR);
}
}Define the
OnCancelMatchmakingComplete()
function. This function handles the callback when the cancel matchmaking process completes to switch the Quick Play widget to a relevant state.void UMatchmakingDSWidget_Starter::OnCancelMatchmakingComplete(FName SessionName, bool bSucceeded) const
{
// Abort if not a game session.
if (!SessionName.IsEqual(OnlineSession->GetPredefinedSessionNameFromType(EAccelByteV2SessionType::GameSession)))
{
return;
}
// Back to server selection if cancel matchmaking is successful.
if (bSucceeded)
{
W_Parent->SwitchContent(UQuickPlayWidget::EContentType::SELECTSERVERTYPE);
}
// Show error message if cancel matchmaking is failed.
else
{
W_Parent->SetErrorMessage(TEXT_FAILED_CANCEL_MATCH, false);
W_Parent->SwitchContent(UQuickPlayWidget::EContentType::ERROR);
}
}Bind the buttons to start and cancel the matchmaking. In the
NativeOnActivated()
function, add the code below. This code binds the dedicated server button and the retry button to start matchmaking. Also, it binds the cancel button to cancel the matchmaking process.void UMatchmakingDSWidget_Starter::NativeOnActivated()
{
Super::NativeOnActivated();
UOnlineSession* BaseOnlineSession = GetWorld()->GetGameInstance()->GetOnlineSession();
if (!ensure(BaseOnlineSession))
{
return;
}
OnlineSession = Cast<UAccelByteWarsOnlineSessionBase>(BaseOnlineSession);
ensure(OnlineSession);
W_Parent = GetFirstOccurenceOuter<UQuickPlayWidget>();
if (!ensure(W_Parent))
{
return;
}
// Bind buttons.
Btn_StartMatchmakingDS->OnClicked().AddUObject(this, &ThisClass::StartMatchmaking);
W_Parent->GetProcessingWidget()->OnCancelClicked.AddUObject(this, &ThisClass::CancelMatchmaking);
W_Parent->GetProcessingWidget()->OnRetryClicked.AddUObject(this, &ThisClass::StartMatchmaking);
// TODO: Bind events to listen to matchmaking callbacks.
}Unbind those buttons when the widget is not active. In the
NativeOnDeactivated()
add the following code:void UMatchmakingDSWidget_Starter::NativeOnDeactivated()
{
Super::NativeOnDeactivated();
// Unbind buttons.
Btn_StartMatchmakingDS->OnClicked().RemoveAll(this);
W_Parent->GetProcessingWidget()->OnCancelClicked.RemoveAll(this);
W_Parent->GetProcessingWidget()->OnRetryClicked.RemoveAll(this);
// TODO: Unbind events from listening matchmaking callbacks.
}Build your project and open it in the Unreal Engine Editor. Navigate to
/Content/TutorialModules/Play/MatchmakingDS/
. There, you will find a data asset calledDA_MatchmakingDSEssentials
. 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. From the Main Menu, navigate to Play Online > Quick Play > Elimination > Dedicated Server. You will be able to see the loading state and can cancel it to back to the server selection state if the implementation was successful.
Resources
The files used in this tutorial section are available in the Unreal Byte Wars GitHub repository.
- AccelByteWars/Content/TutorialModules/Play/MatchmakingEssentials/UI/W_QuickPlay.uasset
- AccelByteWars/Source/AccelByteWars/TutorialModules/Play/MatchmakingEssentials/UI/QuickPlayWidget.h
- AccelByteWars/Source/AccelByteWars/TutorialModules/Play/MatchmakingEssentials/UI/QuickPlayWidget.cpp
- AccelByteWars/Content/TutorialModules/Play/MatchmakingDS/UI/W_MatchmakingDS_Starter.uasset
- AccelByteWars/Source/AccelByteWars/TutorialModules/Play/MatchmakingDS/UI/MatchmakingDSWidget_Starter.h
- AccelByteWars/Source/AccelByteWars/TutorialModules/Play/MatchmakingDS/UI/MatchmakingDSWidget_Starter.cpp