How to accept an invitation in Game Center

2019-02-10 07:51发布

问题:

I'm trying to implement invitations with Game Center and there's one thing that i don't understand. Ok, i've sent an invitation from one device to another. Then i have an UIAlertView on receiver which asks me i would like to accept or decline the invitation. when i accept it it is handled like this:

[GKMatchmaker sharedMatchmaker].inviteHandler = ^(GKInvite *acceptedInvite, NSArray *playersToInvite) 
                 {
                     // Insert application-specific code here to clean up any games in progress.
                     if (acceptedInvite)
                     {
                         GKMatchmakerViewController *mmvc = [[[GKMatchmakerViewController alloc] initWithInvite:acceptedInvite] autorelease];
                         mmvc.matchmakerDelegate = self;
                         [presentingViewController presentModalViewController:mmvc animated:YES];
                     }
                     else if (playersToInvite)
                     {
                         GKMatchRequest *request = [[[GKMatchRequest alloc] init] autorelease];
                         request.minPlayers = 2;
                         request.maxPlayers = 4;
                         request.playersToInvite = playersToInvite;

                         GKMatchmakerViewController *mmvc = [[[GKMatchmakerViewController alloc] initWithMatchRequest:request] autorelease];
                         mmvc.matchmakerDelegate = self;
                         [presentingViewController presentModalViewController:mmvc animated:YES];

                     }
                 };

Well, that's great, but what next? the sender device is obviously waiting for some standard type of response, cause it also shows an alert telling me that there's some invitations not answered yet if i tap "Play now".

So how do i accept an invitation? What kind of data (and how) should i send back? And what exactly should i do on the receiver's side? Should game start instantly after tapping "Accept" or i should dismiss the AlertView first and then tap "Play now"?

Ray Wenderlich's tutorial says that i should choose second way but when dismiss the alert and tap "Play now" it turns out the sender device is still waiting for response and is not aware that i have already accepted the invitation. if i tap "Play now" at this moment then, as i said above, it shows an alert which says that the application is waiting for the response. So if you've ever done that then please explain me what should i do. Thanks!

回答1:

  1. I register for invites as soon as the game is loaded and call the delegate when an invite is received
  2. So inviteReceived calls the match maker for dismissing the game center controller and creating the match
  3. And finally, when the match is being found, the method connectionStatusChanged takes care of presenting all the game's views and players and stuff

Here is the code:

I register for invites as soon as the game is loaded and call the delegate when an invite is received:

- (void)registerInvites {
    [GKMatchmaker sharedMatchmaker].inviteHandler = ^(GKInvite *acceptedInvite, NSArray *playersToInvite) {
        self.pendingInvite = acceptedInvite;
        self.pendingPlayersToInvite = playersToInvite;
        [delegate inviteReceived];
    };
}

So inviteReceived calls the match maker for dismissing the game center controller and creating the match:

- (void)inviteReceived {
    [[GCMultiplayerHelper sharedInstance] findMatchWithMinPlayers:2 maxPlayers:2 viewController:(UIViewController*)[self.superview nextResponder] delegate:self];
}


- (void)findMatchWithMinPlayers:(int)minPlayers maxPlayers:(int)maxPlayers viewController:(UIViewController *)viewController delegate:(id<GCMultiplayerHelperDelegate>)theDelegate {
    if (!gameCenterAvailable) return;

    matchStarted = NO;
    self.match = nil;
    self.presentingViewController = viewController;
    delegate = theDelegate;

    [presentingViewController dismissModalViewControllerAnimated:YES];
    GKMatchmakerViewController *mmvc;

    if (pendingInvite != nil) {

        mmvc = [[[GKMatchmakerViewController alloc] initWithInvite:pendingInvite] autorelease];

    } else {

        GKMatchRequest *request = [[[GKMatchRequest alloc] init] autorelease]; 
        request.minPlayers = minPlayers;     
        request.maxPlayers = maxPlayers;
        request.playersToInvite = pendingPlayersToInvite;

        mmvc = [[[GKMatchmakerViewController alloc] initWithMatchRequest:request] autorelease];    

    }

    mmvc.matchmakerDelegate = self;
    [presentingViewController presentModalViewController:mmvc animated:YES];

    self.pendingInvite = nil;
    self.pendingPlayersToInvite = nil;
}

