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

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

 

In iOS5, Game Center has a new API that makes it even easier to create another type of game – turn-based games!

This new API is perfect for board games, turn based strategy, word games, and other types of casual turn based games. You can take a turn in your game, wait for your friend to take his turn, and then get notified when it’s your turn again!

 

Turn Based Gaming Overview

In a turn based game, only one player can affect the game state at a time. This player will hold the baton, or the game state. They will take a turn, which will change the game state, then pass the turn on with the new game state.

However, other players will have ability to observe matches in between their turns. Because the games, or matches, don’t require our constant attention, but can be visited, played, and the we can do other things while we wait, we can be in the middle of many games at once. Because of this, in our game we’ll give the players the ability to switch between the matches they’re currently in.

Here are the major classes in the Turn Based Gaming API, which we’ll be covering in detail in this tutorial:

  • GKTurnBasedMatch: Contains all the information and game state for a match. We’ll use this object to encapsulate the match players, the match game state, and the important information about who holds the turn and who’s still playing.
  • GKTurnBasedMatchmakerViewController: This will be our primary UI element for interacting with matches, switching between matches, and creating new matches. We’ll use it as our command center.
  • GKTurnBasedEventHandlerDelegate: We will make a helper class implement this protocol, so we can get notifications when the turn moves from player to player, when we are invited to a new match, or when the game ends.

Note that the Game Center app will automatically keep track of who we are playing with and other data about our game, so users can always switch to Game Center to see their game status.

The SpinningYarn Game

If you harken back to your days in grade school, you may remember a writing exercise where each child started writing a story. After a certain period, you passed your paper to your neighbor and he gave you his. You read what he wrote and continued the story. This continued back and forth until you ended up with a story, often with hilarious results!

This is the turn-based game we’ll be making in this tutorial. I’ve made a starter project that contains the UI already made, so we can keep the focus mainly on the Turn Based Gaming APIs.

So go ahead and download the resources for this tutorial, and you’ll find a starter project inside. Open it up in Xcode and run it. You should see the following UI:

Turn Based Gaming Starter Project

Right now this project just contains a text view displaying some sample text, and a text field at the bottom of the screen that you can enter text into. Note it doesn’t actually do anything yet – it’s just placeholder code for now. The app also has a pretty paper background (thanks to playingwithbrushes on Flickr!)

Feel free to look at ViewController.xib to see how the UI is arranged, and take a look at ViewController.m to see the code (it’s very simple at this point). We’ll convert the project into a fully functional game from here!

Setting up Game Center

Before you can start writing any Game Center code, you need to do two things:

  1. Create and set an App ID
  2. Register your app in iTunes Connect

Let’s go through each of these in turn.

Create and Set an App ID

The first step is to create and set an App ID. To do this, log onto the iOS Dev Center, and from there log onto the iOS Provisioning Portal.

From there, select the App IDs tab, and create a new App ID for your app, similar to the following (except you’ll be choosing different values):

Creating a new App ID in the iOS Provisioning Portal

The most important part is the Bundle Identifier – you need to set this to a unique string (so it can’t be the same as the one I used!) It’s usually good practice to use a domain name you control followed by a unique string to avoid name collisions.

Once you’re done, click Submit. Then open the SpinningYarn Xcode project, select the spinningyarn target, and in the Summary tab set your Bundle identifier to whatever you entered in the iOS Provisioning portal, as shown below (except you’ll be entering a different value):

Setting the bundle identifier in Xcode

One last thing. Xcode sometimes gets confused when you change your bundle identifier mid-project, so to make sure everything’s dandy take the following steps:

  • Delete any copies of the app currently on your simulator or device
  • Quit your simulator if it’s running
  • Do a clean build with Project\Clean

Congrats – now you have an App ID for your app, and your app is set up to use it! Next you can register your app with iTunes Connect and enable Game Center.

Register your app in iTunes Connect

The next step is to log on to iTunes Connect and create a new entry for your app.

Once you’re logged onto iTunes Connect, select Manage Your Applications, and then click the blue “Add New App” button in the upper left.

On the first screen, enter Spinning Yarn for the App Name, 311 for SKU Number, and select the bundle ID you created earlier, similar to the screenshot below:

