Invite players programmatically into a match

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

Answered by uncletr in 399552022

ok, thanks for your input. I really want to create my own viewcontroller so my interface looks like it is part of my game motif instead of some default Game CEnter interface. However, we will see how it goes 🙂 . There is not a lot of examples using swift 4 so I am trying to read everything and put the pieces of the puzzle together bit by bit.

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......
}

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?

I know how to do what I did in the app Go Connect. I don't know if that is what you want or not.

I am not familiar with Go Connect.


I just want to find a way to invite players into a match without displaying the matchmaker view controller provided by Game Center

I think a missed reading the "Real-time matches" section in teh game cnter porgramming guide :>P

It seems like it is talking about this topic. I will give it a read and see what happens, No idea how I missed that section

Download Go Connect and see if that is what you want.


I once duplicated the invite functionality through Cloudkit to avoid using GameCenter but decided it wasn't worth it.


What is wrong with the Game Center View Controllers?

>>What is wrong with the Game Center View Controllers?

I want to be able to invite my friends to the match and if they cannot join then be able to invite random players into the match at that point to fill the available slots. I do not think Game Center view controller provides this type of thing since I call the findMatchWithMinPlayers method which then brings up the Game Center viewcontroller with all random players.


I discovered I can provide a "matchRequest.recipients" array indicating specific players to invite (like my friends), but I am not sure whether the Game Center UI view controller will default to inviting a random player automatically if one of my friends declines the invitation. Do you know how Game Center UI view controller handles a decline of a player listed in the "recipient" array?

>Do you know how Game Center UI view controller handles a decline of a player listed in the "recipient" array?


I do not recall.


After 'rolling my own in CloudKit' in order to avoid using 'Game Center' I decided that was a mistake and reverted to the Game Center approach. I'd recommend your doing the same. They thought alot about the 'invite' concept and came up with a solution that works for most scenarios. I suspect you will find that any particular 'edge case' that you are most focused on will be, in actual practice, a rarity.


IMHO.

Accepted Answer

ok, thanks for your input. I really want to create my own viewcontroller so my interface looks like it is part of my game motif instead of some default Game CEnter interface. However, we will see how it goes 🙂 . There is not a lot of examples using swift 4 so I am trying to read everything and put the pieces of the puzzle together bit by bit.

Again - check out Go Connect and see which view controllers you don't like and why they might be necessary.

And somewhere up there you asked about teh collision - the collision is very likely when the game crashes for any one of a bunch of reasons - game over, network problem. In that case both players will try a reconnect making a collision possible.

I downloaded th GoConnect "Lifestyle" app from the AppStore and it asked me for me email address and a subDomain. I have no idea what a subDomain is so I did not continue.


I did not see any "GoConnect" app dealing with games and such

Go Connect is an app on the Apple App Store. There is a space between Go and Connect.

Searching for "Go Connect" in the App Store returns the following results for me:


  • Connect by goPanache (Booking Beauty Professional)
  • GOconnect (Lifestyle)
  • GoToConnect (Business)
  • Proximiti GoCONNECT (Business)
  • Word Search - Crossword
  • GO!CONNECT! (Casual)
  • 4FrontGo
  • Go-SIM
  • etc..


There is nothin which I can see caleld Go Connect dealing with games

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

From the documentation:


"If the value of [GKMatchRequest.recipients] is non-

nil
, when you use the request to create a match, Game Center invites those players to the match. No automatching is done and the
GKMatchRequest
maxPlayers
and
minPlayers
properties are ignored."

Hey PBK,


Not sure about the uncletr but how Go Game Connect does it in regards to multiplayer is also more ore less what I was hoping to do. Seems all I have to do is initalize the GKMatchmakerViewController with the match?


But.. ideally I would skip directly to the controller that is shown when the player taps the "Invite" button. Is that possible? Should be..

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?

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.

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?

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

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

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

apple App Store

Invite players programmatically into a match
 
 
Q