Beginning Turn-Based Gaming with iOS 5 Part 2

Note from Ray: This is the seventh iOS 5 tutorial in the iOS 5 Feast! This tutorial is a free preview chapter from our new book iOS 5 By Tutorials. Enjoy! This is a blog post by iOS Tutorial Team member Jacob Gundersen, an indie game developer who runs the Indie Ambitions blog. Check out […] By Jake Gundersen.

Leave a rating/review
Save for later
Share

Note from Ray: This is the seventh iOS 5 tutorial in the iOS 5 Feast! This tutorial is a free preview chapter from our new book iOS 5 By Tutorials. Enjoy!

This is a blog post by iOS Tutorial Team member Jacob Gundersen, an indie game developer who runs the Indie Ambitions blog. Check out his latest app – Factor Samurai!

This is the second part of a two part tutorial series where we’ll show you how to build a simple turn-based game with the new Game Center APIs in iOS 5.

In the first part of the tutorial series, we started with the basics – getting the app set up, and creating a turn-based match.

In this second and final part of the series, we’ll get to the fun stuff. We’ll allow players to take their turns and add the extra details and polish to wrap up this game!

So advance to the next turn, and let’s wrap up this game! :]

Sending a Turn

We need to set up a method that sends a turn. When it’s our turn, we want to be able to add a string of text (max 250 characters) to the end of the current story. When we send a turn, we’ll add our text to the previous text, then we’ll send that new string with our turn.

It’s probably a good time to talk about the GKTurnBasedMatch object – remember this is passed to us in our didFindMatch callback that gets called when the user creates a new match (or joins an existing one). All of the methods that signal a new turn will also give us a GKTurnBasedMatch to work with.

As you saw in the logs earlier, this object has a participants array that contains a GKTurnBasedParticipant for each player. You can find out whose turn it is by looking at the currentParticipant property.

It also contains a matchData property which holds an NSData object of up to 4096 bytes that we’ll use to record the state of our match (the string of the story for this game), which will be passed from one player to the next.

The first thing we need to do is keep track of the current match, so we can modify the match data and have each player take their turn. So open GCTurnBasedMatchHelper.h and add the following after the @interface:

@property (retain) GKTurnBasedMatch * currentMatch;

And synthesize it in GCTurnBasedMatchHelper.m:

@synthesize currentMatch;

Let’s modify our didFinidMatch callback to set the current match to the passed in match. Just add this to the bottom of the method:

self.currentMatch = match;

Now let’s create a method to let the player take his turn (by adding a new bit of text to the story in this game). We’ll call this method when the user enters some text in the text field and hits Done on the keyboard.

Open up ViewController.xib, and bring up the Assistant Editor so ViewController.h is visible. Control-drag from the text field down below the @interface to bring up the Connection popup. Set the Connection to Action, the name to sendTurn, and click Connect.

Switch to up ViewController.m and implement the method as follows:

- (IBAction)sendTurn:(id)sender {
    GKTurnBasedMatch *currentMatch = 
      [[GCTurnBasedMatchHelper sharedInstance] currentMatch];
    NSString *newStoryString;
    if ([textInputField.text length] > 250) {
        newStoryString = [textInputField.text substringToIndex:249];
    } else {
        newStoryString = textInputField.text;
    }
    NSString *sendString = [NSString stringWithFormat:@"%@ %@", 
      mainTextController.text, newStoryString];
    NSData *data = 
      [sendString dataUsingEncoding:NSUTF8StringEncoding ];
    mainTextController.text = sendString;
    
    NSUInteger currentIndex = [currentMatch.participants 
      indexOfObject:currentMatch.currentParticipant];
    GKTurnBasedParticipant *nextParticipant;
    nextParticipant = [currentMatch.participants objectAtIndex: 
      ((currentIndex + 1) % [currentMatch.participants count ])];
    [currentMatch endTurnWithNextParticipant:nextParticipant 
      matchData:data completionHandler:^(NSError *error) {
        if (error) {
            NSLog(@"%@", error);
        }
    }];
    NSLog(@"Send Turn, %@, %@", data, nextParticipant);
    textInputField.text = @"";
    characterCountLabel.text = @"250";
    characterCountLabel.textColor = [UIColor blackColor];
}

This method is doing a whole bunch of things. Let’s step through each bit.

First we set up the currentMatch variable by retrieving the match from the GCTurnBasedMatchHelper singleton. We may be involved in many matches at a time, but we’ll only be displaying one match at a time. We’ll keep track of this one match in our currentMatch variable.

Next we need to check to see if the length of the string we input into the text field is too long. If the string is longer than 250 characters we cut it off with the substringToIndex call. If not, we just pass the string into our variable.

Next we create an NSData object by combining the string that’s in the mainTextController with the string we just created. The dataUsingEncoding method converts the NSString representation to a UTF8 string and stores it in the data object.

The next few lines set up the nextParticipant object. Each time we send a turn we need to send information about who the next person in the turn rotation is. We can set up our game to send the turn to any participant, including ourselves. We can follow a strict rotation where the order of players always follows a pattern. Or, we can set up other rules about who gets the next turn.

In our case we are retrieving the index of the current player, or the position of the currentMatch.currentParticipant property, in the currentMatch.participants array. Once we have the index of the current player, we just add one to it get that participant from the participants array.

Once we have the NSData and the nextParticipant set, we can make the endTurnWithNextParticipant:matchData:completionHandler: call. The completion handler is a block that will be called when ending the turn successfully completes (or fails). In our case we are just logging any error that occurs.

We also log out the nextParticipant and the data object. We can take a look at this to see if this is working as expected. The last action is to clear the contents of the textInputField and reset the characterCountLabel to 250 so when we load the next game, it’s not cluttered with old text.

Build and run now, and start a new match with the match controller. Type something into the text field and press done. You should see something like the following in your log:

Error message when sending a turn in the game

You’ll notice that in this log there is an error message. This is because I ran the method twice. The first time it sent fine. However, once I sent my turn to the server, it was no longer my turn.

The match is now in the status “matching” which means that it’s looking for an automatched second player. When I try and send another turn for my player, this is the error message that comes back and my new turn isn’t recorded.

Jake Gundersen

Contributors

Jake Gundersen

Author

Over 300 content creators. Join our team.