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

クイックプレイメニューを追加する - 専用サーバーでのクイックマッチ - (Unreal Engine モジュール)

Last updated on June 12, 2024

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.

Preview of Quick Play widget's Select Game Mode state Unreal Byte Wars quick match dedicated server

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:

Preview of Quick Play widget's Select Server Type state Unreal Byte Wars quick match dedicated server

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.

Preview of Quick Play widget's Success state Unreal Byte Wars quick match dedicated server

Loading state

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

Preview of Quick Play widget's Loading state Unreal Byte Wars quick match dedicated server

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.

Preview of Quick Play widget's Error state Unreal Byte Wars quick match dedicated server

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.

Preview of dedicated server selection widget Unreal Byte Wars quick match dedicated server

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.

  1. 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;
  2. Open the MatchmakingDSWidget_Starter CPP file and define the StartMatchmaking() function. Later, you 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 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)
    }
  3. 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)
    }
  4. 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;
  5. Open the MatchmakingDSWidget_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 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);
    }
    }
  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 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);
    }
    }
  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 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);
    }
    }
  8. 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.
    }
  9. 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.
    }
  10. Build your project and open it in the Unreal Engine Editor. Navigate to /Content/TutorialModules/Play/MatchmakingDS/. There, you will find a data asset called DA_MatchmakingDSEssentials. Open it and enable the Is 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.

    Activate tutorial module data asset starter mode Unreal Byte Wars quick match dedicated server

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