Transcript
>> Welcome to the third Game Center session.
This is Game Center Techniques, Part 2 and I'm going
to talk to you about adding multiplayer to your game.
I'm Nathan Taylor.
I'm a senior iPhone development
engineer, the Game Center team.
And we want to talk about how the facilities for multiplayer
do the hard stuff, getting people connected in terms
of network gaming so that you can
just easily take advantage of our APIs
and get your game players playing with each other.
I'm going do a quick overview of what Game Center is
and what Game Center offers and then I'm going to step
into the nitty gritty of what we do for
multiplayer to make it easy for you.
First of all Game Center is Apple's social gaming network.
It's comprised of three parts-- there's
the built-in application, Game Center app,
if you've installed the developer seed you've
seen our icon on your home screen or page 2.
It's also a framework.
The GameKit framework is where the Game Center
API lives and we have a set of online services,
our Game Center services, which
we host sort of in the cloud.
There are servers and they handle a lot of the storage
requirements for your leaderboards and your achievements
as well as all the players and then they
have the Auto-Matching and invite services
that hook your players up for multiplayer.
Game Center provides several of these facilities
here; the friend relationships, leaderboards,
achievements and the multiplayer
API that's the focus of this talk.
All of these build together combined to make a social gaming
network and then the multiplayer you know leverages that
and that leverages the friend relationships to send
friend invites and also it just helps grow the network.
If you play with somebody you'll see them on
the recently played list in the Game Center app.
And then you can make them your friend and
add them to your network for future invites.
So what you're going to learn in this session,
I'm going to show you the overview slide,
the graphic that is the block diagram that is Game
Center that you've seen before if you've been here.
But we'll focus on the area that we're going to talk about.
I'm going to give you a quick look at what we provide
in the Game Center services and then I'm going
to go in-depth on what the multiplayer services are.
I'm going to start with Authentication
because you can't do anything
in Game Center unless you've authenticated the local player,
about how to get connected through invites and Auto-Matching
and talk about the network communications that we
set up for you and you know the different types
of things you can do here and how
to be a good network citizen.
Finally we're going to get into how you can make it fun
and engaging for users beyond how great your game is
but let them talk to each other with player communications.
So this is the block diagram that is Game Center.
We have the GameKit framework in the middle in green here.
And your games and Game Center sit on top of this.
We provide the general functionality that was covered
in the previous session, which is the authentication,
friends list, leaderboards and achievements.
And then what we're going to cover today in
this session is the multiplayer functionality.
This is our Auto-Matching service, our Game Invitations,
Peer-to-Peer Networking and In-Game Voice Chat.
So the Game Center services, the servers
that we offer are there to connect people.
We use these servers to route requests to devices
and we use these to find devices that can communicate
so that we can establish global peer-to-peer communications.
So the question that came up in the overview,
and yes we do establish wide-area network
peer-to-peer communication between devices.
These services are available over WiFi and over the various
cellular networks and you know being able to connect people
and get together in the same game provides a great
opportunity for social gaming and allows a lot of people
to discover your games because as was shown in the
overview if one person invites their friend to play a game
and that friend does not have the game yet the
invitation notice will give them an opportunity
to buy the game immediately in
the game store, in the app store.
And ultimately there are things you need
to keep in mind; these are mobile devices.
These are phones.
People move around, phone calls come in, connections come
and go and there are some considerations you need to take
into account in handling these off-line situations.
So as I said players will come
and go in the middle of your game.
Now we're going to try and notify you if you have a
connection that goes away but you need to be prepared
for the game player to take phone calls and
if they lose and regain their connection.
So we have facilities where you can detect a disconnect
and then potentially add another player into it
or your game can just go on without that player
or you can handle it whatever way you need to.
And you also need to be aware in iOS 4 of multitasking.
Your game might get switched to the background for some
other reason in which case you might want to Pause.
And if you're in multiplayer you might want to communicate
that to the other players so that they Pause as well.
And ultimately it's important for game play to be able
to continue for the others in one form or another.
If they want to continue and let this person be dropped, you
know without this person, then they should be able to do so.
So the service also-- there are some considerations
that need to be taken in setting up your game.
We currently provide compatibility between different
versions and this comes into play with matchmaking.
In iTunes Connect you set up your game through
its bundle identifier and you register it
to be a game center application and then
you set up the versions that are going
to be compatible to play with each other.
So if you add the Game Center services multiplayer in
version 1.0 and then you know, or actually you add it in 2.0
and you have it in 2.1 and then you know you broke
it in 2.3, so maybe you want to leave that out,
and then maybe 3.0 is now totally different.
It's no longer compatible.
You need to kind of report these in iTunes Connect
so that we know that you know basically if 3.0 comes
in it's compatible with 2.0 and 2.1 but
it's not compatible with 1.0 anymore.
And this is done with Invites on the
recipient's device and the invite will come in
and we'll tell them what version it was for and if they
don't have that version, but they do have the game,
they can at least go to the store and
upgrade to the appropriate version.
Actually, they'll get to go to the latest version.
So that's one thing to keep in mind.
Before we can get started with multiplayer and Game
Center in general you need to take the GKLocalPlayer,
which is the user of the device
and you need to authenticate it.
So authentication is done with the LocalPlayer and it
also provides the friend list so that you can now dive
into the social network, get the friends of this player
and display them and use them however you want to.
The LocalPlayer provides an invariant playerID
persistent the lifetime of that account.
You should use this for referencing saved games so that if--
because one device might be used for
multiple local players at different times.
You'd like them to have different sets of saved game data.
You also want to use this for cash data as mentioned in the
previous session if you want to submit a leaderboard score
or achievement and the network is offline at the
time, you want to archive that achievement or score.
It will be saved with the playerID
and you will want to resend that.
So the key thing to keep in mind with authentication
is you want to do it as early as possible.
We recommend that you do it as soon as
you can after an application is launching.
The only thing to keep in mind is its probably
best that your game UI is up in some form
because Game Center will show additional UI.
If the user is not logged in we're going to show an
alert allowing them to log in or create a new account.
If they have gone through and logged in
somewhere else we have a single sign-on
and then we will automatically
authenticate and we will at least show the UI
to welcome them back to Game Center and your game.
If you have not authenticated and start using other Game
Center APIs these will return immediately with errors.
So make sure to authenticate as soon as possible.
Here is a quick review of the code.
It is a single method on LocalPlayer.
The first thing you want to do is get the LocalPlayer
through the GKLocalPlayer Singleton method,
and then call authenticateWithCompletionHandler
and this is using the block syntax.
You will receive a callback with an error or not.
If you receive an error you should disable
your Game Center features but make sure
that the user can still play your game in some form.
You know you may have to restrict them to Single-Player
mode, but at least leave some of your game functionality.
Because it would be terrible if your game was not usable when they're on an airplane.
Otherwise go ahead and enable the Game Center
functionality and provide the full Game Center experience.
So the first multiplayer experience that
I want to talk about is Auto-Matching.
This is where we allow people with similar configurations
that want to play multiplayer without any encumbrance just
to jump in and be matched with people that are like-minded.
There is a few classes we use to do this in the API.
They are the GKMatchRequest, which defines the parameters
of the match, the GKMatchmaker that can do this,
the matchmaking, you know it takes the match request and
gets the match back without any UI and then if you want to,
provide standard UI for the matchmaking
and if you do this you need
to handle invitations as well,
which will be the next section.
You can use the GKmatchmakerViewController.
I'm going to walk through the Auto-Matching
flow a little bit here
and show you how things were communicating with the servers.
If you were at the overview session you've
probably seen this before but I'm going to go
into a little bit more detail about
the parts of this matchmaking.
So we're starting up here with Onward, which is one
of our test games and ThunderZeus has just signed in.
We're going to set up Auto-Matching
and then add two more players to play.
So here the game is allowing 2 to 4 players.
ThunderZeus has chosen to play with 4 players and when
I hit the Play Now, the match request will be sent
to by the Matchmaker to our Auto-Matching services.
Now if you've written a great game, it's popular.
You'll have a lot of people out there and the probability
is there are going to people for this person to play with.
Everybody's going to want to play the game.
The services are going to look at all
the requests, find the most appropriate,
the best suited requests, and we'll
return a match to those games.
The Matchmaking class GKMatchmaker or the
View Controller will return a match object
at which point you can begin your game.
So here's a rundown of the matchmaking process.
The first thing you need to do is create a match request.
This is where you define the parameters of the match.
You then send the match request to the server
either through the Matchmaker or the standard UI.
The server then applies the Matchmaking logic and
takes into account parameters of the match request,
information about all the devices that are requesting
similar parameters in their connection capabilities
and looks at particular into two parameters that you can
choose, which is the Player Group and the player attributes.
These are properties on the match request that
allow you to control how the match is grouped,
you know how we segregate the pools of the people that want
to play and also the type of players that can come together.
I'm going to give more details and
in-depth analysis of this later.
Once the server has found the best
match the match is returned
to all the devices that are participating in that match.
Then it's up to you to basically start listening
on that match for all players to connect.
Once everything is ready to go, begin
the game and let everybody have fun.
So let's take a look at what the match request is.
It's a really simple object.
It's the parameters for the match.
You get to set a few properties here.
The first two are the minimum and maximum players.
If you want to allow the user to choose between a certain
set of players you can set a range, 2 to 4 for example.
If you only wanted to allow a 3-player
game you could set both equal to 3.
Ultimately the only requirements here
are that minimum players be less than
or equal to maximum players, it
wouldn't make sense otherwise.
Now keep in mind depending on what type of match you
want, whether you're going to go with a peer-to-peer match
or client-hosted or server-hosted, sorry or server-hosted
match, there may be other limitations to what type
or the number of players that we can support.
Then you're going to assign a Player Group.
A Player Group is some parameters based on your application,
the version of the application, the level they've chosen.
The player attributes are more specific attributes about
what the player's chosen, their class you know in an RPG,
their position in a sport and I'll
take a look at those later.
Let's look at Player Groups right now.
I've got 4 tracks.
We've got the standard oval, the figure eight,
and some that are a bit more interesting.
Now, when we go to the matchmaking
services we want to split the people up into
which racetrack they want to play on right.
They're going to pick this before you
go into Auto-Matching and you know
when that happens the match requests
are all sent to the server.
The server groups these by the Player Group and will
only match players that are in the same Player Group.
Now as you can see there's one side of it
that can happen in this case and that is
that there's a racetrack that's
unpopular or a level that's unpopular
and ultimately just a Player Group
that nobody is playing in.
We provide an API for you to query the activity of this
Player Group, which you can then use to either present UI
to the user to show them that hey, there's
not been many people on that racetrack.
It's not very popular now.
Maybe you don't want to play that one or you can even use it
to automatically redirect them to a different Player Group
after they've chosen it and I demonstrate that here.
You know you query the Player Group and
you switch them to this other racetrack.
Then when the match request goes in that person
is not going to be sitting there for a long time.
They will be immediately matched with everybody
that wants to play that particular track.
So what exactly is a Player Group?
You know, it's hard to define.
It really depends on your game, but it's an
arbitrary grouping based on in-game settings.
You know we've called it internally a bucket or if you
want to think of a hash table, its like has you know.
It's some combination of what the user has
chosen and the configuration of your game.
You know if you have download content, you know
inapt purchase content and you have someone who wants
to play a new track, well that track should have
you know new content of another Player Group.
Ultimately you're going to use this to match
players with compatible in-game settings
and our services will not match
people between Player Groups.
So only in the same Player Group will be matched.
Ideas for Player Group assignment are difficulty setting.
That's pretty easy.
You know you've got people that like to play
easy that are probably not good at the game
so you can kind of keep those people together.
Normal and Hard applies, well as I
showed with the racetracks the game level
or map if you're in first-person shooter.
You may want to combine this with game mode, so you may
want to kind of hash the two together and combine you know,
capture the flag and deathmatch so they'll be a different
Player Group for level 1 capture the flag and deathmatch.
You know each of those would be a different
Player Group as well as level 1 deathmatch.
If you have a global game that's very popular and you
want to keep people playing that are local to each other,
you may want to use Player Groups
based on region or even realm
such as the multi-mass multiplayer on-line
games where you have to remember realms.
One thing to do is as showed, query activity in the Player
Group to make sure that there are people there to play with.
And let me show you how we can do that.
It's basically one a synchronous API.
It's on the GKMatchmaker class and it's called
queryPlayerGroupActivity withCompletionHandler.
The input parameter is the Player Group you wish to use.
In this graphic here each of the colored arrows
represents a player attribute based on the key here.
And what's going to happen is they're going to communicate.
They're all in the same Player
Group and the services are going
to find the best players that fit
the set of player attributes.
So it's going to return a match to one
of each of the different colored arrows.
So I've got here a thief, a fighter, a mage and a cleric.
Now let's see more specifically what
an attribute is and how it works.
Now we were sort of analyzing the used cases here
and try to find the simplest way we could
represent something to achieve these results.
And basically what we've come up with here and its optional
is a 32-bit integer value that you use sort of as flags
to represent the attributes of
your player in this match request.
We sort of do a logical OR operation on this
when performing a match to group these together.
And if you think about this as the
OR the Player Group is the AND,
and if you're outside of the Player
Group its not going to match anything.
You want to choose these based on player characteristics.
I gave an example previously of a role-playing game
where we have a fighter, cleric, mage and a thief
but if you're writing a musical game, a band, you might
have a guitar, bass, drums and vocals or a sports game
where you need a goalie, a couple forwards and defenders.
Ultimately what happens in the server
is we try to combine these flags
to match you know the maxent bit pattern 0xFFFFFFFF.
You know you don't need me to read that but it's there.
You know we're going to combine these and when the
server finds the combination of player attributes
within the same Player Group that matches it is
what's going to use to send the match back to.
So let's take a more in-depth example of how you can
configure a match request and we'll look at it in code here.
So I've kind of broken things in part here,
so we have the basic match request up top
where I'm setting up a 4-player dungeon crawl.
They're going to play my level 4 dungeon.
I have a minimum of 4 players and a maximum of 4
players; you need a 4-player party for this game.
One of the players would set their
attributes to the fighter attributes.
Another one on another device would
be the mage, cleric and thief
and then through the Matchmaker
we'll send up this match request.
Once the match is made the players need
to get connected and this where a lot
of the heavy lifting is done for you by Game Center.
We will establish by default a peer-to-peer connection
and this is where we establish connections directly
between player's devices and we analyze
what the connectivity abilities are,
you know to pick the correct players for a match.
And essentially what this establishes is a mesh where each
device is connected to all other devices that are played.
If you choose to go with a peer-to-peer match, you
have Send and Receive data APIs in the GKMatch object.
The other option we provide with our
services is to go with a server-hosted match.
There are fewer limitations to the number of players but you
have to host a separate server yourself to host the game.
But this has a benefit.
It allows you to improve these abilities,
get more players and provide more options.
The one down side is that to go this way you
need to establish custom network communications.
You need to set up the links between
each device and your server.
We will give the devices enough
information so that you can figure
out who should be playing each other
when they connect to your server.
We will do the invites and the Auto-Matching
but it's up to you to connect to your server
and get everybody communicating through your service.
So let's just take a quick look at how these look like.
It's pretty straightforward.
Once you've communicated with the Auto-Matching
services and had the matches returned
to the devices either a peer-to-peer network, here a little
mesh will be set up where each device talks to the other
or you could go with the hosted approach where every
device talks to your run, the central server you run.
So let's look at what we need to do Matchmaking.
These are two devices representing two different
players that want to be connected through our services.
And we're going to replace one of these
with the classes you need to do this.
Here we have two classes that I went through before.
The match request and the Matchmaker, the match request
is pretty straightforward as I showed you earlier.
We set up a match request with the player counts
and the minimum players and maximum players.
The Player Group and the player
attributes are defined, how this person,
this local person, should be matched with other players.
This match request is passed as the Matchmaker and with
this code here we initialize the shared Matchmaker.
Then we call create match or request withCompletionHandler.
This takes the match request that you just created as
input and will return to you on success a GKMatch object
that represents the peer-to-peer network and it will contain
information for you to find out when players connect,
disconnect and also to send and receive data.
If we are unable to create a match an error
will be returned and you need to handle
that error and report the situation to the user.
On success though you need to set somebody to be the
delegate of this match to start receiving connections
and receiving data, here I set the delegate to self.
The other way you could set the match is server-hosted.
If you go the server-hosted route you're
going to want to use a different API.
This API is findPlayersforRequest withCompletionHandler.
Instead of us returning a GKMatch
object that contains all the connections
for the peer-to-peer network retain an array of GKPlayers.
Each GKPlayer has a playerID that is invariant which you
can communicate to the server to help connect these people.
Similarly as the other API an error will be returned
if we are unable to connect and create the match.
Now in summary of Matchmaking it's pretty straightforward.
It's simple to set up Matchmaking without UI or with UI.
The first step is to create a match request.
Think about the Player Groups you need for your game.
How do you want to separate how people play in your game?
That's kind of the first step you need to think about.
And then think about if you're going to
need attributes at all and if you do,
you now make sure that the sign goes to the match request.
Then you're going to request the match.
You're going to take this match request you built,
hand it off to the Matchmaker or stand it off
to the standard UI through the MatchmakerViewController.
When you get the match back you need to handle
player state changes and wait for players to connect.
After everybody is connected the game is ready to go on.
So that wraps up Auto-Matching.
The next thing I want to talk about are invitations.
Invitations are handled by some of the
same classes and a couple other classes.
Again we have the match request.
We also have the Matchmaker and the new classes are
the GKInvite and the MatchmakerViewController again.
So we use the match request the same way but
the rest is going to be a little bit different.
So let's take a look at an invite
flow in a demo game that we created
and I've got a few screen shots to walk you through here.
I've got two devices, inviter and an invitee.
The inviter has already launched
the game and been authenticated.
The player is going to select to invite their
friends to play and up comes the standard UI.
To do this you're going to need to implement that
button and initialize and show the standard UI.
Then the player can Select To Invite a
Friend, which will bring up their friend list.
They can choose their friend and essentially even
choose multiple friends from this list at the same time.
Once they've got people they want to play with they'll
click Next where they can compose an optional message
that will show up on the device
when the invitation is received
and once Send is pressed the view controller sends
the match request and the players up to the service
where we compose a notification, find the players
device and send the notification on to the device
and when the recipients device receives
the notification up pops the alert.
If they have the game and its compatible
they can choose to Accept
or Decline the invitation, we always hope that they Accept.
So here the invitee is going to accept the game.
The game launches and will automatically
display the Matchmaker UI.
At this point now everybody is connected
and ready to go and we're just waiting
on ThunderZeus, the inviter, to start the game.
They pick PlayNow.
At this point the match object is returned,
the players are connected and the game starts.
So what do we use invitations for and how do they work?
Well, generally they're to invite friends to play games.
And they are two ways that this can happen,
and they only happen involving Game Center UI.
One is through the standard in-game UI
provided by the GKMatchmakerViewController
and the other way is through is Game Center.
As was discussed in the overview if the user browses
to their friend's page in the Game Center application
and then views one of the games that their friend is
playing there is a Play button available on that screen.
If they click that Play button we're going to launch
your game and request that you invite that player
to play the game with the player of your device.
What happens is we send push notifications.
All the invites goes through the
push notification mechanism.
It's sent directly to your friend's device and there
are pretty much options that they'll get to choose from.
The primary one is to Accept the invite and Play the game.
If they're busy and don't want to play they can Decline.
If they don't have the game or don't have a
compatible version they can go to the apps store
and buy your game or upgrade to your latest version.
Once the invite is accepted and they
have the latest game we're going
to automatically launch the game
and that's where you come into play.
The flow to creating, to inviting friends to play is
pretty much like creating a MatchmakerViewController.
You're going to create a match request,
use the same set of properties min players
and max players, Player Groups and player attributes.
You will initialize the MatchmakerViewController
with this request.
This MatchmakerViewController uses underneath
a GKMatchmaker object that I discussed
with Auto-Matching and shows our standard UI.
So you're going to show the MatchmakerViewController
object you created where the user is now in control.
And if you have a range of players they are able to change
the number of players they wish to play and then select
from their friends list the players
that they wish to play with.
It's also possible that they-- you know you have
a 4-player game they may invite one or two players
and then choose to Auto-Match the remaining players.
So if they don't invite everybody to fill in
all the game slots, all the available players,
Auto-Matching as I discussed before will fill
in the rest, automatically behind the scenes.
When the user is done with this UI you're
either going to get a match or you're not.
And so hopefully we'll get a match
and you can start the game.
So again we're going to start with two devices,
one to communicate through the Game Center services
and we have essentially one device that
represents the inviter and one the invitee.
So I take away the inviters device here and
show you the classes that you're going to use
at the top level for setting up game invitations.
It's really simple the two you need to worry about.
Again we start with the match request.
We're going to start pretty much the same
parameters, 2 to 4 players in our level 4 dungeon.
We're going to initialize the match request.
We initialize the MatchmakerViewController
with our match request.
We want to be the delegate of the MatchmakerViewController
because through a delegate method that the match is returned
and then we will show the MatchmakerViewController
to present the UI to the user.
Now at this point we need to be the delegator
and implement these delegate methods.
So let's look at what the delegate does.
The first and primary one, the one we hope always gets
called is MatchmakerViewController did create match.
This is the delegate method that is called
when the user has completed the ViewController,
the Game Center services have found the best people to play
with and/or the invitations have been
accepted and you will get a return to match.
Again you want to set yourself
to be the delegator of the match
or somebody else and then wait for everybody to connect.
Now optionally you can do just like with Auto-Matching,
you can choose to do the ViewController with a hosted match
in which case you will get the
MatchmakerViewControllerDidFindPlayer delegate method called
and similar to Auto-Matching this
returns an array of players.
There are a few other delegate methods that handle
cancellation, MatchmakerViewController was canceled.
This happens when the user clicks the Cancel button.
Errors-- MatchmakerViewController did fail with error.
This is that the server's, based on the match
request was unable to make a valid match.
If you have an error in your match request something
went wrong in communicating with the servers.
You may get this call.
We've gone through how you send an
invite but there is work you need to do
to be able to handle the invite once it's received.
Game Center will show the invite alert.
When the user accepts your game will be launched.
But for you to know that you were launched with
an invite we needed to implement these two methods
and when you get these you need to show the ViewController.
These are both basically properties
that are blocks on GKMatchmaker.
The first is the InviteHandler block.
This block is called when your game is launched or when an
invite has been accepted by the user on behalf of your game.
And basically the block will be called and pass the invite.
There are some things worth knowing, this is one.
You should keep this thing set at all times.
You may be called immediately after
setting this block to the GKMatchmaker.
Because if your game was launched in response
to an invite, you know, the invite is waiting,
so as soon as you send this CompletionHandler it's
going to get called and the invite is going to passed to it
so be ready to handle it when you send it.
It also may get called at any point during your game flow.
If you're just playing the game, playing your
game, and they receive another invite from one
of their friends to play their game, the alert comes up,
and they can choose to accept or decline that invite.
If they want to play with this other person that
invited them, you know they like them better
than who they're playing with, you need to
respect their wishes and make sure that you clean
up your game state and get them set up into this new game.
So you are going to be called and you are going to be given a
GKInvite object and all you really need
to do is initialize the MatchmakerViewController
with this invite and show it.
The other method, which is not in the
API that you've seen in the seeds,
but will be coming soon is the playerstoInviteHandler.
This handles a special case of your game being launched
from Game Center from a friend's game details page.
And it has basically the same sort
of conditions as the InviteHandler.
It can be called immediately.
With multitasking it can potentially be called at any time.
And you know do the same thing,
initialize the MatchmakerViewController.
It's a little bit different.
Instead of being the recipient of an invite you're actually
going to be sending an invite on behalf of the user.
Transparently you're going to set up the UI.
So to do this you want to initialize the
ViewController with the match request
and the array of players that this block has given.
So we're going to take a look at the code for
these and how these come together right now.
So I've moved to the other side and we're implementing
the invitee recipient code and we have two blocks
that we're dealing with again, the
GKMatchmaker and the GKMatchmakerViewController.
Let's implement the InviteHandler that's going to pass
the invite, the GKInvite to the matchmaker ViewController.
It's the InviteHandler block on the shared
Matchmaker and it's a block that takes
as a parameter one single parameter, the GKInvite.
This is a pretty simple object.
You don't actually need to pull anything out of it.
You're just going to pass it along.
You're going to pass it and initialize
the MatchmakerViewController with it.
Again you need to become the delegate of the
ViewController and you need to show the ViewController.
Now I'm going to take a little liberty with the next
slide because it's actually the invite tour side
but I'm going to show it here because it fits.
This is the playerstoInviteHandler,
which works pretty much the same way.
You're going to set up your players InviteHandler block
and instead of a GKInvite object it's an array of players.
And instead of initializing the ViewController
with an invite you'll mate it with a match request,
which we'll make based on the properties the player chooses
perhaps before this step you actually want to show some UI
so that it will let the player pick
the level that they want to play on.
Because remember this is a little bit different,
essentially you're going to send the invite
out so you can let them pick the level, pick their
class whatever and playerstoInvite and the same thing,
set up the delegate and show the ViewController.
So in summary, invitations are pretty easy.
A couple things you need to do.
One, remember to create the match request.
You know present the standard UIs because all invitation
flow goes through the standard UI whether sending one out,
you're handling or receiving an invite or
you're going to prepare an invite response
to someone launching an app from Game Center.
The few things to remember is you can be called at any time.
Make sure that you can clean up your game
state, and you need to respect the user's wishes.
You know, if they've accepted an invite and they're called
it's because they want to play that invite and you need
to abandon what they're currently doing, and
remember that it may be called immediately.
So let's take a look at the hard stuff,
the networking that we do for you.
Basically all of the networking
is done under the GKMatch object.
And this networking, this peer-to-peer
networking that we do for you is actually--
shares a lot of the infrastructure that makes FaceTime work.
FaceTime is established as a peer-to-peer connection
and it uses a lot of the same stuff that we do.
So the match represents the game
communications between the players.
It's got an array of players.
It lets you know when players are connecting.
It gives you an API so that you can send data.
If you've seen the previous versions of the
GameKit framework, a lot of this is similar.
We have two ways of sending data.
You can send data unreliably you know.
This is data, you know that if it didn't
go through it's going to be stale anyway
and you can just send new data and replace it.
You know position information of a player moving
around a map or it can be sent reliably and what we do
with reliable data is we will wait for acknowledgement
and attempt to resend the data if it doesn't go through.
Now in general a lot of the stuff we need
to do unreliable is probably satisfactory.
It also provides a delegate method so that you can
receive data on all the other players in the match.
And finally there's a PlayerStateChange delegate method that
allows you to wait and watch for player's state changes.
It will tell when you players connect
and when players disconnect.
And you use this first off to wait for all players to
connect before you start sending any of your game data
and also to be able to notice when
players drop or disconnect mid game.
You know, if someone takes a phone call, goes into a
tunnel, you know you need to be able to handle this.
We're on mobile devices.
So let's take a look at what we need
to do to wait for players to connect.
It's a GKMatch delegate method
called MatchPlayersDidChangeState.
The operative objects are the player
and the state that they changed to.
I highlight the two states that we care
about here, the connected state.
This is when they initially connect and a
disconnected state when they disconnect.
And we will try, when you get this
disconnect, they are really disconnected.
We have tried through our connections to
reconnect them and have been unable to.
So at this point they're gone and
you need to be able to handle that.
There are ways you can do this
with a match and the Matchmaker.
You can choose to add players to the
Auto-Match but we'll take a look at that later.
So when you're using this call and waiting for players to
connect, we have a property that can help you to do that.
This is property on the match called expectedPlayers
and you can watch for that to decrement.
We'll decrement how the players connect that we expect.
So we'll start off you now you've got a 4-player game.
We're going to be expecting 3 players and
as each player connects this will decrement.
When this gets to 0, if you haven't already started
your game because remember this player state can happen
at any time, it's time to start your game.
A couple of ways to send data once the connection is
established and you want to start a multiplayer game
that means communicating the game state between devices.
So two APIs, we have a GKMatch, sendDatatwoPlayers
with data mode allows you to send your data
to a subset of the players that are in the match.
And again you can send it reliably or unreliably.
Here I use reliable as my example.
Worth noting is that this method will return a bouillon
and it would be false if for some reason we were unable
to send the data and in that case
the error property will be populated.
Similarly we have a method basically to
broadcast data to all the players in the match.
This is SendDatatoAllPlayers again with a data mode
and again this property will turn
a bouillon and an error on failure.
To receive data there a single development method that you
need to implement that is matched, DidReceiveDatafromPlayer
and you know I really can't tell you what to do here because
it all depends on your game code but you want to take
that data you got and run it through your game
engine and it's pretty much as easy as that.
So some things to keep in mind when
using our Matchmaking services,
we want everybody here to write
games that are good network citizens.
This means that games that will work with
multiple instances running on the same network.
Cooperate and play nice when there are
other games running on the same network.
So here are a couple of things we recommend that you do.
First, keep your network traffic to a minimum.
By minimum I mean make it small, so minimize the size
of the data packets and send as few packets as possible.
So some things not to do-- don't send data
for every game frame if you can avoid it.
If you're game is running at 60 frames per second do you
really need to send location players for every frame.
Think hard about that, because that's
an awful lot of data to be sending.
You also don't want to broadcast
data to all players all the time.
It's usually the case that the data only needs to
go to a subset of the players and not to everybody.
To help with this we also recommend that you
try adopting some common networking strategies.
Some of these are to set up a client-host network topology.
This is where you're going to choose
one of the peers to be a host
and all other devices will communicate through that host.
Or you can set up a ring network where the device is
communicated along the ring and with the array of players
in the match and the disconnect notices
you can also re-establish that ring
so it's a little more robust than some other ring networks.
Or you can host your own servers
and use our server-based networking.
So let's take a quick look at what
it kind of takes to do a client-host
because this is what a lot of you
are probably going to want to do.
This is what we've done in most of our demo games.
The first thing you need to do is to nominate the host.
And common ways to do this are to set up a voting or a
coin-toss algorithm where random numbers are generated,
sent to all the devices, collated and the host is
chosen from that or we found that there is kind
of an easy way that you can do things, too.
You can compare the playerIDs.
Now the playerIDs are strings, but you
still use string collation to compare them.
And while it's not truly random, you will be able to
reliably and very cheaply find either the lowest sort order
or the highest order playerID and make that one the
host without having to communicate excess packets.
Ultimately then you want to communicate all
data to the host that involves the game state
where the host then maintains the truth and
then chooses who it needs to send data out to.
So the host will then pass that
data to the necessary clients.
We take at look at how this affects the networking.
Here's a peer-to-peer mesh where we've got you know
bidirectional connections between all the devices.
There basically are 6 bidirectional connections here.
If we move to a client-host topology we
basically reduce the communication down to,
let me go back real quick, 3 bidirectional caches.
The green arrows represent the subset that are used for
the client host so the device up front has become the host.
Now everybody communicates through it.
Alternatively as I mentioned you know you may want to think
about using a ring network that is suitable for your game.
One of the graphics is wrong, but there should
be another arrow on that short link in red,
but basically we established-- used 4 of the connections
as basically unidirectional links
and we can send data around the ring.
So that handles what we do for peer-to-peer.
If you were going the other route and you want to host
your own server, some considerations you need to take
into account is one, when using the GKMatchmaker and
Auto-Matching or the MatchmakerViewController you want
to make sure you choose the correct API to use.
It is essentially a separate set of APIs and parameters
for peer-to-peer networking, which is the default
and hosted networking, which is for a
client, when you host the server yourself.
You can still use our invitations in Auto-Matchmaking flow.
That's why it's there.
We want to do that part for you.
And you can even use the playerID to track players.
You know we only give you an array
of playerIDs for the match.
You can use those to find the unique matches on your server.
The multiple ways you want to do this is
communicate these matched players to your server
and then implement your networking
and set up communications.
So let's take a look at the Auto-Matching
API that we use for this.
I think you've seen it once before in
the slides but we'll just review it here.
This is findPlayersforRequest withCompletionHandler.
It's a method on the GKMatchmaker and it returns an array
of players or an error you now for a server-hosted match.
Now if you want to use a standard UI or handle
invitations you do this with a match request and you set
up the standard GKMatchmakerViewController
but in addition to setting yourself
as the delegate you want to set the hosted property to YES.
That's telling us you intend for this to be a hosted
game where you're going to host it on your own servers.
You'll show the UI and then you'll
get back a different delegate call.
I'll show you the delegate.
It's the MatchmakerViewController, didfindPlayers delegate
and you'll get an array of players for this match.
So for peer-to-peer networking GKMatch provides
all the API you need to do the communications.
We've got Send.
We've have Receive and we've got player state change APIs.
It's important that you handle the player state changes.
Remember these are mobile devices.
They can take phone calls.
They now multitask.
They can lose their connection to the
network so be able to handle that.
Be a good network citizen.
You don't want to overwhelm the networks
that games are being played on you know.
Use our APIs appropriately and, you know, make
sure that you're not over-saturating the network.
And if you need to handle, you want to handle a lot
of players, you have some other functionality you want
to handle, seriously consider hosting on your own servers.
So the last thing I want to talk
about is In-Game Voice Chat.
We made this very easy for you to establish voice
communications between the players in your match.
Now this only applies to peer-to-peer
matches as it uses the GKMatch class
and the GKVoiceChat class, which represents a distinct chat.
So In-Game Voice Chat allows your
players to communicate with each other.
All the iPhones even the iPod touches.
They all have microphone.
You know if you connect the microphone headset to the
iPod touch, it's great for players to communicate.
It's a new thing to be able to do this
and it's a new thing on the phones.
You know it's almost kind of expected to be able to do this.
It really keeps players involved.
If players can talk to each other, you know get some
more into the game, they can do things like trash talk.
They can encourage the others.
They can strategize among their own team.
It really enhances the competition.
We make it very easy for you to integrate.
It's basically you know we do all the networking
for you to send the voice packets between devices.
All you have to do are create the Voice Chats
and then manipulate them for which one is active.
So let's take a look at what Voice Chats offer.
We have multiple named Voice Chats
that are accessible from the GKMatch.
You can use properties on the Voice Chats or methods
to start and stop them so you can hear selected chats.
You can have multiple chats going.
The microphone is always routed to only a single chat.
And you can increase or decrease the volume of a given chat.
And if you need to it's possible for you to allow
the player to mute another player in any given chat.
And then just like in Matchmaking it's
useful to watch for the state changes
so we have a handler implemented by a block.
The players update the handler, so you can find out when players connect,
disconnect, start and stop speaking.
So before you set up the Voice Chats you
need to set up the audio on the device.
It's a little pre-set up you need to do.
You want to set your audio session to play and
record and make it the active audio session.
Take a quick look at this code.
There are a couple of ways to do this.
I'm showing you the AVAudioSession.
You basically set up its shared instance.
You set its category to Play and
Record category and you make it active.
It's pretty straightforward.
Once you've got the audio session set
up you need to get the Voice Chats.
Before you can actually do this you need to get the match.
So from the match, you're self-match,
I'm going to create two chats.
The main chat or the lobby, which is where everybody
will be able to talk to everybody else and the team chat
for the red team, where only the people on
the red team after that is connected can talk.
Here I show where we can stop the main chat so
it's not going to play through this user's device
so they won't hear the audio from the
main chat and start the team chat.
And then I will make the team chat active to
the route the microphone to the team chat.
And one important thing to note is when you make the
microphone active for this it's generally important
for you to give some indication to the user.
And an audible and a visual indicator
are usually called for.
So it's just when you activate a chat and
get the microphone active indicate it please.
Handling player state changes is pretty straightforward.
It's a block, the playerStateUpdateHandler.
There are 4 states that you may care about--
connected, if a player connects you may want
to show their icon, show their name in lobby whatever.
If a disconnect, remove them from that list.
And when they start speaking you may want
to show an icon you know a speaker icon,
a little dot next to the name and
remove it when they go silent.
So a lot of this functionality for
multiplayer can only be tested on devices.
So its' very important that you test this
on devices in particular like invitations
or Voice Chat do not work you know you'll want to
test with multiple devices and multiple accounts.
Testing on the simulator is limited.
You can test mostly other Game Center
features like leaderboards and achievements
but invitations are not available due to
limitations and In-Game Voice Chat is also disabled.
There is only one little side effect
that you probably won't notice
but our preemptive cache invalidation is also
disabled in the simulator, which you will only notice
in the Game Center application probably, if at all.
So thank you for listening to me.
A couple of things I want to say before I leave the
stage here is remind you that the first thing you need
to do before you use Game Center
is authenticate the local player.
Nothing will work unless you do that.
Then think about for your app how you want to divide
the players that are going to play multiplayer.
You know come up with some good
Player Groups and player attributes
so that you can get the right sets of people together.
To handle invites make sure you implement both
the InviteHandler and the playersToInviteHandler.
Use GKmatchmakerViewController to present the
standard invitation UI and standard Matchmaking UI.
Once you have a match, wait for all players
to connect before you start sending packets
otherwise they're not going to go through.
It's a lot easier if you just wait
before you start sending them.
Integrate Voice Chat because it gets your players
more involved and we make it easy for you to do so.
And remember the Game Center is currently a preview on
iPhone, sorry iOS 4 and will be available later this year.
For more information contact the Graphics and
Game Technologies Evangelist, Allan Schaffer.