24 Replies
      Latest reply on May 25, 2020 9:45 PM by PBK
      uncletr Level 1 Level 1 (0 points)

        I am using Swift 4.

         

        I am able to authenticate the localplayer and find a match using the Game Center match viewcontroller.  I was also able to link the iOS simulator (player1) to my real iPhone 8 device (player2) into a match for test purposes.

         

        However, after the localplayer is authenticated, I would like to obtain a list of all my game center "friends" myself and then create my own viewController interface to invite/connect players into the game.   I was able to call "GKLocalPlayer.local.loadChallengableFriends( )" to obtain the friends, but I am not sure how to properly invite them to a match one by one programmatically.

         

        Googling indicates GKMatchmaker inviteHandler, GKInvite and "player DidAccept" are involved but I do not know how to put this all together.

         

        Any pointers, hints or sample code would be greatly appreciated.

         

        In the meantime, I will continue to Google around

        • Re: Invite players programmatically into a match
          PBK Level 7 Level 7 (3,795 points)

          There are many tutorials that will walk you through this.  Search for them.

           

          It's been quite some time (pre ARC)  but this code worked long ago:

           

           

          - (void)player:(GKPlayer *)player didAcceptInvite:(GKInvite *)invite{
              GKMatchmakerViewController *mmvc = [[[GKMatchmakerViewController alloc] initWithInvite:invite] autorelease];
              mmvc.matchmakerDelegate = self;
              [self presentViewController:mmvc animated:YES completion:nil];
          }
          
          
          -(void) sendOutAnInvitationTo:(NSString *)action{
            GKMatchRequest *request = [[[GKMatchRequest alloc] init] autorelease];
            request.minPlayers = 2;
            request.maxPlayers = 4;
            GKMatchmakerViewController *mmvc = [[[GKMatchmakerViewController alloc] initWithMatchRequest:request] autorelease];
            if([action isEqualToString:@"add a player"])[mmvc addPlayersToMatch:myMatch];
            mmvc.matchmakerDelegate = self;
                  [self presentViewController:mmvc animated:YES completion:nil];
          }
          
          
          - (void)matchmakerViewControllerWasCancelled:(GKMatchmakerViewController *)viewController{
                  [self dismissViewControllerAnimated:YES completion:nil];
          }
          
          - (void)matchmakerViewController:(GKMatchmakerViewController *)viewController didFailWithError:(NSError *)error{
                  [self dismissViewControllerAnimated:YES completion:nil];
          }
          
          - (void)matchmakerViewController:(GKMatchmakerViewController *)viewController didFindMatch:(GKMatch *)match{
              [self dismissViewControllerAnimated:YES completion:nil];
              match.delegate = self;
            if (match.expectedPlayerCount == 0){
            [self initiateAMatch:match];
            [self startMultiplayerPlay:match];
            }
          }
          
          
          -(void) initiateAMatch:(GKMatch *)match{
            useGameCenter=YES;
            bluetoothStatus=1;
            AVAudioSession *audioSession = [AVAudioSession sharedInstance];
            NSError *error= nil;
            [audioSession setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker error:&error];
            [audioSession setActive: YES error: NULL];
            self.allChannel=[match voiceChatWithName:@"allPlayers"];
          
            [allChannel start];
            allChannel.volume = 1.0;
            allChannel.active=YES;
            voiceChatIsActive=YES;
            self.myMatch = match; // Use a retaining property to retain the match.
          }
          
          
          
          - (void)match:(GKMatch *)match player:(NSString *)playerID didChangeState:(GKPlayerConnectionState)state{
            switch (state){            
                  case GKPlayerStateUnknown:
                      // handle a new player connection.
                      // NSLog(@"here with number =  %i",match.expectedPlayerCount);
                      break;
                  case GKPlayerStateConnected:
                      // handle a new player connection.
                      // NSLog(@"here with number =  %i",match.expectedPlayerCount);
                      if (match.expectedPlayerCount == 0){
                         [self initiateAMatch:match];  //problem if switched from an earlier game??
                         [self startMultiplayerPlay:match]; 
                      }
                      break;
                  case GKPlayerStateDisconnected:
                      if([match.players count]==0){  // 2016 was playerids
                             UIAlertView *playerList;
                             playerList = [[UIAlertView alloc]
                                  initWithTitle:nil
                                  message:@"Game has eneded.  You are no longer connected to any other player."
                                  delegate: self        
                                  cancelButtonTitle:@"Ok"
                                  otherButtonTitles:nil];
                           [playerList show];
                           [playerList release];
                      }
                      [self startMultiplayerPlay:match];//I think this will work....
                      break;
             }
          }
          
          -(void) startMultiplayerPlay:(GKMatch *)match{
          ////     good to go......
          }
          
          
          • Re: Invite players programmatically into a match
            uncletr Level 1 Level 1 (0 points)

            PBK,

             

            Thanks for the code, but I have all of this code already working.

             

            I would like to find a way to Invite players to participate in a match without presenting the Game Center matchmaker view controller and having to click an "Invite Players" button.     I would like to design my own view controller interface to add players to a game instead of using the default Game Center matchmaker view controller.

             

            I am assuming I would still need to create the match using the GKMatchRequest (as below) but I am hoping I do not have to display the matchmaker view controller which is provided.

             

                    let request = GKMatchRequest.init()
                    request.minPlayers = minPlayers
                    request.maxPlayers = maxPlayers

             

            I have googled and googled but have not found anything

             

            Do you know how to do this?

            • Re: Invite players programmatically into a match
              dawvgawrbh Level 1 Level 1 (0 points)

              Hello everyone. I am new to this forum. Interesting thread

              • Re: Invite players programmatically into a match
                Dan-Druff Level 1 Level 1 (0 points)

                Hi, Did you end up having any luck with this? I'm having the same issue with implementing the invitation handler...which has a bunch of deprecated items associated with it in the documentation.

                 

                https://developer.apple.com/documentation/gamekit/gkmatchmaker/1521060-invitehandler

                 

                var inviteHandler: ((GKInvite, [Any]?) -> Void)? { get set }

                 

                I just want to know how to actually accept an invite? I can send one, and on the test device have a notification banner that launches the app...but what do we do from there?

                  • Re: Invite players programmatically into a match
                    JohanHWB Level 1 Level 1 (0 points)

                    Did you look into the GKLocalPlayerListener?

                     

                    The critical step is to register your GameKit wrapper (the entity you have setup to receive the invite related push events) to make it receive the local player related events - including those relevant for invites:

                     

                    GKLocalPlayer.local.register(self)

                     

                    Then the handler will receive all these events - which are all part of the GKLocalPlayerListener:

                     

                        // MARK: GKInviteEventListener
                        
                        func player(_ player: GKPlayer, didAccept invite: GKInvite) {
                            print("Did accept invite, update UI or show and start the game?")
                        }
                        
                        func player(_ player: GKPlayer, didRequestMatchWithRecipients recipientPlayers: [GKPlayer]) {
                            print("Did request match with recipients")
                        }
                        
                        func player(_ player: GKPlayer, didRequestMatchWithPlayers playerIDsToInvite: [String]) {
                            print("Did request match with players")
                        }
                    
                    

                     

                    Hope this helps.

                      • Re: Invite players programmatically into a match
                        Dan-Druff Level 1 Level 1 (0 points)

                        Thanks for the reply!!

                         

                        Yes, I'm using the GKLocalPlayerListener protocol. I'm at the point where I can receive the invite, have it launch the app and I can even accept the invite it on the test device, and get it to call 'did accept invite'.  That's great, but it then gets stuck on the matchmaker, and never calls 'did find match'. What am I missing?

                          • Re: Invite players programmatically into a match
                            PBK Level 7 Level 7 (3,795 points)

                            Here's what I do from there:  (I do not recall why I had to check for 'didAcceptInviteVCShowing' and dismiss it if it was showing.)

                             

                             

                             

                            
                            -(void)acceptThisInvite:(GKInvite *)invite{
                                didAcceptInviteVCShowing=YES;
                                GKMatchmakerViewController *mmvc = [[GKMatchmakerViewController alloc] initWithInvite:invite];
                                mmvc.matchmakerDelegate = self;
                                [[self topController] presentViewController:mmvc animated:YES completion:^{
                                    if (@available(iOS 11.0, *)) {
                                        mmvc.view.frame=CGRectMake(0,mmvc.view.safeAreaInsets.top, mmvc.view.bounds.size.width, mmvc.view.bounds.size.height-mmvc.view.safeAreaInsets.top);
                                    } else {
                                        // Fallback on earlier versions
                                    }    
                                }];
                            }
                            
                            - (void)player:(GKPlayer *)player didAcceptInvite:(GKInvite *)invite{
                                
                                if(!didAcceptInviteVCShowing){
                                   [self acceptThisInvite:invite];
                                }else{
                                    [[self topController] dismissViewControllerAnimated:YES completion:^{
                                        [self acceptThisInvite:invite];
                                    }];
                                }
                            }
                                
                            
                              • Re: Invite players programmatically into a match
                                Dan-Druff Level 1 Level 1 (0 points)

                                Thank you so much for your help! I'm still struggling though.

                                 

                                How would I write this example in Swift?  What are we trying to do here? If the VC is showing, accept the invite?? There isn't an "acceptThisInvite" function...

                                 

                                How do I accept an invite? This is the piece I'm missing. I'm able to get the app to call "didAcceptInvite", but it never gets to "didFindMatch", which is what starts the game. There must be a step in between...

                                 

                                I'm sure Game Center must provide a way to do this?

                                 

                                Thank you again,

                                 

                                Dan

                                  • Re: Invite players programmatically into a match
                                    PBK Level 7 Level 7 (3,795 points)

                                    Sorry, I don't do Swift.

                                     

                                    In didAcceptInvite you first check to see if you are already displaying a "did accept invite" MatchMaker view controller (didAcceptInviteVCShowing=YES).  If you are, you dismiss it and then show the new view controller only after it is dismissed.  But if you are not showing the "did accept invite" view controller then you immediately show  a "did accept invite" "mmvc" viewController.   The mmvc delegate will call didFindMatch: when it is dismissed by the user.  In didFindMatch you set didAcceptInviteVCShowing back to NO.

                                     

                                     

                                    I created the method acceptThisInvite because it is called in two places.  Perhaps this will be simplier to translate into Swift:

                                     

                                    
                                    - (void)player:(GKPlayer *)player didAcceptInvite:(GKInvite *)invite{
                                          
                                        if(!didAcceptInviteVCShowing){
                                            didAcceptInviteVCShowing=YES;
                                            GKMatchmakerViewController *mmvc = [[GKMatchmakerViewController alloc] initWithInvite:invite];
                                            mmvc.matchmakerDelegate = self;
                                            [[self topController] presentViewController:mmvc animated:YES completion:^{
                                                if (@available(iOS 11.0, *)) {
                                                    mmvc.view.frame=CGRectMake(0,mmvc.view.safeAreaInsets.top, mmvc.view.bounds.size.width, mmvc.view.bounds.size.height-mmvc.view.safeAreaInsets.top);
                                                } else {
                                                    // Fallback on earlier versions
                                                }
                                            }];
                                        }else{
                                            [[self topController] dismissViewControllerAnimated:YES completion:^{
                                                didAcceptInviteVCShowing=YES;
                                                GKMatchmakerViewController *mmvc = [[GKMatchmakerViewController alloc] initWithInvite:invite];
                                                mmvc.matchmakerDelegate = self;
                                                [[self topController] presentViewController:mmvc animated:YES completion:^{
                                                    if (@available(iOS 11.0, *)) {
                                                        mmvc.view.frame=CGRectMake(0,mmvc.view.safeAreaInsets.top, mmvc.view.bounds.size.width, mmvc.view.bounds.size.height-mmvc.view.safeAreaInsets.top);
                                                    } else {
                                                        // Fallback on earlier versions
                                                    }
                                                }];
                                            }];
                                        }
                                    }