Wdrażam grę turową z trybem multiplayer poprzez gamecenter. Mam 2 urządzenia (1 ipad, 1 iphone) do przetestowania w trybie piaskownicy, które działały dobrze, ale ostatnio zaczęło się zmagać w automatycznym procesie kojarzenia. Po wysłaniu pierwszego zwrotu od jednego użytkownika, drugie urządzenie nie rozpoznaje natychmiast tej gry, ale otwiera własną świeżą grę. Zanim udało się od razu zorientować się, że gra zaczęła się w drugim urządzeniu, kojarzenie było dość proste. Nie pamiętam też żadnych części związanych z dopasowywaniem (NSCoding
, GKTurnBasedEventHandler
, GKTurnBasedMatchmakerViewControllerDelegate
przekazać metody itp.).Game Matchmaking GKTurnBasedMatch ma znaczące opóźnienie (~ 1 min)
Teraz wysyłam pierwszą turę z jednego urządzenia i muszę poczekać około 1 minuty, aby drugie urządzenie mogło połączyć się z tą grą. Po nawiązaniu połączenia funkcje endTurnWithMatchData działają bez żadnych problemów, mogą wysyłać i odbierać dane w ciągu 1-2 sekund. Ale to nie będzie dobry UX, jeśli użytkownicy zaczną świeżą grę i będą musieli poczekać 1 minutę, aby inny użytkownik mógł połączyć się z jego grą. Czy ktoś doświadczał znacznego opóźnienia w automatycznym doborze partnera? Nie zaimplementowałem jeszcze zaproszeń, więc nie mogę tego sprawdzić. Zapisane przeze mnie dane z NSKeyedArchiver wydawały się dość duże, 3396 bajtów, nawet w przypadku nowej gry z prawie żadnymi danymi. A oto odpowiednie części mojego kodu:
GameOptionsViewController
:
- (void)turnBasedMatchmakerViewControllerWasCancelled:(GKTurnBasedMatchmakerViewController *)viewController
{
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)turnBasedMatchmakerViewController:(GKTurnBasedMatchmakerViewController *)viewController didFailWithError:(NSError *)error
{
[self dismissViewControllerAnimated:YES completion:nil];
}
- (void)turnBasedMatchmakerViewController:(GKTurnBasedMatchmakerViewController *)viewController didFindMatch:(GKTurnBasedMatch *)match
{
[self dismissViewControllerAnimated:NO completion:nil];
self.gcMatch = match;
[self performSegueWithIdentifier:@"GameMultiplayer" sender:self];
}
- (void) prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if([segue.identifier isEqualToString:@"GameMultiplayer"])
{
GameViewController *GameVC = (GameViewController *)segue.destinationViewController;
[GameVC setGameMode:GAMEMODE_MULTIPLAYER_SAMEDEVICE];
//Multiplayer game it is
if(self.gcMatch != nil)
{
[GameVC setGameMode:GAMEMODE_MULTIPLAYER_GAMECENTER];
GameVC.gcMatchDelegate = self;
GameVC.gcMatch = self.gcMatch;
NSLog(@"Game OVC Segue: Match ID | %@", self.gcMatch.matchID);
}
}
else
{
...
}
}
GameViewController
:
//This method is called according to user actions
//It's the only method I use to send data to other participant
-(void) sendCurrentGameDataWithNewTurn:(BOOL) newTurn
{
NSLog(@"Sending game data current participant : %@", gcMatch.currentParticipant.playerID);
//Update match data if it is corrupted anyhow
if (gcMatch.currentParticipant == nil)
{
[GKTurnBasedMatch loadMatchWithID:gcMatch.matchID withCompletionHandler:^(GKTurnBasedMatch *match, NSError *error)
{
if (error != nil)
{
NSLog(@"Error :%@", error);
return ;
}
[self sendCurrentGameDataWithNewTurn:newTurn];
}];
}
else
{
NSData *matchData = [NSKeyedArchiver archivedDataWithRootObject:game];
//Game advances to new player, buttons are disabled
if(newTurn)
{
NSLog(@"SENDING NEW TURN");
NSUInteger currentIndex = [gcMatch.participants
indexOfObject:gcMatch.currentParticipant];
GKTurnBasedParticipant *nextParticipant;
nextParticipant = [gcMatch.participants objectAtIndex:
((currentIndex + 1) % [gcMatch.participants count])];
[gcMatch endTurnWithNextParticipants:[NSArray arrayWithObject:nextParticipant] turnTimeout:GC_TURN_TIMEOUT matchData:matchData completionHandler:^(NSError *error) {
NSLog(@"Sent");
if (error) {
NSLog(@"SNT - %@", error);
}
}];
}
else
{
NSLog(@"ONLY UPDATING DATA");
[gcMatch saveCurrentTurnWithMatchData:matchData completionHandler:^(NSError *error) {
NSLog(@"Sent");
if (error) {
NSLog(@"OUD - %@", error);
}
}];
}
}
}
-(void) updateGameDataWithGCMatch
{
//Update whole game data
self.game = [NSKeyedUnarchiver unarchiveObjectWithData:self.gcMatch.matchData];
//Update game ui
...
}
-(void) handleTurnEventForMatch:(GKTurnBasedMatch *)match didBecomeActive:(BOOL)didBecomeActive
{
//Check if I got data for the currently active match that options vc forwarded me here, if not do some debug print and return
if(![self.gcMatch.matchID isEqual:match.matchID])
{
//For debugging reasons I skip if i get info for any previous match (other player quit etc)
NSLog(@"GCMatch matchID: %@ match matchID: %@",self.gcMatch.matchID,match.matchID);
return;
}
NSLog(@"Turn event handle");
self.gcMatch = match;
if([match.currentParticipant.playerID isEqualToString: [GKLocalPlayer localPlayer].playerID ])
{
//Disable field buttons
[self setFieldButtonsEnabled:TRUE];
[self turnChangeAnimationFromLeftToRight:FALSE];
}
[self updateGameDataWithGCMatch];
}
Game Center może mieć pozornie arbitralne opóźnienia. Nigdy nie wiadomo, czy to ze względu na naszą własną sieć, czy coś ze strony Apple. –
Mam opóźnienie od ostatnich 2-3 tygodni. Teraz było gorzej albo lepiej. Czy mogę prosić o takie opóźnienia podczas testowania aplikacji na kontach Sandbox na 2 urządzeniach. Jeśli inni deweloperzy również go mają, to przestanę szukać rozwiązania; kontynuować testowanie, tak jak jest. – guenis
Doświadczyłem również znacznego opóźnienia podczas pracy z piaskownicą GC. Wydaje się również, że różni się on znacznie od sesji roboczych do sesji roboczych. – crgt