代码之家  ›  专栏  ›  技术社区  ›  Stephan

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

  •  2
  • Stephan  · 技术社区  · 4 年前

    我试图在一个非常简单的游戏中使用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
    

    调查结果:

    • minPlayers 设置为2。当完成处理程序被调用时,这意味着至少又找到了一个玩家。但回归的玩家数量 match.players.count 为0
    • 匹配器显示一个错误,表示 cannot set connecting state for players ... as there is no inviteDelegate set yet 。我找不到此邀请代表的任何信息。

    实际问题:

    什么是邀请电报?我真的需要实现这样的吗(如果需要,那么如何实现?)?(我不这么认为,因为文档中规定比赛只有在接受邀请后才开始)。

    如何解决此问题?

    1 回复  |  直到 4 年前
        1
  •  0
  •   Fault    4 年前

    这里有一个工作的例子给你。在两台机器上打开,确保两者都经过身份验证,在两台计算机上按“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")
            }
        }
    }