Creating a new App in iTunes

Click continue, and follow the prompts to set up some basic information about your app. Note you will probably have to change the name, since I’ve already taken the Spinning Yarn name :]

Don’t worry about the exact values to put in, since it doesn’t really matter and you can change any of this later – you just need to put something (including a dummy icon and screenshot) in to make iTunes Connect happy.

When you’re done, click Save, and if all works well you should be in the “Prepare for Upload” stage and will see a screen like this:

App in Ready to Upload Stage

Click the blue “Manage Game Center” button to the upper right, click the big blue “Enable” button, and click “Done”. That’s it – Game Center is enabled for your app, and you’re ready to write some code!

By the way – inside the “Manage Game Center” section, you might have noticed some options to set up Leaderboards or Achievements. We won’t be using those in this book, but if you ever need them that’s where they are!

 

Authenticate the Local Player: Strategy

When your game starts up, the first thing you need to do is authenticate the local player.

You can think of this as “logging the player into Game Center.” If he’s already logged in, it will say “Welcome back!” Otherwise, it will ask for the player’s username and password.

Authenticating the local user is easy – you just call authenticateWithCompletionHandler. You can optionally pass in a block of code that will be called once the user is authenticated.

But there’s a trick. There’s another way for the user to log in (or log out!). He can be using your app, switch to the Game Center app, log or out from there, and switch back to your app.

So your app needs to know whenever the authentication status changes. You can find out about these by registering for an “authentication changed” notification.

So, our strategy to authenticate the player will be as follows:

  • Create a singleton object to keep all the Game Center code in one spot.
  • When the singleton object starts up, it will register for the “authentication changed” notification.
  • The game will call a method on the singleton object to authenticate the user.
  • Whenever the user is authenticated (or logs out), the “authentication changed” callback will be called.
  • The callback will keep track of whether the user is currently authenticated, for use later.

Now that you’re armed with this plan, let’s try it out!

Authenticate the Local User: Implementation

In the SpinningYarn Xcode project, create a new file with the Objective-C class template. Name the class GCTurnBasedMatchHelper and make it a subclass of NSObject.

Then replace GCTurnBasedMatchHelper.h with the following:

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

 

This imports the GameKit header file, and then creates an object with two booleans – one to keep track of if game center is available on this device, and one to keep track of whether the user is currently authenticated.

It also creates a property so the game can tell if game center is available, a static method to retrieve the singleton instance of this class, and another method to authenticate the local user (which will be called when the app starts up).

Next switch to GCTurnBasedMatchHelper.m and add the following right inside the @implementation:

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

This synthesizes the gameCenterAvailable property, then defines the method to create the singleton instance of this class.

Note there are many ways of writing singleton methods, but this is the simplest way when you don’t have to worry about multiple threads trying to initialize the singleton at the same time.

Next add the following method right after the sharedInstance method:

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

This method is straight from Apple’s Game Kit Programming Guide. It’s the way to check if Game Kit is available on the current device.

By making sure Game Kit is available before using it, this app can still run on iOS 4.0 or earlier (just without network capabilities).

Next add the following right after the isGameCenterAvailable method:

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

The init method checks to see if Game Center is available, and if so registers for the “authentication changed” notification. It’s important that the app registers for this notification before attempting to authenticate the user, so that it’s called when the authentication completes.

The authenticationChanged callback is very simple at this point – it checks to see whether the change was due to the user being authenticate or deauthenticated, and updates a status flag accordingly.

Note that in practice this might be called several times in a row for authentication or deauthentication, so by making sure the userAuthenticated flag is different than the current status, it only logs if there’s a change since last time.

Finally, add the method to authenticate the local user right after the authenticationChanged method:

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

This calls the authenticateWithCompletionHandler method mentioned earlier to tell Game Kit to authenticate the user. Note it doesn’t pass in a completion handler. Since you’ve already registered for the “authentication changed” notification it’s not necessary.

OK – GCTurnBasedMatchHelper now contains all of the code necessary to authenticate the user, so you just have to use it! Switch to AppDelegate.m and make the following changes:

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

