65.9K
CodeProject 正在变化。 阅读更多。
Home

Azure PlayFab 上的 Unity 第 5 部分:玩家匹配以寻找游戏会话

starIconemptyStarIconemptyStarIconemptyStarIconemptyStarIcon

1.00/5 (3投票s)

2022 年 2 月 18 日

CPOL

4分钟阅读

viewsIcon

6153

在本文中,我们将 PlayFab 的匹配功能集成到游戏中,以便玩家可以自动匹配并加入同一服务器一起玩。

在本文中,我们将学习如何为 Unity 游戏项目启用玩家匹配,以便游戏客户端可以自动连接到 PlayFab 分配的服务器。

在这里,我们将使用 PlayFab 的匹配 API 并实现匹配过程所需的匹配票证流程。

让我们从 上一篇文章 继续我们的 Unity 游戏项目,并将其转换为我们的游戏可以连接和玩多人匹配的服务器代码。

要求

请确保您拥有一个 PlayFab 帐户 和以下软件来学习本教程

任务简报

PlayFab 为我们提供了许多非常复杂的多人功能,否则这些功能将难以构建和扩展。他们最好也是最 nice 的功能之一是他们的匹配 API。

匹配功能允许玩家根据您定义的任何自定义因素(例如区域、技能水平或游戏类型)查找并找到其他玩家加入游戏会话。结合 PlayFab 的自动多人服务器管理和分配,我们可以构建可扩展的多人服务器后端,并在游戏和玩家群增长时从免费层开始启动。

我们将用 PlayFab 的匹配功能替换手动游戏服务器请求功能,以使玩家能够找到彼此并加入服务器。

创建匹配队列

要开始匹配,我们首先需要在仪表板上创建一个队列。

我们打开仪表板到 **Build** > **Multiplayer**,然后选择 **Matchmaking** 选项卡。

接下来,我们单击 **New Queue** 并按如下方式填写队列选项

  • 队列名称:TestQueue
  • 最小匹配人数:2
  • 最大匹配人数:4
  • 启用服务器分配:是
  • 多人游戏服务器的构建:选择您上传的构建

此示例使用简单的区域选择规则,但我们可以从选择中添加任何我们自己的自定义规则集。在这种情况下,我们添加一个具有以下选项的规则

  • 规则名称:Region
  • 权重:1
  • 类型:Region selection rule
  • Attribute path: latencies
  • 最大延迟为:200 的匹配票证

现在我们单击 **Create queue** 来保存配置。

客户端上的匹配

我们已准备好将匹配 API 集成到游戏客户端中。

匹配过程分为三个阶段

  • 创建票证:这会在服务器上启动匹配请求并获取一个票证。
  • 等待匹配:这大约每六秒检查一次票证状态,以查看它是否找到匹配项、超时或已取消。
  • 加入匹配:如果找到匹配项,这将检索匹配服务器的详细信息以进行连接。

显然,此过程必须在游戏开始之前完成。因此,在本示例中,我们将此代码添加为登录过程的一部分。

我们在系列开头 实现 PlayFab 登录 的地方打开 `Assets/Scripts` 文件夹中的 `PlayFabCode.cs` 脚本文件,并在顶部插入另一个 using 语句

using PlayFab.MultiplayerModels;

接下来,我们将以下代码添加到类中以处理匹配过程。此请求中已为示例硬编码了延迟值,但我们也可以通过 ping PlayFab QoS 服务器 来计算延迟值。我们还必须确保队列名称与我们在创建匹配队列时使用的名称匹配。

private string matchmakingTicket = "";
private float ticketTimer = 0;
private void RequestMatchmaking()
{
    CreateMatchmakingTicketRequest requestData = new CreateMatchmakingTicketRequest();
    requestData.Creator = new MatchmakingPlayer {
        Entity = new PlayFab.MultiplayerModels.EntityKey {
            Id = PlayFabSettings.staticPlayer.EntityId,
            Type = PlayFabSettings.staticPlayer.EntityType,
        },
        Attributes = new MatchmakingPlayerAttributes {
            DataObject = new {
                latencies = new object[] {
                    new {
                        region = "EastUs",
                        latency = 100,
                    },
                },
            },
        },
    };
    requestData.QueueName = "TestQueue"; // Matchmaking Queue Name
    requestData.GiveUpAfterSeconds = 120; // 120 seconds
    PlayFabMultiplayerAPI.CreateMatchmakingTicket( requestData, OnCreateMatchmakingTicketResult, OnCreateMatchmakingTicketError );
}


private void OnCreateMatchmakingTicketResult( CreateMatchmakingTicketResult response )
{
    CheckMatchmakingTicket( response.TicketId );
}


private void OnCreateMatchmakingTicketError( PlayFabError error )
{
    Debug.Log( error.ErrorMessage );
}


