Real-Time Multiplayer

Warning: This API requires IOS 8.0 or higher.

In a real-time match, the players are connected to Game Center (and thus to each other) simultaneously. This form of match is suitable for implementing any type of game that requires live participation. A key advantage of real-time matches is that Game Kit and Game Center provide extensive support for real-time matches, which simplifies the code you need to write. In particular, it solves many problems of finding players to join into a match, it provides a high-level networking interface that lets you ignore many of the problems of the underlying networking layer. 

However, even though Game Kit solves many of these problems, your game design still needs to be prepared to deal with complex issues that arise from real-time networking, including:

  • The need for multiple instances of your game (running on different devices) to perform tasks simultaneously or near simultaneously, while synchronizing states between the devices
  • Network reliability
  • Network latency

Implementing a real-time match requires extensive work designing, implementing, and testing your game.

Checklist for Adding Real-Time Matchmaking to Your Game

The checklist for creating a game that supports real-time matches is more extensive than that for other Game Center technologies and comprises three main areas: matchmaking, data exchange, etc. As part of this process, you also have many design decisions to make about how matches are played in your game, including:

  • How many players can play at once
  • What does a network version of your game looks like
  • What data needs to be shared to build your design

These and other questions impact the design of your gameplay and networking code.

Finding Players for a Match

Determine whether your game will use the standard matchmaking interface, display a custom matchmaking interface, or use a combination of both. Regardless of which implementation you choose, you must support the chosen implementation behavior inside your game as well as add support for handling invitations received from outside of your game.

When a player wants to create a match, your game must display a user interface to allow the player to see and configure the state of the match. The simplest way to implement this is to use the standard user interface provided by the GameKit. It implements many common matchmaking scenarios with a small investment in code. However, if you want to implement your own custom behavior, you can design your own custom user interface and then call the IOS Native provided API  to perform this task programmatically. API returns data to your game so that it can update its own user interface.

Defining Player Group and Attributes  

Game Center’s default behavior is to automatically match any player waiting to play your game into any match that needs more players. This has the advantage of matching players quickly into matches, but it also means that players can be added to matches that they are not interested in playing. In that case, you can allow the players to define the kind of matches they want to play, and then match them only with like-minded players. This is accomplished with a player group.

A player group is defined by an unsigned 32-bit integer. Without setting Player Group property,  the player can be matched into any waiting match. When you set the Player Group property to a nonzero number, then the player is matched only with players whose match requests share the same player group number. Typically, if your game uses player groups, it provides a custom interface that allows the player to pick the precise options he or she is interested in. It takes the choices of the player and combines them to form a player group number.

Here are some examples of how you can partition a list of players:

  • Separate players by skill level.
  • Separate players by the set of rules used to adjudicate the match.
  • Separate players based on the map the match is played on.

Although it is up to you to determine exactly how many player groups you want to create, don’t create groups just to create them. Creating many smaller player groups can result in every player waiting for a long time to play a match. Instead, create large groups that players can identify with

Player Group should be set before you starting the match search, the code snippet bellow shows how to set player group property.

int GroupId = 5;


 If the Player Attributes value is nonzero, then automatching uses the value as a mask that restricts the role the player can play in the group. Automatching with player attributes matches new players into the game so that the bitwise OR of the masks of all the players in the resulting match equals 0xFFFFFFFF.

If you want to use Player Attributes property in your game it  should be set before you starting the match search, the code snippet bellow shows how to set player attributes property.

int ROLE_WIZARD = 0x4; // 100 in binary
GameCenter_RTM.instance.SetPlayerAttributes (ROLE_WIZARD);


Using the Standard Matchmaking User Interface

The standard matchmaking user interface is often displayed in response to the user tapping a button on your game’s title screen. It can appear immediately after the button is tapped or after several interim screens between the title screen and the matchmaking screen. For example, if your match request includes player groups or player attributes, you usually have your own custom user interface screen to configure the match request before displaying the default matchmaking user interface.

int minPlayers = 2;
int maxPlayers = 2;

//Optionally you can provide and invitation message
string invitationMessage = "Come play with me, bro.";

//Optionally you can predefine invited friends list to the match
//The code bellow assumes that player has at-least one friend, and you already loaded the friend list
//so we can send an invite to the first player in the friends list
string[] invitations  = new string[]{ GameCenterManager.FriendsList[0] };

GameCenter_RTM.Instance.FindMatchWithNativeUI(minPlayers, maxPlayers, invitationMessage, invitations);


As result to find match request you will get  Action<GK_RTM_MatchStartedResult> ActionMatchStarted Simple code example how to handle this action can be found bellow

