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

すべてを統合する - ピアツーピアでのクイックマッチ - (Unreal Engine モジュール)

Last updated on October 23, 2024

The goal of the matchmaking UI is to show the exact state of matchmaking, so the widget has many high-level states. To understand when each state should show up, refer to this diagram:

Connect the UI to start, cancel, and display the matchmaking status

  1. Open the MatchmakingP2PWidget_Starter CPP file and replace the StartMatchmaking() function using the code below to trigger starting matchmaking. The OnlineSession variable is a reference to the online session you created earlier, which is the MatchmakingP2POnlineSession_Starter class.

    void UMatchmakingP2PWidget_Starter::StartMatchmaking()
    {
    if (OnlineSession->ValidateToStartMatchmaking.IsBound() &&
    !OnlineSession->ValidateToStartMatchmaking.Execute(SelectedGameModeType))
    {
    return;
    }

    // Reset stored invite
    SessionInvite = nullptr;

    // Reset auto join session countdown.
    AutoJoinCurrentCountdown = AutoJoinDelay;
    MatchFoundCurrentCountdown = MatchFoundDelay;
    SessionJoinedCurrentCountdown = SessionJoinedDelay;
    Tb_WaitingForPlayersCountdown->SetText(FText::FromString(FString::FromInt(AutoJoinCurrentCountdown)));

    ChangeWidgetState(EWidgetState::REQUEST_SENT);

    OnlineSession->StartMatchmaking(
    GetOwningPlayer(),
    OnlineSession->GetPredefinedSessionNameFromType(EAccelByteV2SessionType::GameSession),
    EGameModeNetworkType::P2P,
    SelectedGameModeType);
    }
  2. Replace the JoinSession() function using the following code to trigger the join session to the invite that the game received when the matchmaking completed.

    void UMatchmakingP2PWidget_Starter::JoinSession()
    {
    if (!SessionInvite)
    {
    ChangeWidgetState(EWidgetState::ERROR);
    Tb_ErrorText->SetText(TEXT_FAILED_SESSION_INVITE_INVALID);
    }

    ChangeWidgetState(EWidgetState::JOINING_MATCH);

    OnlineSession->JoinSession(
    OnlineSession->GetLocalUserNumFromPlayerController(GetOwningPlayer()),
    OnlineSession->GetPredefinedSessionNameFromType(EAccelByteV2SessionType::GameSession),
    SessionInvite->Session);
    }
  3. Replace the CancelMatchmaking() function using the following code to trigger the canceling matchmaking:

    void UMatchmakingP2PWidget_Starter::CancelMatchmaking()
    {
    ChangeWidgetState(EWidgetState::CANCELING_MATCH);

    OnlineSession->CancelMatchmaking(
    GetOwningPlayer(),
    OnlineSession->GetPredefinedSessionNameFromType(EAccelByteV2SessionType::GameSession));
    }
  4. Replace the RejectSessionInvite() function using the following code to trigger the reject match session invite:

    void UMatchmakingP2PWidget_Starter::RejectSessionInvite()
    {
    if (!SessionInvite)
    {
    ChangeWidgetState(EWidgetState::ERROR);
    Tb_ErrorText->SetText(TEXT_FAILED_SESSION_INVITE_INVALID);
    }

    ChangeWidgetState(EWidgetState::REJECTING_MATCH);

    OnlineSession->RejectSessionInvite(
    OnlineSession->GetLocalUserNumFromPlayerController(GetOwningPlayer()),
    *SessionInvite.Get());
    }
  5. Replace the NativeTick() function using the following code to trigger the join session once the auto join countdown hits zero.

    void UMatchmakingP2PWidget_Starter::NativeTick(const FGeometry& MyGeometry, float InDeltaTime)
    {
    Super::NativeTick(MyGeometry, InDeltaTime);

    MoveCameraToTargetLocation(InDeltaTime, FVector(60.0f, 800.0f, 160.0f));

    // Manual "Auto" Join
    if (WidgetState == EWidgetState::WAITING_FOR_PLAYER && AutoJoinCurrentCountdown > 0)
    {
    AutoJoinCurrentCountdown -= InDeltaTime;
    Tb_WaitingForPlayersCountdown->SetText(FText::FromString(FString::FromInt(AutoJoinCurrentCountdown)));

    if (AutoJoinCurrentCountdown <= 0)
    {
    JoinSession();
    }
    }

    // Match found delay
    if (WidgetState == EWidgetState::MATCH_FOUND && MatchFoundCurrentCountdown > 0)
    {
    MatchFoundCurrentCountdown -= InDeltaTime;
    if (MatchFoundCurrentCountdown <= 0 && SessionInvite)
    {
    // Check if auto join is enabled or not
    const TSharedPtr<FOnlineSessionInfoAccelByteV2> SessionInfo = StaticCastSharedPtr<FOnlineSessionInfoAccelByteV2>(
    SessionInvite->Session.Session.SessionInfo);
    check(SessionInfo.IsValid());
    const bool bAutoJoin = SessionInfo->GetBackendSessionData()->Configuration.AutoJoin;

    ChangeWidgetState(bAutoJoin ? EWidgetState::JOINING_MATCH : EWidgetState::WAITING_FOR_PLAYER);
    }
    }

    // Session joined delay
    if (WidgetState == EWidgetState::SESSION_JOINED && SessionJoinedCurrentCountdown > 0)
    {
    SessionJoinedCurrentCountdown -= InDeltaTime;
    if (SessionJoinedCurrentCountdown <= 0)
    {
    ChangeWidgetState(EWidgetState::REQUESTING_SERVER);
    }
    }
    }
  6. Bind the callback functions to show the relevant user interface when certain matchmaking events occur. This function is also responsible for triggering the StartMatchmaking() immediately. To do this, replace the NativeOnActivated() function with the following code:

    void UMatchmakingP2PWidget_Starter::NativeOnActivated()
    {
    Super::NativeOnActivated();

    UOnlineSession* BaseOnlineSession = GetWorld()->GetGameInstance()->GetOnlineSession();
    if (!ensure(BaseOnlineSession))
    {
    return;
    }

    OnlineSession = Cast<UAccelByteWarsOnlineSessionBase>(BaseOnlineSession);
    ensure(OnlineSession);

    // Get selected game mode type from the previous widget
    UAccelByteWarsBaseUI* BaseUIWidget = Cast<UAccelByteWarsGameInstance>(GetGameInstance())->GetBaseUIWidget();
    for (const UCommonActivatableWidget* Widget : BaseUIWidget->Stacks[EBaseUIStackType::Menu]->GetWidgetList())
    {
    if (const UQuickPlayWidget* QuickPlayWidget = Cast<UQuickPlayWidget>(Widget))
    {
    SelectedGameModeType = QuickPlayWidget->GetSelectedGameModeType();
    }
    }

    Btn_Join->OnClicked().AddUObject(this, &ThisClass::JoinSession);
    Btn_Cancel->OnClicked().AddUObject(this, &ThisClass::CancelMatchmaking);
    Btn_Reject->OnClicked().AddUObject(this, &ThisClass::RejectSessionInvite);
    Btn_Retry->OnClicked().AddUObject(this, &ThisClass::StartMatchmaking);

    OnlineSession->GetOnStartMatchmakingCompleteDelegates()->AddUObject(this, &ThisClass::OnStartMatchmakingComplete);
    OnlineSession->GetOnMatchmakingCompleteDelegates()->AddUObject(this, &ThisClass::OnMatchmakingComplete);
    OnlineSession->GetOnSessionInviteReceivedDelegates()->AddUObject(this, &ThisClass::OnSessionInviteReceived);
    OnlineSession->GetOnJoinSessionCompleteDelegates()->AddUObject(this, &ThisClass::OnJoinSessionComplete);
    OnlineSession->GetOnSessionServerUpdateReceivedDelegates()->AddUObject(this, &ThisClass::OnSessionServerUpdateReceived);

    OnlineSession->GetOnCancelMatchmakingCompleteDelegates()->AddUObject(this, &ThisClass::OnCancelMatchmakingComplete);
    OnlineSession->GetOnRejectSessionInviteCompleteDelegate()->AddUObject(this, &ThisClass::OnRejectSessionInviteComplete);

    // Start matchmaking immediately
    StartMatchmaking();
    }
  7. Unbind those callbacks when the widget is not active. Replace the NativeOnDeactivated() with the following code:

    void UMatchmakingP2PWidget_Starter::NativeOnDeactivated()
    {
    Btn_Join->OnClicked().RemoveAll(this);
    Btn_Cancel->OnClicked().RemoveAll(this);
    Btn_Reject->OnClicked().RemoveAll(this);
    Btn_Retry->OnClicked().RemoveAll(this);

    OnlineSession->GetOnStartMatchmakingCompleteDelegates()->RemoveAll(this);
    OnlineSession->GetOnMatchmakingCompleteDelegates()->RemoveAll(this);
    OnlineSession->GetOnSessionInviteReceivedDelegates()->RemoveAll(this);
    OnlineSession->GetOnJoinSessionCompleteDelegates()->RemoveAll(this);
    OnlineSession->GetOnSessionServerUpdateReceivedDelegates()->RemoveAll(this);

    OnlineSession->GetOnCancelMatchmakingCompleteDelegates()->RemoveAll(this);
    OnlineSession->GetOnRejectSessionInviteCompleteDelegate()->RemoveAll(this);

    Super::NativeOnDeactivated();}
  8. There are several buttons you need to bind to let the player leave the game session. Those buttons are the leave button in the Match Lobby and the quit buttons in the Pause and Game Over widget. To do this, we can assign a delegate to leave the session. Open the MatchmakingP2POnlineSession_Starter CPP file and add the following code to the RegisterOnlineDelegates() function:

    void UMatchmakingP2POnlineSession_Starter::RegisterOnlineDelegates()
    {
    // ...
    const TDelegate<void(APlayerController*)> LeaveSessionDelegate = TDelegate<void(APlayerController*)>::CreateWeakLambda(
    this, [this](APlayerController*)
    {
    LeaveSession(GetPredefinedSessionNameFromType(EAccelByteV2SessionType::GameSession));
    });
    UPauseWidget::OnQuitGameDelegate.Add(LeaveSessionDelegate);
    UMatchLobbyWidget::OnQuitLobbyDelegate.Add(LeaveSessionDelegate);
    UGameOverWidget::OnQuitGameDelegate.Add(LeaveSessionDelegate);
    // ...
    }
  9. When the online session is deinitialized, you need to unbind to stop listening to the event. You can do this by adding the following code in the ClearOnlineDelegates() function:

    void UMatchmakingP2POnlineSession_Starter::ClearOnlineDelegates()
    {
    // ...
    UPauseWidget::OnQuitGameDelegate.RemoveAll(this);
    UMatchLobbyWidget::OnQuitLobbyDelegate.RemoveAll(this);
    UGameOverWidget::OnQuitGameDelegate.RemoveAll(this);
    // ...
    }

Resources