6

gamecenter を介してマルチプレイヤー モードのターン制ゲームを実装しています。サンドボックスモードでテストする2つのデバイス(1つのiPad、1つのiPhone)があり、正常に機能していましたが、最近、自動マッチメイキングプロセスで苦労し始めました. 1 人のユーザーから最初のターンを送信した後、他のデバイスはそのゲームをすぐには認識せず、独自の新しいゲームを開きます。ゲームが他のデバイスで開始されたことをすぐに検出できるようになる前は、マッチメイキングはかなり簡単でした. NSCodingまた、マッチメイキングに関連する部分 ( 、GKTurnBasedEventHandlerGKTurnBasedMatchmakerViewControllerDelegateデリゲート メソッドなど)を変更した覚えはありません。

ここで、1 つのデバイスから最初のターンを送信し、他のデバイスがそのゲームに正常に接続できるように約 1 分待つ必要があります。接続が発生した後、endTurnWithMatchData 呼び出しは問題なく機能し、1 ~ 2 秒以内にデータを送受信できます。しかし、ユーザーが新しいゲームを開始し、別のユーザーが自分のゲームに接続できるようになるまで 1 分待たなければならない場合、それは良い UX とは言えません。自動マッチメイキング プロセスで大幅な遅延を経験した人はいますか? 招待状はまだ実装していないので確認できません。NSKeyedArchiver でアーカイブした matchdata は、データがほとんどない新しいゲームであっても、3396 バイトとかなり大きいように見えました。そして、ここに私のコードの関連部分があります:

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];
}
4

1 に答える 1

0

あなたの質問について:

私自身、Game Center でのマッチメイキングにかなり慣れており、遅延もかなり頻繁に発生しました。これは、私のサイトではなく、リンゴのゲーム センター サーバーが原因であることが証明されています。

追加のガイダンスについては、次のとおりです。

私が見る限り、デバイスでのマッチメイキングに対するあなたの現在のアプローチは次のとおりです。

接続できる試合があるかどうかを確認します --> YES の場合、ゲームデータをリクエストして試合に接続します ELSE 独自の試合を開始し、試合データをブロードキャストします

私の経験では、matchrequestbroadcasts から始めて、2 番目のプレイヤーが見つかるまで待ってから、サーバー デバイスを定義し (たとえば、ゲーム センター名のチェックサムを下げることによって)、そのデバイスでゲームを開始することをお勧めします。

于 2013-04-29T09:59:13.473 に答える