クイックプレイメニューを追加する - ピアツーピアでのクイックマッチ - (Unreal Engine モジュール)
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, a four-player free-for-all (FFA), and Team Deathmatch, where two teams of two players compete.
The Quick Play widget is available in the Resources section and consists of the 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 for matchmaking. In this tutorial, you will spawn a button for matchmaking using peer-to-peer (P2P).
- Success: showing matchmaking success message.
- Loading: showing a spinner to show current matchmaking status (e.g., matchmaking started or finding a match).
- Error: showing the matchmaking error message.
To change between those states, the Quick Play widget uses a combination of Unreal Motion Graphics's (UMG) WidgetSwitcher
and a widget switcher called AccelByteWarsWidgetSwitcher
. The AccelByteWarsWidgetSwitcher
is a custom WidgetSwitcher
with predefined states: empty, loading, error, and success. Here are the declarations of the mentioned components in the Header file:
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 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.
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 the server type for matchmaking using the selected game mode. By default, this state contains an empty container. You will use this container to generate a button to trigger matchmaking using P2P.
Success state
This state will only display a message that the matchmaking is complete. When the matchmaking completes, your game will immediately travel to the match lobby of the P2P server (also known as the host or listen server).
Loading state
This state displays a spinner and a message to show the matchmaking processes.
To set the loading message text, the Quick Play widget has the function below. The function will replace the message text and toggle to show 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. The function will replace the message text and toggle 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 P2P server selection UI
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 P2P. To do this, you will be working with the MatchmakingP2PWidget_Starter
class that is available in the Resources section and consists of the following files:
- Header file:
/Source/AccelByteWars/TutorialModules/Play/MatchmakingP2P/UI/MatchmakingP2PWidget_Starter.h
- CPP file:
/Source/AccelByteWars/TutorialModules/Play/MatchmakingP2P/UI/MatchmakingP2PWidget_Starter.cpp
- Blueprint widget:
/Content/TutorialModules/Play/MatchmakingP2P/UI/W_MatchmakingP2P.uasset
If you open the widget's Blueprint file, you will see how the widget is constructed.
As you can see, it is a button that you can use to trigger the start of matchmaking using P2P. You can check the definition of that button in the Header file.
UPROPERTY(BlueprintReadOnly, meta = (BindWidget, BlueprintProtected = true, AllowPrivateAccess = true))
UCommonButtonBase* Btn_StartMatchmakingP2P;
Ready the UI
In this section, you are going to prepare the MatchmakingP2PWidget_Starter
widget class so it is displayed in the Quick Play widget.
Declare some functions to be called to trigger matchmaking events. Open the
MatchmakingP2PWidget_Starter
Header file and add the following code:protected:
void StartMatchmaking() const;
void CancelMatchmaking() const;Open the
MatchmakingP2PWidget_Starter
CPP file and define theStartMatchmaking()
function. Later, this function 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 UMatchmakingP2PWidget_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 peer-to-peer (P2P)
}Define the
CancelMatchmaking()
function. Later, this function will trigger to cancel the matchmaking, but for now, add the following dummy function:void UMatchmakingP2PWidget_Starter::CancelMatchmaking() const
{
// Dummy cancel matchmaking and back to the server selection.
W_Parent->SwitchContent(UQuickPlayWidget::EContentType::SELECTSERVERTYPE);
// TODO: Cancel matchmaking using peer-to-peer (P2P)
}Back to the
MatchmakingP2PWidget_Starter
Header file. Declare the functions below that 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
MatchmakingP2PWidget_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 about online sessions will be covered later.void UMatchmakingP2PWidget_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 UMatchmakingP2PWidget_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 UMatchmakingP2PWidget_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 P2P button and the retry button to start matchmaking. It also binds the cancel button to cancel the matchmaking process.void UMatchmakingP2PWidget_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_StartMatchmakingP2P->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 UMatchmakingP2PWidget_Starter::NativeOnDeactivated()
{
Super::NativeOnDeactivated();
// Unbind buttons.
Btn_StartMatchmakingP2P->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. In the Editor, go to
/Content/TutorialModules/Play/MatchmakingP2P/
. There, you will find a data asset called DA_MatchmakingP2PEssentials. Open it and enable theIs Starter Mode Active
. Then, save the data asset. 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 > P2P. You will 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/Play/TutorialModules/MatchmakingEssentials/UI/QuickPlayWidget.h
- AccelByteWars/Source/AccelByteWars/Play/TutorialModules/MatchmakingEssentials/UI/QuickPlayWidget.cpp
- AccelByteWars/Content/TutorialModules/Play/MatchmakingP2P/UI/W_MatchmakingP2P.uasset
- AccelByteWars/Source/AccelByteWars/TutorialModules/Play/MatchmakingP2P/UI/MatchmakingP2PWidget_Starter.h
- AccelByteWars/Source/AccelByteWars/TutorialModules/Play/MatchmakingP2P/UI/MatchmakingP2PWidget_Starter.cpp