private void CheckMatchmakingTicket( string ticketId )
{
    Debug.Log( "Checking ticket " + ticketId );
    matchmakingTicket = ticketId;
    GetMatchmakingTicketRequest requestData = new GetMatchmakingTicketRequest();
    requestData.QueueName = "TestQueue"; // Matchmaking Queue Name
    requestData.TicketId = ticketId;
    PlayFabMultiplayerAPI.GetMatchmakingTicket( requestData, OnCheckMatchmakingTicketResult, OnCheckMatchmakingTicketError );
}


private void OnCheckMatchmakingTicketResult( GetMatchmakingTicketResult response )
{
    bool queueTicketCheck = false;
    switch( response.Status )
    {
        case "Matched":
            ErrorMessage.text = "Found Match!";
            Debug.Log( "Found Match " + response.MatchId );
            matchmakingTicket = "";
            JoinMatch( response.MatchId );
            break;
        case "WaitingForMatch":
            ErrorMessage.text = "Waiting for match";
            Debug.Log( "Waiting for match..." );
            queueTicketCheck = true;
            break;
        case "WaitingForPlayers":
            ErrorMessage.text = "Waiting for players";
            Debug.Log( "Waiting for players..." );
            queueTicketCheck = true;
            break;
        case "WaitingForServer":
            ErrorMessage.text = "Waiting for server";
            Debug.Log( "Waiting for server..." );
            queueTicketCheck = true;
            break;
        case "Canceled":
            ErrorMessage.text = "Canceled";
            Debug.Log( "Canceled..." );
            matchmakingTicket = "";
            break;
        default:
            break;
    }


    if( queueTicketCheck )
    {
        ticketTimer = 6.0f;
    }
}


private void OnCheckMatchmakingTicketError( PlayFabError error )
{
    Debug.Log( error.ErrorMessage );
}


private void JoinMatch( string matchId )
{
    Debug.Log( "Joining Match..." );
    GetMatchRequest requestData = new GetMatchRequest();
    requestData.QueueName = "TestQueue"; // Matchmaking Queue Name
    requestData.MatchId = matchId;
    PlayFabMultiplayerAPI.GetMatch( requestData, OnGetMatchResult, OnGetMatchError );
}


private void OnGetMatchResult( GetMatchResult response )
{
    Client.matchAddress = response.ServerDetails.IPV4Address;
    Client.matchPort = (ushort)response.ServerDetails.Ports[ 0 ].Num;
SceneManager.LoadScene( SceneName ); // Load Main Scene
}


private void OnGetMatchError( PlayFabError error )
{
    Debug.Log( error.ErrorMessage );
}

接下来,我们在 `Update` 方法中实现一个计时器来检查匹配票证的状态

void Update()
{
    // Update matchmaking ticket check
    if( ticketTimer > 0 && matchmakingTicket != "" )
    {
        ticketTimer -= Time.deltaTime;
        if( ticketTimer <= 0.0f )
        {
            CheckMatchmakingTicket( matchmakingTicket );
        }
    }
}

在 `OnRegisterSuccess` 和 `OnLoginSuccess` 中,我们将加载 `MainScene` 的代码行替换为对 `RequestMatchmaking` 的调用以开始该过程。

例如,`OnLoginSuccess` 现在看起来像这样

private void OnLoginSuccess(LoginResult result)
{
    ErrorMessage.text = "";
    RequestMatchmaking();
}

然后我们需要更新客户端脚本以获取匹配的服务器信息。我们将这两个变量添加到 PlayFab 登录脚本设置的类中,以传递信息

static public string matchAddress = "";
static public ushort matchPort = 0;

最后,我们按照以下方式更改 `Start` 方法以使用此服务器信息连接到游戏会话

void Start()
{
    Debug.Log( "Starting Client" );
    if( RunLocal )
    {
        connectToServer( "127.0.0.1", 7777 );
    }
    else
    {
        connectToServer( matchAddress, matchPort );
    }
}

我们必须牢记,在生产级的多人游戏中,我们应该以更强的健壮性和更好的错误处理来实现此过程。

供参考,您可以在 此处 找到完整的 `PlayFabCode.cs` 脚本。

现在我们可以构建游戏客户端可执行文件并运行多个实例,以尝试与我们的 PlayFab 服务器进行匹配。

后续步骤

在本文中,我们看到了集成 PlayFab 的多人功能是多么简单有效。

继续本系列的 最后一部分,我们将通过探索使用玩家统计信息的 PlayFab 排行榜支持来结束。不要错过!

要了解有关 Azure PlayFab Analytics 的更多信息,并获得功能概述、快速入门指南和教程,请查看 Azure PlayFab Analytics 文档

© . All rights reserved.