Estoy tratando de conectar a dos jugadores entre sí usando GameKit en un juego muy simple. Quiero usar GKMatchmaker.shared().findMatch porque no quiero mostrar ningún controlador de vista relacionado con GameCenter. (para mantenerlo simple)
Aunque GameKit crea una coincidencia después de encontrar a dos jugadores, se produce un error que impide que cualquiera de los jugadores envíe un mensaje a los demás.
El código básico es el siguiente (basado en los documentos descritos aquí: 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)) } })La salida de eso es
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 failedminPlayers se establece en 2. Como se llama al controlador de finalización, esto significa que se encontró al menos un jugador más. Pero el número de jugadores devueltos en match.players.count es 0cannot set connecting state for players ... as there is no inviteDelegate set yet . No puedo encontrar ninguna información sobre este delegado invitado.¿Qué es un inviteDelegate? ¿Realmente necesito implementar tal (si es así, entonces cómo?)? (No lo creo, ya que los documentos establecen que el partido solo comienza después de que se aceptan las invitaciones).
¿Cómo puedo resolver este problema?
aquí hay un ejemplo de trabajo para usted. abra en dos máquinas, asegúrese de que ambas estén autenticadas, presione "findMatch()" en ambas máquinas (y espere la confirmación), luego haga ping baby ping
Creo que el error "no inviteDelegate set yet" no significa que la creación de coincidencias falló, y puede ignorarse con seguridad, como se menciona aquí
querrá implementar más del protocolo GKMatchDelegate, pero este es un esqueleto para fines de demostración
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") } } }