Beginning Turn Based Gaming with iOS 5 Part 2(转载)

原文地址:http://www.raywenderlich.com/5509/beginning-turn-based-gaming-with-ios-5-part-2

 

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:


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.

Taking Turns

There are several ways that we can take a turn in our app. When we use automatch for a slot in our game, one of two things will happen. Either

  1. We’ll get back a new match, with our player as the first participant, or
  2. We’ll get back an existing match where our player has been placed in a second, third, fourth, etc slot in an existing match.

In both scenarios, didFindMatch will be called. We’ll need to write some code to distinguish between the two cases, because we want different things to happen in each case:

  1. If we get back a new match, we want to create a clean slate for our story. In our app, we’ll use the string “Once upon a time . . . “ every time we begin a new story.
  2. If we get back an existing match, then the match.matchData object will be populated with NSData with the story so far. Instead of the starter text, we want to show this in our text view.

Each participant has a lastTurnDate property that is null until that participant takes their first turn. We’re going to use the last turn property of the first participant in the participants array to determine if we are the first turn, or if another player has started the match. If we find that lastTurn is null, we’ll assume that we’re dealing with a new match, otherwise we’ll assume that we already have matchData that we’ll be dealing with.

So open up GCTurnBasedMatchHelper.m and replace the didFindMatch method as follows:

Beginning <wbr>Turn <wbr>Based <wbr>Gaming <wbr>with <wbr>iOS <wbr>5 <wbr>Part <wbr>2(转载)

This code should be easy to comprehend. We’re getting the participant at the first index in our participants array, then testing to see if the lastTurnDate is populated. If it is, we know we’re entering a match that has already started. If not, we know it’s a new match and we are logging the case either way.

At this point, you’ll need a second device or to switch between sandboxed game center accounts in order to get the existing match scenario. A single account/player can only take the first turn, after that you need a second player involved to test many of these scenarios.

So run the app on both devices (run one of them in the debugger so you can see its log messages). Join a few matches and take your turn on each device, watching what shows up in your log. You should see some new matches, and hopefully some existing matches too, which proves the match-making worked!

Note that as of this writing this tutorial, the time between creating a new automatch and being able to jump in to the second player position can be up to five minutes. This will probably get much faster by the time you are reading it, but don’t be alarmed if you start an automatch on one device and immediately on a second device and instead of putting the second player into the first player’s game, it creates another new match for the second player.

One more word about automatch while we’re on the subject. Automatch doesn’t start matching until the first player is finished taking his/her turn. This is true for an invited slot as well. If you start a game with three players, the third player won’t be invited or automatched until after the first and second player have both taken their turn.

Implementing Our Own Delegate Protocol

Now is a good time to introduce our new delegate protocol. We are going to build a protocol to manage the communication between the GCTurnBasedMatchHelper class and our ViewController. This is better than hard-coding the ViewController into the GCTurnBasedHelper, because it will allow us to more easily reuse this class.

The GCTurnBasedMatchHelper will do some of the work, like distinguishing between a new and existing match, but will then then pass the match through to our ViewController class to handle what do for each case, because that’s particular to the game logic.

Lets go ahead and build the delegate protocol now. Modify GCTurnBasedMatchHelper.h to look like the following (notice the new protocol, and delegate instance variable and property):

Beginning <wbr>Turn <wbr>Based <wbr>Gaming <wbr>with <wbr>iOS <wbr>5 <wbr>Part <wbr>2(转载)

Also before we forget, switch to GCTurnBasedMatchHelper.m and synthesise the delegate as follows:

@synthesize delegate;

We’ve added the five protocol method declarations and a new instance variable, delegate. The delegate object will be sent the the methods, and it will be up to that delegate (in our case the ViewController class) to implement them.

Let’s quickly go through them now. Then later when we implement them we’ll explain them in more detail.

  1. enterNewGame. The first method we’ve already discussed the use for. When we are presented with a new game from the didFindMatch method, we want to display the “Once upon a time” starter text to the screen.
  2. layoutMatch. The layoutMatch method is used when we want to view a match where it’s another player’s turn (just to check the state of the story for example). We want to prevent the player from sending a turn in this case, but we still want to update the UI to reflect the most current state of the match.
  3. takeTurn. The takeTurn method is for those cases when it is our player’s turn, but it’s an existing match. This scenario exists when our player chooses an existing match from the GKTurnBasedMatchmakerViewController, or when a new turn notification comes in. We’ll talk about notifications a little later in this tutorial.
  4. recieveEndGame. The receiveEndGame method will be called when a match has ended on our player’s turn, or when we receive a notification that has a match has ended on another player’s turn. For this simple game, we’ll just end the game when we are getting close to the current NSData turn-based game size limit (4096 bytes).
  5. sendNotice. The sendNotice method happens when we receive an event (update turn, end game) on a match that isn’t one we’re currently looking at. If we receive an end game notice on a match that we’ve got loaded into our currentMatch variable, we’ll update the UI to reflect the current state of that match, but if we receive the same notice on a match other than the one we’re looking at, we don’t want to automatically throw the user into that match, taking them away from the match they are currently looking at. We’ll decide later how to handle those notices.