And finally, when the match is been found, the method connectionStatusChanged takes care of presenting all the game's views, players and starting the match:

- (void)matchmakerViewController:(GKMatchmakerViewController *)viewController didFindMatch:(GKMatch *)theMatch
{
    self.match = theMatch;
    match.delegate = self;
    if (!matchStarted && match.expectedPlayerCount == 0) {
        NSLog(@"Ready to start match! - didFindMatch");
        [presentingViewController dismissModalViewControllerAnimated:YES];

        [self.delegate connectionStatusChanged:CONNECTIONSUCCESS];
    }
}


回答2:

I've successfully implemented an online game center match following Ray's tutorials. The answer to you question is: You don't have to send anything to the inviting device. When you call the line:GKMatchmakerViewController *mmvc = [[[GKMatchmakerViewController alloc] initWithMatchRequest:request] autorelease];, the matchMakerVController handles the connection . However, you should write an invitation handler ASAP, preferably in the authentication changed method. See mine:

-(void) authenticationChanged {

if ([GKLocalPlayer localPlayer].isAuthenticated && !userAuthenticated) {
    NSLog(@"Authentication changed: player authenticated.");
    userAuthenticated = TRUE;

    [self sendUnsentScores];

    [GKMatchmaker sharedMatchmaker].inviteHandler = ^(GKInvite *acceptedInvite, NSArray *playersToInvite){

        NSLog(@"Invite");

        if([AppDelegate mainMenuController].presentedViewController!=nil) {
            [[AppDelegate mainMenuController] dismissViewControllerAnimated:NO completion:^{

            }];
        } // if we're not on the main menu, or another game is going on.
          // this would be easier to do if you were using a navigation controller
          // where you'd just push the multiplayer menu etc.


        self.pendingInvite = acceptedInvite;
        self.pendingPlayersToInvite = playersToInvite;

        [[AppDelegate mainMenuController] presentViewController:[AppDelegate mainMenuController].multiGameMenu animated:NO completion:^{ // push the multiplayer menu

            [[AppDelegate mainMenuController].multiGameMenu duel:nil];
        }];

    };

}

and here is the duel method if you're interested. Very messy code but deal with it :)

- (IBAction)duel:(id)sender {
NSLog(@"duel");

if (presentingMenu.multiGameController==nil || presentingMenu.multiGame.gameInProgress==NO) {

    presentingMenu.multiGame=nil;
    presentingMenu.multiGameController=nil;

    MultiViewController *mvc = [[MultiViewController alloc] init]; //create game VC

    presentingMenu.multiGameController = mvc; //presenting menu is just the main menu VC
                                              // it holds this menu, and the game
                                              // objects.
}

if (presentingMenu.multiGame == nil) {

    presentingMenu.multiGame = [[MultiGame alloc] // similarly create the game object

    initWithViewController:presentingMenu.multiGameController];
    //they both have pointers to each other (A loose, bad MVC).                        

    presentingMenu.multiGameController.game = presentingMenu.multiGame;

    [presentingMenu.multiGame startGame];

}

if (presentingMenu.multiGameController.gameState==0) { //new game

    presentingMenu.multiGameController.game = presentingMenu.multiGame;

    [[GCHelper sharedInstance] findMatchWithMinPlayers:2 maxPlayers:2 viewController:self delegate:presentingMenu.multiGame]; // the GC magic happens here - it know about the invite.

} else {

    [self presentViewController:presentingMenu.multiGameController animated:YES completion:^{

    }];

}

}


回答3:

inviteHandler = ^(GKInvite *acceptedInvite, NSArray *playersToInvite) is deprecated now. See the new way to register for invite notifications.

GKMatchMaker invite handler deprecated