无法使用 GKMatchmaker.shared().findMatch 连接 GameKit 中的玩家

Can't connect players in GameKit using GKMatchmaker.shared().findMatch

我正在尝试在一个非常简单的游戏中使用 GameKit 将两个玩家相互联系起来。我想使用 GKMatchmaker.shared().findMatch 因为我不想显示任何与 GameCenter 相关的视图控制器。 (为简单起见)

问题:

即使 GameKit 在找到两名玩家后创建了一场比赛,也会发生一个错误,阻止任何一名玩家向其他玩家发送任何消息。

现状:

基本代码如下(基于此处描述的文档:https://developer.apple.com/documentation/gamekit/finding_multiple_players_for_a_game

print("Requesting multiplayer match")
let request = GKMatchRequest()
request.minPlayers = 2
request.maxPlayers = 2
request.recipientResponseHandler = {(player: GKPlayer, respnse: GKInviteRecipientResponse) -> Void in
    print("new player about to join")
    print(player.alias)
    print(respnse)
}

GKMatchmaker.shared().findMatch(for: request, withCompletionHandler: {
    (match: GKMatch?, error: Error?) -> Void in
    if error != nil {
        // Handle the error that occurred finding a match.
        print("error during matchmaking")
        print(error as Any)
    } else if match != nil {
        guard let match = match else { return }

        print("connected to \(match.players.count) players")

        // load the multiplayer data handler
        let handler = MultiMatchHandler()
        match.delegate = handler

        // load the multiplayer service
        let service = MultiMatchService(match: match)
        service.sendMessageToAll(text: "Hello from the other side")

        // finish the match making
        GKMatchmaker.shared().finishMatchmaking(for: match)

        // Start the game with the players in the match.
        self.view?.presentScene(GameScene.newScene(multiplayer: service))
    }

})

那个的输出是

Requesting multiplayer match
2022-01-05 01:19:16.554959+0100 Grapefruit[38300:10026027] [Match] cannot set connecting state for players: (
    "<GKPlayer: 0x282add280>(alias:... gamePlayerID:... teamPlayerID:... name:... status:(null) friendBiDirectional:0 friendPlayedWith:1 friendPlayedNearby:0 acceptedGameInviteFromThisFriend:0 initiatedGameInviteToThisFriend:0 automatchedTogether:1)"
), as there is no inviteDelegate set yet. The state might directly change to Ready when we set the inviteDelegate later and call sendQueuedStatesAndPackets.
2022-01-05 01:19:16.557002+0100 Grapefruit[38300:10026027] [Match] syncPlayers failed to loadPlayersForLegacyIdentifiers: (
    "..."
)
connected to 0 players
sending text Hello from the other side failed

调查结果:

实际问题:

什么是邀请代表?我真的需要实施这样的(如果是,那么如何实施?)? (我不这么认为,因为文档说明比赛仅在接受邀请后才开始)。

我该如何解决这个问题?

这是一个适合您的工作示例。在两台机器上打开,确保都经过身份验证,在两台机器上按“findMatch()”(并等待确认),然后 ping baby ping

我相信“尚未设置邀请代表”错误并不意味着必要的匹配失败,可以安全地忽略,如前所述here

您需要实现更多 GKMatchDelegate 协议,但这是用于演示目的的框架

import SwiftUI
import GameKit
import SpriteKit

class MyGameScene: SKScene, GKMatchDelegate {
    override func didMove(to view: SKView) {
        self.backgroundColor = .yellow
    }
    
    //GKMatchDelegate protocol
    func match(_ match: GKMatch, didReceive data: Data, forRecipient recipient: GKPlayer, fromRemotePlayer player: GKPlayer) {
        print("\(Self.self) \(#function) -- ping received")
    }
}

struct Matchmaker: View {
    @State var isAuthenticated:Bool = false
    @State var scene = MyGameScene()
    @State var match:GKMatch? = nil
    var body: some View {
        ZStack {
            Color.clear
            SpriteView(scene: scene)
            VStack(alignment: .leading, spacing: 20) {
                Text("1) authenticate() \(Image(systemName: isAuthenticated ? "checkmark.icloud" : "xmark.icloud"))")
                Button { findMatch() } label: {
                    Text("2) findMatch() \(Image(systemName: (match != nil) ? "person.fill.checkmark" : "person.fill.xmark"))")
                }
                Button { ping() } label: {
                    Text("3) ping()")
                }
            }
        }
        .onAppear() {
            authenticate()
        }
    }
    
    func authenticate() {
        GKLocalPlayer.local.authenticateHandler = { viewController, error in
            if let error = error { print(error) }
            isAuthenticated = (error == nil)
        }
    }
    
    func findMatch() {
        guard isAuthenticated else { return }
        let request = GKMatchRequest()
        request.minPlayers = 2
        request.maxPlayers = 2
        request.playerAttributes = 0xFFFFFFFF //mask for "i'll match with anyone"

        GKMatchmaker.shared().findMatch (for: request) { match, error in
            if let error = error { print(error) }
            self.match = match
            self.match?.delegate = scene
        }
    }
    
    func ping() {
        let players = match?.players ?? [];
        let data = Data()
        do {
            try match?.send(data, to: players, dataMode: .reliable)
        } catch  {
            print("Sending failed")
        }
    }
}