Let’s go ahead and send the delegate methods in our didFindMatch method for our new match and existing match scenarios. Replace the NSLog methods with calls to the delegate methods, like so:

Beginning <wbr>Turn <wbr>Based <wbr>Gaming <wbr>with <wbr>iOS <wbr>5 <wbr>Part <wbr>2(转载)

Next, open up ViewController.h and mark it as implementing our new protocol:

Beginning <wbr>Turn <wbr>Based <wbr>Gaming <wbr>with <wbr>iOS <wbr>5 <wbr>Part <wbr>2(转载)

Then switch to ViewController.m and implement the enterNewGame and takeTurn methods:

Beginning <wbr>Turn <wbr>Based <wbr>Gaming <wbr>with <wbr>iOS <wbr>5 <wbr>Part <wbr>2(转载)

Pretty simple, eh?

One last thing, we need to set the delegate property of the GCTurnBasedMatchHelper class to our ViewController. Let’s do that in the viewDidLoad method, like so:

[GCTurnBasedMatchHelper sharedInstance].delegate = self;

Build and run on both devices, and you should be able to pass turns around!

Start a new game, either by invitation or automatch, take the first turn, give it a few minutes to make sure the server is updated, then enter that game from the other device. If you have created participants by invitation you should have a game waiting in the your turn section, if done by automatch create another automatch game on the other device with the same number of players. Again, the automatch won’t always put you into the match you want, it does create new matches frequently.

Note that after the other side takes a turn, your screen won’t update because we haven’t added the code in for that. You can get the game to recognize it’s your turn by tapping the game center button, and selecting the game.

Too many matches? At this point I have about five matches that have wrong data and other problems with them. Some of your old games may act wrong because the data in them is incomplete or missing. I’d remove all of them and start fresh. A good way to clean out all this data is to call a method that programmatically deletes all the matches for a user.

Put this code into the completion block for authenticateWithCompletionHandler like so:

Beginning <wbr>Turn <wbr>Based <wbr>Gaming <wbr>with <wbr>iOS <wbr>5 <wbr>Part <wbr>2(转载)

This code will only clear out the matches for one Game Center account, so you’ll have to run it on both devices. Also, remember when you have this code in it will clear all your matches on startup, so make sure to comment it out when you don’t need it.

Received a turn based game from Game Center

What To Do When It’s Not Our Turn

Currently we have the ability to input text and run the game while it’s not our turn. While the API prevents us from updating the game state outside our turn, our app will throw errors and it would be better to indicate to the player when they are unable to enter text.

When it’s not the current player’s turn, we want to update a status label telling the player that the match is currently in another player’s turn. Also, we should disable the text field.

Open up ViewController.xib, drag a label next to to the Game Center icon, and make it as wide as the screen. Bring up the Assistant Editor, make sure ViewController.h is visible, control-drag from the label down inside the @interface and, connect it to an outlet named statusLabel.

Adding a status label into the view controller

We’ll need to make some changes in both the GCTurnBasedMatchHelper class and the ViewController class in order keep track of whose turn it is. Let’s start by editing our didFindMatch method in GCTurnBasedMatchHelper.m:

Beginning <wbr>Turn <wbr>Based <wbr>Gaming <wbr>with <wbr>iOS <wbr>5 <wbr>Part <wbr>2(转载)

Note we swapped the if/else statement around a bit here.

We’re checking the current player’s (from the match) playerID against the currently player that’s logged into game center. If they match, it’s our player’s turn. In that case we send the same method. However, if they don’t match then it’s not the current player’s turn (this can happen when it’s someone else’s turn, or when it’s no one’s turn, because the match has ended).

If it’s not our player’s turn, then we’re going to send a different method, the layoutMatch method. This just updates the UI to reflect the current state of the match. In our app, we’ll be doing this a lot, we’ll want the player to be able to watch as the story progresses.

Here’s the implementation for the layoutMatch method. This code should go in ViewController.m:

Beginning <wbr>Turn <wbr>Based <wbr>Gaming <wbr>with <wbr>iOS <wbr>5 <wbr>Part <wbr>2(转载)

