2013-03-25 10 views
7

Ich versuche, ein Echtzeit-Multiplayer-Spiel mit einer benutzerdefinierten Benutzeroberfläche (kein GKMatchMakerViewController) zu implementieren. Ich benutze startBrowsingForNearbyPlayersWithReachableHandler:^(NSString * playerID, BOOL erreichbar), um einen lokalen Player zu finden und dann eine Match-Anfrage mit dem GKMatchmaker Singleton zu initiieren (was ich bereits initiiert habe).iOS Game Center GameKit Programmatic Laden Matchmaking

Hier ist, wo ich Probleme habe. Wenn ich eine Anfrage sende, wird der Completion-Handler fast sofort ohne einen Fehler ausgelöst, und die zurückgegebene Übereinstimmung hat eine erwartete Spieleranzahl von Null. Inzwischen hat sich der andere Spieler auf jeden Fall nicht auf die Anfrage reagiert

Relevante Code:

- (void) findMatch { 
    GKMatchRequest *request = [[GKMatchRequest alloc] init]; 
    request.minPlayers = NUM_PLAYERS_PER_MATCH; //2 
    request.maxPlayers = NUM_PLAYERS_PER_MATCH; //2 
    if (nil != self.playersToInvite) { 
    // we always successfully get in this if-statement 
    request.playersToInvite = self.playersToInvite; 
    request.inviteeResponseHandler = ^(NSString *playerID, GKInviteeResponse response) { 
     [self.delegate updateUIForPlayer: playerID accepted: (response == GKInviteeResponseAccepted)]; 
    }; 
} 
request.inviteMessage = @"Let's Play!"; 

[self.matchmaker findMatchForRequest:request withCompletionHandler:^(GKMatch *match, NSError *error) { 
    if (error) { 
    // Print the error 
    NSLog(@"%@", error.localizedDescription); 
    } else 
    if (match != nil) { 
     self.currentMatch = match; 
     self.currentMatch.delegate = self; 

     // All players are connected 
     if (match.expectedPlayerCount == 0) { 
     // start match 
     [self startMatch]; 
     } 
     [self stopLookingForPlayers]; 
     } 
    }]; 
} 

ich aus einer früheren Frage wissen (iOS Gamecenter Programmatic Matchmaking), die ich brauche dazu gehören:

- (void)matchForInvite:(GKInvite *)invite completionHandler:(void (^)(GKMatch *match, NSError *error))completionHandler 

in der obige Code, aber ich weiß nicht, wo das enthalten sein sollte. Ich habe es sowohl mit dem GKMatchRequest eingeladeneResponseHandler als auch mit dem Matchmaker finMatchForRequest: withCompletionHandler vergeblich versucht. Das Verhalten, das passiert, ist, dass der Matchmaker sofort eine Übereinstimmung zurückgibt (noch bevor der Eingeladene eingeladen wurde) und der matchRequest girobeeResponseHandler wird nie aufgerufen, selbst nachdem der Eingeladene die Match-Einladung angetippt hat.

Kann jemand dazu einen Rat geben? Vielen Dank.

... Jim

+0

Wie haben Sie startBrowsingForNearbyPla bekommen? yersWithReachableHandler funktioniert? Ich bekomme nie einen Rückruf von ihm? – bobmoff

Antwort

15

Ich habe gerade das funktioniert an meinem Spiel heute Abend. Es gibt mehr Verhandlungen, die Sie tun müssen, um den Kommunikationskanal einzurichten. Die anfängliche Übereinstimmung, die an den Inviter zurückgegeben wird, wartet darauf, dass der Eingeladene antwortet ... Hier ist mein Prozess mit nur zwei Spielern. Hier sind alle Schritte, die mein Kommunikations-Spin-Up durchführt. Offensichtlich keine wirkliche Fehlerbehandlung hier enthalten:

Erstens erkennen Sie echte Spieler

Zweitens direkt nach der Authentifizierung gesetzt inviteHandler. So etwas wie das:

[GKMatchmaker sharedMatchmaker].inviteHandler = ^(GKInvite* acceptedInvite, NSArray *playersToInvite) 
{ 
    if(acceptedInvite != nil) 
    { 
     // Get a match for the invite we obtained... 
     [[GKMatchmaker sharedMatchmaker] matchForInvite:acceptedInvite completionHandler:^(GKMatch *match, NSError *error) 
     { 
      if(match != nil) 
      { 
       [self disconnectMatch]; 
       // Record the new match... 
       self.MM_gameCenterCurrentMatch = match; 
       self.MM_gameCenterCurrentMatch.delegate = self; 
      } 
      else if(error != nil) 
      { 
       NSLog(@"ERROR: From matchForInvite: %@", [error description]); 
      } 
      else 
      { 
       NSLog(@"ERROR: Unexpected return from matchForInvite..."); 
      } 
     }]; 
    } 
}; 

Drittens, Holen Sie sich Ihre Liste der Freunde playerIds (nicht Alias).

Viertens Richten Sie Ihre GKMatchRequest so etwas wie dieses ... Ich lade nur einen Freund:

