Beginning Turn-Based Gaming with iOS 5 Part 1
Update 10/24/12: If you’d like a new version of this tutorial fully updated for iOS 6 and Xcode 4.5, check out iOS 5 by Tutorials Second Edition! Note from Ray: This is the sixth iOS 5 tutorial in the iOS 5 Feast! This tutorial is a free preview chapter from our new book iOS 5 […] By Jake Gundersen.
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Sign up/Sign in
With a free Kodeco account you can download source code, track your progress, bookmark, personalise your learner profile and more!
Create accountAlready a member of Kodeco? Sign in
Contents
Beginning Turn-Based Gaming with iOS 5 Part 1
35 mins
Apple’s Turn Based Match View Controller
The first thing we need to do to play a turn-based match is create one! As discussed above, we can do that using Apple’s provided GKTurnBasedMatchmakerViewController, so let’s create a button we can to presend it to the screen.
Add the gameCenterButton.png file from the resources for this tutorial into your project, and add a new button to the ViewController.xib as shown below:
Once you’ve added the button, set its type to Custom in the Attributes Inspector, and the Image to gameCenterButton.png. You can hit command equals to easily autosize the button to the same size as the image.
Then make sure the Assistant Editor is up and showing ViewController.h, and control-drag from the button down below the @interface. Set the Connection type to Action, name the method presentGCTurnViewController, and click Connect.
Note: Although I’m using the Game Center icon for this tutorial, you shouldn’t use the game center icon in your apps. This practice is discouraged by Apple, and may cause an app to be rejected. Their reasoning is that Game Center is not just the view controller, it is leaderboards, achievements, view controllers (turn based and live) and using this button creates an inconsistent user experience across different apps. So in your apps, you should use some other kind of visual icon or button.
Now, we’re not actually going to do the heavy lifting to present the GKTurnBasedMatchmakerViewController inside our ViewController class. Rather, we’ll let the GCTurnBasedMatchHelper class do all that work for us. This way, the Game Center code will be nicely separated and more easily reusable in future projects.
So open up GCTurnBasedMatchHelper.h and add a new instance variable and method into the header:
// New instance variable
UIViewController *presentingViewController;
// New method
- (void)findMatchWithMinPlayers:(int)minPlayers
maxPlayers:(int)maxPlayers
viewController:(UIViewController *)viewController;
Here we create a new variable to store the view controller that will present the GKTurnBasedMatchmakerViewController, and a method that we’ll use to present it to the screen to find a match with a specified number of players.
Next switch to GCTurnBasedMatchHelper.m and add the following method after authenticateLocalUser:
- (void)findMatchWithMinPlayers:(int)minPlayers
maxPlayers:(int)maxPlayers
viewController:(UIViewController *)viewController {
if (!gameCenterAvailable) return;
presentingViewController = viewController;
GKMatchRequest *request = [[GKMatchRequest alloc] init];
request.minPlayers = minPlayers;
request.maxPlayers = maxPlayers;
GKTurnBasedMatchmakerViewController *mmvc =
[[GKTurnBasedMatchmakerViewController alloc]
initWithMatchRequest:request];
mmvc.turnBasedMatchmakerDelegate = self;
mmvc.showExistingMatches = YES;
[presentingViewController presentModalViewController:mmvc
animated:YES];
}
First we check the status of gameCenterAvailable. We can’t do anything if game center isn’t connected, so in that case we bail.
If we’re connected, then we set up a GKMatchRequest. This object is the same as we would use for any multiplayer game center game. We are setting the minimum and maximum players for the request. It will control the GKTurnBasedViewController, not allowing us to include more than our max players or less than our min players.
We’re going to let up to 12 players play a game of SpinningYarn at a time. Because the game isn’t live, the amount of data and bandwidth required for a turn-based game is less intensive and so it’s easier to have many players in a game. 4 players is the maximum for a live multiplayer game, but the turn-based game can support up to 16!
We then create a new GKTurnBasedMatchmakerViewController, passing in the GKMatchRequest. We set the delegate of that object to self (GCTurnBasedMatchHelper). This will throw an error which we’ll fix soon.
Then we set the showExistingMatches property to YES. This property controls what’s presented to the user. If we set it to YES then we’ll see all the matches we have been involved in. This includes current matches where it’s the player’s turn, matches where it’s some other player’s turn, and matches that have ended.
There’s a ‘+’ button on the top right that can be used to create a new game. This presents a view that starts with the minimum number of players, and we can add players until we reach the specified max. Each slot can be filled with an invitation to a specific player, or can be an automatch slot. If we set the showExistingMatches property to NO, then we’ll be presented only with the create new game view.
Almost done – we just need to call this new method. Open ViewController.h and import the helper’s header at the top of the file:
#import "GCTurnBasedMatchHelper.h"
Then switch to ViewController.m and implement presentGCTurnViewController as follows:
- (IBAction)presentGCTurnViewController:(id)sender {
[[GCTurnBasedMatchHelper sharedInstance]
findMatchWithMinPlayers:2 maxPlayers:12 viewController:self];
}
If you build and run now you’ll see the GKTurnBasedMatchmakerViewController presented when you tap the game center button:
Of course, if you try to create a match or do anything else, the game will crash, because we haven’t implemented the delegate methods yet! So let’s fix that next.
Implementing the Matchmaker View Controller Delegate
The first step is to open GCTurnBasedMatchHelper.h and modify the @interface as follows:
@interface GCTurnBasedMatchHelper : NSObject
<GKTurnBasedMatchmakerViewControllerDelegate> {
Here we simply mark our helper class as implementing the delegate protocol for the matchmaker view controller.
Next, switch to GCTurnBasedMatchHelper.m and add some placeholder implementations of the protocol at the end of the file:
#pragma mark GKTurnBasedMatchmakerViewControllerDelegate
-(void)turnBasedMatchmakerViewController:
(GKTurnBasedMatchmakerViewController *)viewController
didFindMatch:(GKTurnBasedMatch *)match {
[presentingViewController
dismissModalViewControllerAnimated:YES];
NSLog(@"did find match, %@", match);
}
-(void)turnBasedMatchmakerViewControllerWasCancelled:
(GKTurnBasedMatchmakerViewController *)viewController {
[presentingViewController
dismissModalViewControllerAnimated:YES];
NSLog(@"has cancelled");
}
-(void)turnBasedMatchmakerViewController:
(GKTurnBasedMatchmakerViewController *)viewController
didFailWithError:(NSError *)error {
[presentingViewController
dismissModalViewControllerAnimated:YES];
NSLog(@"Error finding match: %@", error.localizedDescription);
}
-(void)turnBasedMatchmakerViewController:
(GKTurnBasedMatchmakerViewController *)viewController
playerQuitForMatch:(GKTurnBasedMatch *)match {
NSLog(@"playerquitforMatch, %@, %@",
match, match.currentParticipant);
}
@end
The first method (didFindMatch) is fired when the user selects a match from the list of matches. This match could be one where it’s currently our player’s turn, where it’s another player’s turn, or where the match has ended.
The second method (wasCancelled) will fire when the cancel button is clicked.
The third method (didFail) fires when there’s an error. This could occur because we’ve lost connectivity or for a variety of other reasons.
The final method (playerQuitForMatch) method is fired when a player swipes a match (while it’s their turn) and quits it. Swiping a match will reveal a quit (if it’s a match that is still active) or remove button. If a player quits a match while it’s still their turn, they need to handle the match, update it’s state, and pass it along to the next player. If a player were to quit without passing the turn on to the next player, the match would not be able to progress forward!
A match that is finished will stay on Apple’s servers and can be viewed by players that participated in it. If one player removes the match, it will no longer show up in that player’s list of matches. However, because there are multiple players involved in a match, that match data still persists on the Game Center servers until all players have removed it.
For now, or each of these methods we’re just dismissing the view controller and logging out some information. An exception is the playerQuit method, where we don’t dismiss the view controller, because the user might want to keep doing something else.
Build and run now. Start a new match with an auto-matched player and you should have a log that looks like the following:
Note how the view controller dismisses immediately after you start a new match, even though it couldn’t possibly have found a player to join your game yet! If you look at the logs, you’ll see one of the GKTurnBasedParticipants is yourself (the local player) and the second has an id of null (it hasn’t found a partner for you yet).
Keep playing around to see if you can get the other log messages to appear. If you press the cancel button, or swipe a started match, you should see the cancelled or player quit messages, and if you disconnect your network and try to start a match you’ll see the did fail message.
Congratulations, you have successfully created a turn-based match between two devices!
Take a well-deserved breather for now, and in the next tutorial we’ll add the fun part – sending the turns and completing our simple turn-based game!