The first thing we’re doing in this method is constructing the string we’ll put in the statusLabel. We need to distinguish between open and closed matches first. We check the GKTurnBasedMatchStatus match.status – if it’s equal to ended, then we have and ended game and we set the statusString to tell the user that.

If we currently waiting on another player, we want to get the position of the player in the array. We’ll add one so we don’t have a Player 0. We construct the string for the player’s turn and set the label to that string.

Next, we are disabling the textInputField so that our player won’t have the ability to enter text. Finally, as we have before, we update the mainTextController to hold the body of the story.

Let’s go back and make a few edits to our other two methods to incorporate the new label and the logic that will turn on the text field. Add this code:

Beginning <wbr>Turn <wbr>Based <wbr>Gaming <wbr>with <wbr>iOS <wbr>5 <wbr>Part <wbr>2(转载)

This code is very similar, except we’ve added some code to enable the text input field and display the status.

A few other things we need to do, Change the properties on the statusLabel so that it’s in word wrap mode and has 2 lines (and make it a bit taller).

Also in the viewDidLoad method, let’s set the statusLabel to something like, “Press the game center button to get started” and disable the textInputField:

Beginning <wbr>Turn <wbr>Based <wbr>Gaming <wbr>with <wbr>iOS <wbr>5 <wbr>Part <wbr>2(转载)

Also note you still have to go back into Game Center and re-select a game to get updates, but we’re one step closer to a functional game!

Taking a turn in our game

Finishing Off the Matchmaker View Controller Delegate Methods

We’re finished with the didFindMatch method. But, we still have to do some minor finishing of the other delegate methods.

The didCancel method only needs to dismiss the view controller, so it’s fine as is. The error method is also satisfactory as is, in a polished implementation we’d want to handle the various errors in a more elegant way, but for our purpose here, logging the error is fine.

But we do have to change the playerDidQuit method, so update it as follows in GCTurnBasedMatchHelper.m:

Beginning <wbr>Turn <wbr>Based <wbr>Gaming <wbr>with <wbr>iOS <wbr>5 <wbr>Part <wbr>2(转载)

If the player currently holds the baton and quits a match, that match is stuck, because only the current player can submit a turn, and a next player, and that player has quit. So when the player quits during their turn, we need to hand off the baton for them. That’s what this method does.

This method is called when we quit a game from the view controller and it’s our turn. If it’s not our turn and we quit, then another method, playerQuitOutOfTurn, is called for us and all that is dealt with automatically.

In this case we’re iterating through the list of participants and looking for a participant who doesn’t have a matchOutcome of GKTurnBasedMatchOutcomeQuit. We don’t want to pass the match to a player who has quit. If we try to give the match to a player who has quit we’ll get an error and that turn won’t be recorded.

When we find the next participant in the array that doesn’t have a quit status, we call participantQuitInMatchWithOutcome:nextParticipant:matchData:completionHandler: which assigns an outcome to the quitting player (in this case, quit) passes the match to the next player, and end the turn.

In this game, we don’t need to do anything with the matchData, but pass it on. In other scenarios, the game may require something to be done to the game state before it can be passed on.

While we’re fixing this, we should make some of the same changes to our sendTurn method. In a case like this one, we want to iterate through the participants and make sure the one we’re passing the match to hasn’t quit. In fact, if you build and run now, start a match with three players (in a two player game if one quits the game ends), go around a few times, then have a player quit, then try to pass the quit player the match, you’ll see this:

Current turn isn't as expected error

So change the sendTurn method in ViewController.m to this:

Beginning <wbr>Turn <wbr>Based <wbr>Gaming <wbr>with <wbr>iOS <wbr>5 <wbr>Part <wbr>2(转载)
Beginning <wbr>Turn <wbr>Based <wbr>Gaming <wbr>with <wbr>iOS <wbr>5 <wbr>Part <wbr>2(转载)

First we add the code that runs through all the participants, the first time it finds one where they haven’t quit (usually this will be the first iteration in the loop) it breaks out of the loop. This way we skip over participants who have quit.

The other thing we added here was two bits of unrelated code. First, we update the status if there was an error or if there wasn’t. Second, if the turn was send without problem, we disable the textInputField so that another turn cannot be sent immediately to that game.

If you build and run now, you should see the status update when you send a turn!

Updating the status label when the turn is complete

 

Event Handler Delegate

Our game is coming along well so far, but there’s one major problem – we never get updated when the other players take their turn! It’s quite annoying having to constantly check by bringing up the Game Center UI.

