メインコンテンツまでスキップ

クイックプレイメニューを追加する - ピアツーピアでのクイックマッチ - (Unreal Engine モジュール)

Last updated on June 12, 2024

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.

Preview of Quick Play widget's Select Game Mode state Unreal Byte Wars quick match peer-to-peer

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.

Preview of Quick Play widget's Select Server Type state Unreal Byte Wars quick match peer-to-peer

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).

Preview of Quick Play widget's Success state Unreal Byte Wars quick match peer-to-peer

Loading state

This state displays a spinner and a message to show the matchmaking processes.

Preview of Quick Play widget's Loading state Unreal Byte Wars quick match peer-to-peer

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.

Preview of Quick Play widget's Error state Unreal Byte Wars quick match peer-to-peer

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.

Preview of P2P server selection widget Unreal Byte Wars quick match peer-to-peer

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.

  1. 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;
  2. Open the MatchmakingP2PWidget_Starter CPP file and define the StartMatchmaking() function. Later, this function will trigger to start the matchmaking, but for now, add the dummy function below. The W_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)
    }
  3. 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)
    }
  4. 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;
  5. Open the MatchmakingP2PWidget_Starter CPP file and define the OnStartMatchmakingComplete() function. This function handles the callback when the start matchmaking process completes to switch the Quick Play widget to a relevant state. The OnlineSession 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);
    }
    }
  6. 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);
    }
    }
  7. 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);
    }
    }
  8. 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.
    }
  9. 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.
    }
  10. 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 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 quick match peer-to-peer

  11. 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