This creates the Singleton instance (which registers for the “authentication changed” callback as part of initialization), then calls the authenticateLocalUser method.

Usually you’d have to add the Game Kit framework to your project as well, but I’ve already added this for you in the Build Phases\Link Binary with Libraries section of your target settings.

That’s it! Compile and run your project, and if you’re logged into Game Center you should see something like the following:

Welcome Back from Game Center

 

Turn Based Gaming Basics

Now that we’re successfully authenticating with Game Center and have a starter project ready, we’re ready to start talking about the meat of this tutorial: Turn Based Gaming.

In a turn based game, you don’t need to play at the same time as our opponents (although you can be). For example, you can take your turn while your friend is asleep, and then they can wake up, take their turn while you’re showering, and so on. A player can be in the middle of playing many of these asynchronous matches at the same time.

Visualize control of the game as a baton in a relay race. Only one player can hold the baton (or take a turn) at a time. When the baton is passed, it needs to contain everything that the player needs to know about that game.

To understand more about how it works, let’s start by reviewing the Turn Based Gaming classes in more detail.

 

GKTurnBasedMatch

This class stores information about an individual match, such as:

  • creationDate: The date that the match was first created.
    currentParticipant: The GKTurnBasedParticipant who currently holds the baton (his/her turn). More on this below.
  • matchID: An NSString uniquely identifying the match. This is typically long and not easily readable.
  • message: An NSString to be displayed to help the user identify the match in the GKTurnBasedMatchmakerViewController. You can set this to whatever you want.
  • participants: An NSArray of all GKTurnBasedParticipants who are included in the match (includes those who have quit).
  • status: The current state of the match, as an GKTurnBasedMatchStatus. Includes values like Open, Ended, Matching, etc.

 

GKTurnBasedParticipant

This class stores information about an individual player, such as:

  • playerID: An NSString unique identifier about the player, never changes. This is not the same as the user’s Game Center nickname, and you should usually not display this because it isn’t easily readable.
  • lastTurnDate: An NSDate of last turn. This is null until the player has taken a turn.
  • matchOutcome: The outcome of the match as a GKTurnBasedMatchOutcome. Includes values such as Won, Lost, Tied, 3rd etc.
    status: The current state of the player, as a GKTurnBasedParticipantStatus. Includes values like Invited, Declined, Active, Done, etc.

 

GKTurnBasedMatchmakerViewController

This is the standard user interface written by Apple to help players work with turn-based gaming matches. It allows players to:

  • Create matches. You can use this view controller to create matches, either by auto match or by invitation. When you create a new match, you get to play the first turn right away (even if the system hasn’t found an auto match partner yet!) When the system has found someone and they take their turn, you’ll get a notification again. Note that there is currently no programmatic was to create new matches except by using this controller.
  • Switch matches. As discussed earlier, you can have many turn-based games going on at once. You can use this view controller to view different games you’re playing – even if it’s not your turn or the game is over (you can view the current game state in that case).
  • Quit matches. Finally, you can use the view controller to quit from a match you no longer want to play.

 

GKMatchRequest

You use this to initialize a GKTurnBasedMatchmakerViewController, much the same way you create a match for normal (live) Game Center multiplayer games.

When you create a GKMatchRequest, you specify a minimum and maximum number of players. You can also segment players (by location, skill level, custom groups, etc.) using this object.

 

GKTurnBasedMatchmakerViewControllerDelegate

When you create a GKTurnBasedMatchmakerViewController, you can specify a delegate that implements this protocol. It provides callback methods for when the view controller loads a new match, cancels, fails due to error, etc.

 

GKTurnBasedEventHandler

Last but not least, this singleton class has a delegate protocol, GKTurnBasedEventHandlerDelegate that provides notifications when the turn passes from one player to another, when we’re invited by a friend to a match, or when the game ends.

 

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:

Adding the present method

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:

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

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:

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

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:

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

If you build and run now you’ll see the GKTurnBasedMatchmakerViewController presented when you tap the game center button:

Creating a new match in Game Center

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:

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

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:

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

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:

Console showing turn based match found

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.

Console showing player quit

Congratulations, you have successfully created a turn-based match between two devices!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值