GameCenter_RTM.ActionMatchStarted += HandleActionMatchStarted;
void HandleActionMatchStarted (GK_RTM_MatchStartedResult result) {
	if(result.IsSucceeded) {
		Debug.Log("Match is successfully created");
		if(result.Match.ExpectedPlayerCount == 0) {
			//we should start the match
	} else {
		Debug.Log("Match is creation failed with error: " + result.error.description);

Implementing a Custom Match User Interface

Implementing a complete custom match interface can be as simple as displaying a network progress indicator until auto-matching completes, or as sophisticated as implementing a complete custom view controller that replicates the standard behavior. The latter is potentially a significant investment in programming time, as it needs to include support for all of the following:

  • Inviting specific players into a match

  • Listening for responses from invited players

  • Looking for nearby players (available via Wi-Fi or Bluetooth)

Follwing snippet shows how to programmatically request a match. It's almost the same as with the standard GameKit user interface.

int minPlayers = 2;
int maxPlayers = 2;

//Optionally you can provide and invitation message
string invitationMessage = "Come play with me, bro.";

//Optionally you can predefine invited friends list to the match
//The code bellow assumes that player has at-least one friend, and you already loaded the friend list
//so we can send an invite to the first player in the friends list
string[] invitations  = new string[]{ GameCenterManager.FriendsList[0] };

GameCenter_RTM.Instance.FindMatchWithNativeUI(minPlayers, maxPlayers, invitationMessage, invitations);


With the Action<GK_RTM_MatchStartedResult> ActionMatchStarted  , if you use programmatical implementation, you should also subscribe to Action<ISN_Error> ActionMatchFailed.

Canceling a Search

The matchmaking process takes time and may not complete quickly enough for some players. If your game includes support for programmatic matching, it needs to provide a user interface that allows the player to cancel an active search. Follwing snippet shows how your game can terminate a pending search.


Processing Invitations from Other Players

When a player accepts an invitation from another player, your game is launched (if necessary) and an invitation is delivered to your game. Your game receives this invitation by implementing an invitation handler. When you use the standard user interface, your invitation handler creates a match view controller and initializes it with data provided to the invitation handler. The invitation handler then presents the match view controller similar to when the player wanted to create a new match directly; in most cases, you use the same delegate code.

Note: You should subscribe to this actions before Game Center API initialization.

You should handle two user cases:

Match Requested With Recipients

When your game is launched directly from the Game Center app to host a match. This parameter holds an array of player identifiers listing the players to invite into the match. Your game must create a new match request, assign its parameters as it would normally, and then set value from recepientIds  parameter into the FindMatch method. When the matchmaking screen is displayed, it is prepopulated with the list of players already included in the match. You can of course choose what method to use FindMatchWithNativeUI or  FindMatch. Simple implementation can be found bellow.

GameCenterInvitations.ActionPlayerRequestedMatchWithRecipients += HandleActionPlayerRequestedMatchWithRecipients;

void HandleActionPlayerRequestedMatchWithRecipients (GK_MatchType matchType, string[] recepientIds, GK_Player[] recepients) {
	if(matchType == GK_MatchType.RealTime) {
		//Optionally you can provide and invitation message
		string invitationMessage = "Come play with me, bro.";

		GameCenter_RTM.Instance.FindMatchWithNativeUI(recepientIds.Length, recepientIds.Length, invitationMessage, recepientIds);

Player Accepted Invitation

When your game receives an invitation directly from another player. In this situation, the other player’s instance of your game has already created a match request, so this instance does not need to create a match request. Instead you can start match using GK_Invite object. As always it's up to use, use GameKit provided interface or implement your own. Simple implementation can be found bellow.

GameCenterInvitations.ActionPlayerAcceptedInvitation += HandleActionPlayerAcceptedInvitation;

void HandleActionPlayerAcceptedInvitation (GK_MatchType type, GK_Invite invite) {
	if(type == GK_MatchType.RealTime) {
		Debug.Log("Player has accepted invitation, printing invite infO");
		Debug.Log("Id: " + invite.Id);
		Debug.Log("Sender: " + invite.Sender.DisplayName);
		Debug.Log("PlayerGroup: " + invite.PlayerGroup);
		Debug.Log("PlayerAttributes: " + invite.PlayerAttributes);

		bool UseNativeUI = true;
		GameCenter_RTM.Instance.StartMatchWithInvite(invite, UseNativeUI);

Searching for Nearby Players

The standard user interface allows players to discover other nearby players, even when neither player is currently connected to Game Center directly. The discovery uses local Wi-Fi or Bluetooth to find other players. This capability is very useful when players are away from their normal network but still want to play against each other. You can implement similar behavior in your custom user interface.

Here’s how you typically implement this behavior:

1) Provide a button in your user interface to allow the player to search for nearby players. When pressed, this button presents a new user interface screen that displays any nearby players it finds. Alternatively, your user interface can simply display nearby players automatically. If you choose this approach, it usually makes sense to keep this player list separated from the rest of the user interface.

2) Call the StartBrowsingForNearbyPlayers method, and subscribe for  notifications of players as they enter and leave the area. When a player is found, add the player to your visible list of players. When a player disappears, remove the player.

GameCenter_RTM.ActionNearbyPlayerStateUpdated += HandleActionNearbyPlayerStateUpdated;

void HandleActionNearbyPlayerStateUpdated (GK_Player player, bool IsAvaliable) {
	Debug.Log("Player: " + player.DisplayName + "IsAvaliable: " + IsAvaliable);
	Debug.Log("Nearby Players Count: " + GameCenter_RTM.Instance.NearbyPlayers.Count);


3) If the player selects one or more players to send an invitation to, create a match request and add the player identifiers for those players to the match request. Then, follow the behavior described in Finding Players for a Match.  When your browsing screen is removed from the screen (either because the player canceled browsing or because he or she invited players already) call


Finding Player Activity in Your Game

Players who are looking for a multiplayer match often want to be matched immediately, or at least be aware of when matchmaking may take longer. For example, if a player is online during a period of time when players are not regularly online, the number of players who are interested in joining a match may be substantially smaller than during prime time. The determination of how many players are online is referred to as player activity.  The GameCenter_RTM class provides a pair of methods you can use to test for the activity on Game Center related to your game. Use following methods to send players activity request:



You can query activity for specific players group activity as well, using:

int MyPlayersGroup = 3;


The  Action<GK_RTM_QueryActivityResult> ActionActivityResultReceived will be fired as result. You will find simple code snipped bellow:

GameCenter_RTM.ActionActivityResultReceived += HandleActionActivityResultReceived;

void HandleActionActivityResultReceived (GK_RTM_QueryActivityResult result) {
	if(result.IsSucceeded) {
		Debug.Log("Currently avaliable players: " + result.Activity);
	} else {

Exchanging Data Between Match Participants

After you have created your match, the participants in the match need to exchange data to synchronize the state of the match between each other. This section describes how to implement and design this part of your matchmaking code.

Designing Your Network Game

Each participant in the match relies on a GKMatch object to exchange data with the other participants connected to the match. The GKMatch class does not define the format or content of your network messages. Instead, it simply sees your messages as bytes to transmit. This gives you great flexibility in designing your network game. The rest of this section describes key concepts you need to understand before implementing your network game.

Whenever you send data to other participants, you decide how much effort the match should use to send the data. Matches can send your data reliably, which means the match retransmits the data until it is received by the target(s), or unreliably, which means it sends the data only once.

  • A reliable transmission is simpler, but potentially slower; a slow or error-prone network may require the device to send the message multiple times before it is successfully delivered to its intended recipients. A match also guarantees that multiple reliable messages sent from one device to the same recipient are delivered in the order they were sent.
  • Messages transmitted unreliably may never reach their destination or may be delivered out of order. Unreliable transmissions are most useful for real-time transactions where any delay in transmission caused by using reliable messaging invalidates the contents of the message. For example, if your game transmits position and velocity information for a dead-reckoning algorithm, reliable messages might provide positioning data that is badly out of date by the time it is delivered to the recipient. By using unreliable messages, messages are delivered faster. Your game takes responsibility for network errors by sending new messages with updated position and reckoning information.

The size of your messages also plays an important role in how quickly the data can be delivered to its targets. Large messages must be split into smaller packets (such splitting is called fragmentation) and reassembled by each target. Each of these smaller packets might be lost during transmission or delivered out of order. Large messages should be sent reliably, so that Game Kit can handle the fragmentation and assembly. However, the process of resending and assembly takes time. You should not use reliable transmissions to send large amounts of real-time data.

Be mindful that your network data is being transmitted across servers and routers that are out of your control. Your messages are subject to inspection and modification by other devices on the network. When your game on one device receives network data from participants on other devices, it should treat that message as untrusted data, and validate its contents before using it. See Apple Secure Coding Guide for information on how to avoid security vulnerabilities.

Here are some general guidelines to follow when designing your game’s networking:

  • Your message format needs to include a way to differentiate between message types. The GK_RTM_Match class does not know anything about the contents of your messages, so you must implement that functionality in your game. For example, you might create an enumerated type that identifies different kinds of messages, and start each message with that enumerated type.
  • Send messages at the lowest frequency that allows your game to function well. Your game’s graphics engine may be running at 30 to 60 frames per second, but your networking code can send updates much less frequently.
  • Use the smallest message format that gets the job done. Messages that are sent frequently or messages that must be received quickly by other participants should be carefully scrutinized to ensure that no unnecessary data is being sent.
  • Pack your data into the smallest representation you can without losing valuable information. For example, an integer in your program may use 32 or 64 bits to store its data. If the value stored in the integer is always in the range 1 through 10, you can store it in your network message in only 4 bits.
  • Limit the size of unreliable messages to 1000 bytes or smaller.
  • Limit the size of reliable messages to 87 kilobytes or smaller.
  • Send messages only to the participants that need the information contained in the message. For example, if your game has two different teams, team-related messages should be sent only to the members of the same team. Sending data to all participants in the match uses up networking bandwidth for little gain.

Starting the Match

When Game Kit delivers a GK_RTM_Match object to your game, the connections to other participants in the match may not be established yet. The Players array on that user’s device can be empty if no other players are connected, or it might hold a subset of players that have already been connected. Your game must wait until all players are connected before starting the match. To determine how many players are waiting to join the match, your game reads the match’s ExpectedPlayerCount property. When the value of this property reaches 0, all players are connected and the match is ready to start.

The appropriate place to perform this check is in the following delegate’s:

The ActionPlayerStateChanged action is called whenever a member of the match connects or disconnects. Code snippet bellow is an example of an implementation of ActionPlayerStateChanged action  handler. In this example, the match delegate defines its own IsMatchStarted property to record whether the match is already in progress. If the match has not started and the count of expected players reaches zero, the method starts the match. In your game, this is where any initial match state would be transmitted to other players or where additional negotiations between the different participants take place.

Even before the match starts, all players already connected to the match can already exchange data with each other. This allows your game to create  interface that allows the players already there to communicate with each other.

int minPlayers = 2;
int maxPlayers = 2;

GameCenter_RTM.ActionMatchStarted += HandleActionMatchStarted;
GameCenter_RTM.ActionPlayerStateChanged += HandleActionPlayerStateChanged1;
GameCenter_RTM.Instance.FindMatch(minPlayers, maxPlayers);

void HandleActionPlayerStateChanged1 (GK_Player player, GK_PlayerConnectionState state, GK_RTM_Match match) {
	switch(state) {
	case GK_PlayerConnectionState.Connected:
		// Handle a new player connection.
	case GK_PlayerConnectionState.Disconnected:
		// A player just disconnected.

void HandleActionMatchStarted (GK_RTM_MatchStartedResult result) {
	if(result.IsSucceeded) {
	} else {

void CheckForMatchStart() {
	GK_RTM_Match match = GameCenter_RTM.Instance.CurrentMatch;
	if(!IsMatchStarted && match.ExpectedPlayerCount == 0) {
		IsMatchStarted = true;
		//Handle Match Start

Sending Data to Other Players

To send data from one device to other devices connected to the match, your game creates a message and encapsulates it in the byte[] array. You send this message to  connected players using:

void SendDataToAll(byte[] data, GK_MatchSendDataMode dataMode)
void SendData(byte[] data, GK_MatchSendDataMode dataMode, params GK_Player[] players)

Code bellow shows how a game might send a position update to the other participants.

string msg = "hello world";
System.Text.UTF8Encoding  encoding = new System.Text.UTF8Encoding();
byte[] data = encoding.GetBytes(msg);
GameCenter_RTM.Instance.SendDataToAll(data, GK_MatchSendDataMode.RELIABLE);


If the error occurred during data sending process Action<ISN_ErrorActionDataSendError  will be fired

GameCenter_RTM.ActionDataSendError += HandleActionDataSendError;

void HandleActionDataSendError (ISN_Error error) {
	Debug.Log("Data Send Error: " + error.Description);

Receiving Data from Other Players

When the match receives data sent by another participant, the message is delivered  with Action<GK_Playerbyte[]ActionDataReceived. Your implementation of this method needs to decode the message and act on its contents.

GameCenter_RTM.ActionDataReceived += HandleActionDataReceived;

void HandleActionDataReceived (GK_Player player, byte[] data) {
	System.Text.UTF8Encoding enc = new System.Text.UTF8Encoding();
	string str = enc.GetString(data);

	IOSNativePopUpManager.showMessage ("Data received: from player: " + player.DisplayName + " \n " + "data: " + str);

Disconnecting from a Match

When a player is ready to leave a match, your game calls the Disconnect method. A player may also be automatically disconnected if their device does not respond for a certain period of time


Example Scenes

The implementation example can be founded under following example scenes:

  • MultiplayerExampleScene
  • Pear-To-PearGameExample