As you’ve been playing with the app, you may have noticed we sometimes get badges and/or system notifications of new turns/invitations to your game. This is being done by the GKTurnBasedEventHandler object. This object sends notifications to and badges our app when certain events happen, like when it’s our player’s turn.

There are three delegate callbacks that give our app a way to deal with these notices as they come in. One is the method that gets called if you starts an invite for that game from within the game center app, one when the turn advances (even if it’s not our turn, there’s a callback every time the match changes hands), and one is fired when the game ends.

In order to receive and handle these events, we first need to set ourselves as the delegate of the GKTurnBasedEventHandler. This object is a singleton and the only time we deal with it directly is when we set ourselves as it’s delegate.

Like the view controller delegate protocol, we’re going to be using our GCTurnBasedMatchHelper class to act as an intermediary for all the communication from these notices. So, that’s what we need to set up as the delegate. We have to set the delegate after we have logged in to game center or it may not work. Change the authenticateUser code to the following:

Beginning <wbr>Turn <wbr>Based <wbr>Gaming <wbr>with <wbr>iOS <wbr>5 <wbr>Part <wbr>2(转载)

You can see here that I’m setting up a block (we do this so we can pass it into the completionHandler of the authenticate method). The block just gets a pointer to the singleton and uses the pointer to set the delegate to self. Simple.

Then we pass that in as the completionHandler parameter in the case where we need to authenticate. If we don’t need to authenticate then we just call the block.

The block takes an NSError parameter if it’s run by the completionHandler. If we call it directly we can just enter nil for the error (because the error would have been coming from any problem with the authenticate method, we didn’t run it).

Alright, we’re set up to receive callbacks from the GKTurnBasedEventHandlerDelegate, well almost. We also need to set our object as a GKTurnBasedEventHandlerDelegate and implement the methods. Do that now:

In GCTurnBasedMatchHelper.h, change the @interface line to:

Beginning <wbr>Turn <wbr>Based <wbr>Gaming <wbr>with <wbr>iOS <wbr>5 <wbr>Part <wbr>2(转载)

And add the following code to GCTurnBasedMatchHelper.m:

Beginning <wbr>Turn <wbr>Based <wbr>Gaming <wbr>with <wbr>iOS <wbr>5 <wbr>Part <wbr>2(转载)

Build and run now. You should be able to test the handleTurn event by letting the other player take a turn, and you should see the log message. w00t!

The handleMatchEnded will require us to write a method that ends the game. The handleInviteFromGameCenter is only fired when you start a game from inside the game center app.

If you send an invite from game center, the callback needs to instantiate a new GKMatchRequest and either programmatically or with the view controller (GKTurnBasedMatchmakerViewController) set up the new match. Invites sent from within the app won’t need to call this method.

Here’s an output to the console for the handleTurn event:

Console output demonstrating handleTurn is called

Handling Invitations

Let’s write handleInviteFromGameCenter next. You may assume erroneously at first, as I did, that this method fires whenever we receive a named invite to a game. This is not what the method is for at all!

There is no method for that, an invite sent from within a game just shows up in your list of available matches. This method handles the incoming data from game center when you create an invite for one of your friends for the game. So, when you switch from game center to the game, there’s information about who you want to invite to a new game included in the callback (playersToInvite). This is called on the inviting player’s game, not the invitee. I include this personal mistake here because I’m not the only one who was confused.

If we get a new invite from game center, we need to instantiate the GKTurnBasedMatchmakerViewController with a GKMatchRequest. This method will give us an array of players that are supposed to be in the match. We’ll use this object to set up the GKMatchRequest. Here’s what that code should look like:

Beginning <wbr>Turn <wbr>Based <wbr>Gaming <wbr>with <wbr>iOS <wbr>5 <wbr>Part <wbr>2(转载)

The first thing we do is get rid of any current modal view controller that is present. After that we set up the GKMatchRequest and then the GKTurnBasedMatchmakerViewController. Note that the showExistingMatches is set to NO. We only want to see the new game view for this match. We set up the delegate and then present our view controller.

If you build and run now you should be able to start a match from the Game Center (it won’t call this method if you do an invite from inside our game) and send the invite. One thing to note, the simulator doesn’t receive any notifications from the GKTurnBasedEventHandlerDelegate, so you’ll have to test this on a device.

Inviting friends in Game Center

Handling the Turn Event

When the handleTurn is called, either the match has moved from one player to another, and it’s still not our turn, or the turn has moved to our player. In addition, the match that’s currently loaded into the game state, may or may not be the match that has received the handleTurn call. We need to distinguish between these scenarios and handle each in turn.

Here’s the code:

Beginning <wbr>Turn <wbr>Based <wbr>Gaming <wbr>with <wbr>iOS <wbr>5 <wbr>Part <wbr>2(转载)