// Initialize the match request - Just targeting iOS 6 for now... 
GKMatchRequest* request = [[GKMatchRequest alloc] init]; 
request.minPlayers = 2; 
request.maxPlayers = 2; 
request.playersToInvite = [NSArray arrayWithObject:player.playerID]; 
request.inviteMessage = @"Let's play!"; 
// This gets called when somebody accepts 
request.inviteeResponseHandler = ^(NSString *playerID, GKInviteeResponse response) 
{ 
    if (response == GKInviteeResponseAccepted) 
    { 
     //NSLog(@"DEBUG: Player Accepted: %@", playerID); 
     // Tell the infrastructure we are don matching and will start using the match 
     [[GKMatchmaker sharedMatchmaker] finishMatchmakingForMatch:self.MM_gameCenterCurrentMatch]; 
    } 
}; 

Fünftens Verwenden Sie die Anfrage findMatchForRequest zu nennen: withCompletionHandler: so etwas wie dieses ...

[[GKMatchmaker sharedMatchmaker] findMatchForRequest:request withCompletionHandler:^(GKMatch* match, NSError *error) { 
    if (error) 
    { 
     NSLog(@"ERROR: Error makeMatch: %@", [error description]); 
     [self disconnectMatch]; 
    } 
    else if (match != nil) 
    { 
     // Record the new match and set me up as the delegate... 
     self.MM_gameCenterCurrentMatch = match; 
     self.MM_gameCenterCurrentMatch.delegate = self; 
     // There will be no players until the players accept... 
    } 
}]; 

Sechste, das sendet die Anfrage an den anderen Spieler und wenn sie akzeptieren, wird der "inviteHandler" aus dem zweiten Schritt aufgerufen.

Siebtens erhält der "inviteHandler" aus dem zweiten Schritt das Spiel für den GKInvite!

Achtzig, der "girlaineResponseHandler" aus dem vierten Schritt wird aufgerufen, der das Spiel beendet hat!

Neuntens, erstellen Sie einen didChangeState von GKMatchDelegate, um die Finalisierung der Übereinstimmung zu behandeln.Etwas wie folgt aus:

- (void)match:(GKMatch *)match player:(NSString *)playerID didChangeState:(GKPlayerConnectionState)state{ 
switch (state) 
{ 
    case GKPlayerStateConnected: 
     // Handle a new player connection. 
     break; 
    case GKPlayerStateDisconnected: 
     // A player just disconnected. 
     break; 
} 
if (!self.matchStarted && match.expectedPlayerCount == 0) 
{ 
    self.matchStarted = YES; 
    // Handle initial match negotiation. 
    if (self.iAmHost && !self.sentInitialResponse) 
    { 
     self.sentInitialResponse = true; 
     // Send a hello log entry 
     [self sendMessage: [NSString stringWithFormat:@"Message from friend, 'Hello, thanks for accepting, you have connected with %@'", self.MM_gameCenterLocalPlayer.alias] toPlayersInMatch: [NSArray arrayWithObject:playerID]]; 
    } 
}} 

Zehnter, hier ist mein nachrichts:

- (void) sendMessage:(NSString*)action toPlayersInMatch:(NSArray*) playerIds{ 
NSError* err = nil; 
if (![self.MM_gameCenterCurrentMatch sendData:[action dataUsingEncoding:NSUTF8StringEncoding] toPlayers:playerIds withDataMode:GKMatchSendDataReliable error:&err]) 
{ 
    if (err != nil) 
    { 
     NSLog(@"ERROR: Could not send action to players (%@): %@ (%d) - '%@'" ,[playersInMatch componentsJoinedByString:@","],[err localizedDescription],[err code], action); 
    } 
    else 
    { 
     NSLog(@"ERROR: Could not send action to players (%@): null error - '%@'",[playersInMatch componentsJoinedByString:@","], action); 
    } 
} 
else 
{ 
    NSLog(@"DEBUG: Message sent to players (%@) - '%@'",[playersInMatch componentsJoinedByString:@","], action); 
}} 

Elfte, erstellen Sie eine didReceiveData von GKMatchDelegate etwas wie folgt aus:

- (void)match:(GKMatch *)match didReceiveData:(NSData *)data fromPlayer:(NSString *)playerID{ 
NSString* actionString = [[[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding] autorelease]; 
// Send the initial response after we got the initial send from the 
// invitee... 
if (!self.iAmHost &&!self.sentInitialResponse) 
{ 
    self.sentInitialResponse = true; 
    // Send a hello log entry 
    [self sendMessage: [NSString stringWithFormat:@"Message from friend, 'Hello, thanks for inviting, you have connected with %@'", self.MM_gameCenterLocalPlayer.alias] toPlayersInMatch: [NSArray arrayWithObject:playerID]]; 
} 
// Execute the action we were sent... 
NSLog(actionString);} 

Zwölfte ... Nun Sie Lassen Sie die Kommunikationskanäle laufen ... machen Sie, was immer Sie wollen ...

+0

Gute Antwort !!!!! –

+0

@ GoRose-Hulman könnten Sie Ihre Antwort für iOS 7 aktualisieren? –

+0

Kennen Sie den richtigen Weg, dies in iOS9 zu tun? Ich habe gerade eine ähnliche Frage gestellt: http://stackoverflow.com/questions/36728503/gkmatchmaker-findmatchforrequest-invite-never-received – mark