We end up with four scenarios. We’ll send delegate methods for three of them, the fourth we’ll ignore, but we’ve set it up here in case you wish to handle it in another game.

The first two are that the current match is the same as the match we’re in. In that case we’ll send takeTurn, if it’s our turn, and layoutMatch if it’s not. We’re still setting the currentMatch to our passed in match, because even though the matchID is the same, the incoming match has updated state data (match.matchData) and the currentParticipant has changed.

If we are sent a notice for a match that we’re not looking at, and it has become our turn, we’ll send the sendNotice delegate method. We’ll use this method to display an alert letting the user know.

If the turns change on matches that we’re not looking at, and it’s not our turn, we’ll do nothing. The users can go looking at those matches by loading them using the GKTurnBasedMatchmakerViewController, we don’t need to interrupt them every time things change on every match. In other kinds of games, we may want to do just that, so that section is available to you.

With the handleTurn method in place, you can now run the game. Each time a new turn is sent, you should see the UI on your game update and the statusLabel should let you know who’s turn it is!

Status label showing the current player's turn

Depending on what the state of your game is, you might get an error saying the sendNotice callback isn’t implemented yet. That’s our next step anyway, so let’s go ahead and implement the sendNotice method in ViewController.m.

Beginning <wbr>Turn <wbr>Based <wbr>Gaming <wbr>with <wbr>iOS <wbr>5 <wbr>Part <wbr>2(转载)

This is pretty straightforward. We’re just letting them know that another match needs their attention. We’ll let them use the GKTurnBasedMatchmakerViewController to load the match when they are ready. You should be able to get this alert if you are playing multiple games:

Showing an alert view when another game is ready

Ending the Game

We’ve really only got one thing left to accomplish, and that’s ending the game. But, we probably also want to give our users some advance notice that they only have a certain number of turns left.

We’ll do this with a new method that checks the length of the NSData. We’ll end the game when it gets to above 3800 characters, but let’s start letting our players know when the game gets to about 3000 characters.

This new method will be called each time a match is loaded, so we’ll put it in our takeTurn method and our layoutMatch method. If the match is getting close to being over, this method will add some information to our statusLabel, saying, there’s only about 200 characters left.

Add this method to ViewController.m right after dealloc:

Beginning <wbr>Turn <wbr>Based <wbr>Gaming <wbr>with <wbr>iOS <wbr>5 <wbr>Part <wbr>2(转载)

Also call this method at the end of layoutMatch and takeTurn:

[self checkForEnding:match.matchData];

Go ahead an build and run, you should get something like this (after you have written a bunch of stuff).

Ending game based on character count

 

What we’ll do is end the game whenever the total character count exceeds 3800. The reason is that we don’t want the possibility that the NSData string will be larger than 4096, because Game Center won’t take the endTurn if the matchData is too large.

So, in modify the sendTurn one last time to the following:

Beginning <wbr>Turn <wbr>Based <wbr>Gaming <wbr>with <wbr>iOS <wbr>5 <wbr>Part <wbr>2(转载)
Beginning <wbr>Turn <wbr>Based <wbr>Gaming <wbr>with <wbr>iOS <wbr>5 <wbr>Part <wbr>2(转载)

We’re just wrapping the current endTurn call in an if statement. If we are above 3800 characters, instead of calling endTurn, we’ll call endMatch. Once we call end game that notification we’ll be sent to all the other players in the handleMatchEnded notification.

We’ll deal with that in a second, but let’s give our end game a whirl. Make sure your handleEndMatch notice still has a log statement in it, and hopefully you’ve still got your last game around (didn’t it take forever to write 3000 characters?).

You should be able to get this:

A game that has ended

Alright, end in sight. Now we just need to handle the handleMatchEnded in GCTurnBasedMatchHelper.m:

Beginning <wbr>Turn <wbr>Based <wbr>Gaming <wbr>with <wbr>iOS <wbr>5 <wbr>Part <wbr>2(转载)
If we’re looking at another match we’ll just send the notice, that spawns the UIAlert, otherwise we’ll send recieveEndGame. Let’s implement that as well in ViewController.m:

Beginning <wbr>Turn <wbr>Based <wbr>Gaming <wbr>with <wbr>iOS <wbr>5 <wbr>Part <wbr>2(转载)

We could do something extra in this case, but because we’re setting the statusLabel in layoutMatch this should suffice. However, should we decide later to add something to an endGame notice, like email our story or invite the same group to play again, we could do that here.

Here’s what it looks like if you get a game ended notice in while the device is locked:

A system notice when a turn based game ends

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值