Turn-Based Multiplayer

In a turn-based multiplayer game, a single shared state is passed between multiple players, and only one player has a permission to modify the shared state at a time. Players take turns asynchronously according to an order of play determined by the game. Your game can use the turn-based multiplayer API provided by the Game Services to manage the following tasks:

  • Invite players to join a turn-based multiplayer match, look for random players to be automatically matched to your game, or a combination of both. Game services allow you to host up to eight participants in a match.
  • Store participant and match state information on Google's / Apple's servers and share updated match data asynchronously with all participants over the lifecycle of the turn-based match.
  • Send match invitation and turn notifications to players. Notifications appear on all devices which the player is logged in (unless disabled).

Turn-based match basics

A turn-based match is a gaming session with multiple participants who take consecutive turns to update the game data during the match. Matches must be initiated by a signed-in player. Your game can use the turn-based multiplayer API to join up to eight players together in a match, including the initiating player and any auto-matched players. Matches take place asynchronously and participants do not need to be simultaneously connected to the Game Services to play.

A turn-based multiplayer match contains these key properties:

  • Participants. A user can become a participant in a turn-based match by initiating a match, joining a match by accepting an invitation, or being auto-matched into a game. Your game can retrieve the participant IDs for all players in a match.
  • Game data. Game-specific data for this match. As a match progresses, the current player can modify and store the game data on Google's servers. The other participants can then retrieve and update this data on their turn. Your game must store the game data in an appropriate format for the device platform. For example, on Android, you must store this data in a byte array and the size of the data must not exceed 128 KB.
  • Match state. A match can fall into one of the following states: ACTIVEMATCHINGENDED, and UNKNOWN, depending on participant and game actions during the match. The state of a match is managed by the Game Services. Your game can check the match state to determine whether a match can proceed, whether players can join by auto-match, and if the match is over (and if it completed normally or ended because of some user action).

Starting a match

To begin a turn-based match, your game can prompt players to select how they want to be matched to other participants. 

You can start match with the random players:

TBM.Matchmaker.FindMatch(2, 2);

With a pre-defined player. You can retrieve player Id  from the Firends List.

public void StartMatchWithFriend(string FriendId) {
    TBM.Matchmaker.FindMatch(2, 2, new string[]{FriendId});

Or allow the user to use Native Device UI for starting the match.

TBM.Matchmaker.ShowNativeFindMatchUI(2, 2);

Once match is started, ActionMatchFound will be fired. You should subscribe to this action before initializing match search. When an appropriate match is found, a current player makes a move. So it's recommended to redirect a player to the game and allow to make it immediately right after ActionMatchFound is fired. 

TBM.Matchmaker.MatchFoundEvent += HandleActionMatchFound;
TBM.Matchmaker.FindMatch(2, 2);

void HandleActionMatchFound (UM_TBM_MatchResult res) {
	Debug.Log("HandleActionMatchFound " + res.IsSucceeded);
	if(res.IsSucceeded) {
		//Redirect to the play scene and make a move

Loading matches and Invitations

Since most games are updating matches and invitations list in the same time + IOS TBM API doesn't have separate invitation object (invitation in IOS is represented as created match where local player as Invited state), we created a single method to load current available matches and invitations for the local player. The information about the loaded matches and invitations will be delivered inside the UM_TMB_MatchesLoadResult object.

Code snippet below shows how to load available matches and invitations.

TBM.Matchmaker.MatchesListLoadedEvent += HandleActionMatchesInfoLoaded;

void HandleActionMatchesInfoLoaded (UM_TMB_MatchesLoadResult res) {
	Debug.Log("HandleActionMatchesInfoLoaded " + res.IsSucceeded);

	if(res.IsSucceeded) {
		Debug.Log("Total Matches Loaded: " + res.Matches.Count);
		Debug.Log("Total Invitations Loaded: " + res.Invitations.Count);

		foreach(UM_TBM_Match match in res.Matches) {

		foreach(UM_TBM_Invite invite in res.Invitations) {


Match is represented as UM_TBM_Match object. Invitations information contains inside the UM_TBM_Invite objects.


The basic flow for turn-taking is as follows:

  1. If the player initiated a match, check  whether the game data is null. If so, the client should initialize this data as needed by your game. For example, you may need to initialize the starting positions for players in a strategy game or initialize the first hand for players in a card game.

  2. Let the current player perform their normal turn.

  3. Update the match by calling TakeTurn method. In your method call, pass in the following information:

    • New Match Data
    • The player to take the next turn.
  4. Repeat steps 2-3 until the match is completed, or until the game ends some other way.

When a local player turns data submitted the TurnEndedEvent action will be fired. When one of the participants has finished the turn, MatchUpdatedEvent will act, both actions have UM_TBM_MatchResult object inside.

TBM.Matchmaker.TurnEndedEvent += HandleActionTurnEnded;
TBM.Matchmaker.MatchUpdatedEvent += HandleMatchUpdatedEvent;

string MatchId = GetCurrentMatchId();
byte[] MatchData = GetMatchDataForCurrentPlayerTurn();
UM_TBM_Participant NextParticipant = GetNextParticipant();

TBM.Matchmaker.TakeTurn(MatchId, MatchData, NextParticipant);

void HandleActionTurnEnded (UM_TBM_MatchResult res){
	Debug.Log("HandleActionTurnEnded " + res.IsSucceeded);
	if(res.IsSucceeded) {

void HandleMatchUpdatedEvent (UM_TBM_MatchResult res){
	Debug.Log("HandleMatchUpdatedEvent " + res.IsSucceeded);
	if(res.IsSucceeded) {

Completing a match

When the match has been played to completion (for example, a user has won the game), your game should call FinishMatch(...) to upload the user’s game data and signal to other participants that the match is over. When your game invokes this method for the first time during a match, it must be during the user's turn. Then the match appears under the Completed Matches category in the user's match list UI.

UM_TBM_Match Match = GetCurrentMatch();
byte[] MatchData = GetMatchDataForCurrentPlayerTurn();

List<UM_TMB_ParticipantResult> results = new List<UM_TMB_ParticipantResult>();

foreach(UM_TBM_Participant p in Match.Participants) {

	UM_TMB_ParticipantResult r;
	if(p ==  Match.LocalParticipant) {
		r = new UM_TMB_ParticipantResult(p.Id, UM_TBM_Outcome.Won);
	} else {
		r = new UM_TMB_ParticipantResult(p.Id, UM_TBM_Outcome.Lost);


TBM.Matchmaker.FinishMatch(Match.Id, MatchData, results.ToArray());

Leaving a match

Participants can choose to leave at any time during the match, while allowing the match to continue. To signal that a participant is leaving, your game should call either QuitInTurn (...) or QuitOutOfTurn (...). When a participant leaves a match, the match can still continue with other participants as long as these conditions are met:

  • There are two or more other remaining participants, or
  • There is one remaining participant and at least one empty auto-match slot is available.

Otherwise, the match is canceled.

In general, when a participant leaves a match, another player cannot join and take that participant’s place. One exception is when a player who joined by auto-match and who has not taken a turn calls.QuitOutOfTurn (...). In this case, the match reverts to the Matching state and another player can take over the place of the participant who left.

To leave a match, your game can call these methods:

public void Quit() {
	if(Match.IsLocalPlayerTurn) {
	} else {

Dismissing a match

Your game can let users dismiss a turn or invitation so that they do not have to see the match again. This hides the match from the dismisser's match list UI and causes the match to expire eventually. Other match participants can continue to play until the dismissed match expires after two weeks, or until the match is played to completion or canceled (whichever happens first). To other participants, the dismissed still appears as participants in the match. Another player cannot take the dismisser's place.

To dismiss a match, use this method:


Implementing a rematch

When a match is over, a participant may want to play a rematch with the same set of invited and auto matched opponents. Your game can initiate a rematch by invoking Rematch(...) . Your game can only invoke this method when the match state is Ended and no other participants have requested a rematch. If the call is successful, the Play Game services sends invitation notifications to all rematched opponents.

To implement a rematch, use this method:


Differences between platforms

We tried to create Unified turn-based matches API, however there is steel some differences between using API on various platforms. 


Match participants is represented as the UM_TBM_Participant objects, and can be retrieved from the UM_TBM_Match.

IOS.  Match has always participant objects count equals to available match slots, even when there is a pending participants. But only when player joins  free slot of the match participant object, PlayerId and DisplayName will be filled. You can find out if participant has joint player using the IsPlayerDefined property. 

Android. Unlike the iOS, participant slot in the patch is filled only when a player is matched. This means that if you create match for 2 players, participants array can only have 1 object until opponent is matched. PlayerId property of the participant object will be filled only if matched player is in the friend list for the local player.

Match Finishing

IOS. If a player has called FinishMatch method, match will be ended for all match participants with the match data and outcomes provided by the FinishMatch method call.

Android. If player has called FinishMatch method, other participant should confirm finishing the match with the data and outcomes provided by the FinishMatch method call. This step is performed by the plugin automatically.

Match Quilting

If a player decided to quit the match your game should call  QuitInTurn(...) or QuitOutOfTurn(...) methods. Here is the match data defense between platforms after calling the quit methods.


  • Match Status: Active
  • Participant State: Declined
  • Participant Outcome: Disconnected


  • Match Status: Ended
  • Participant State: Declined
  • Participant Outcome: None

Tips and Tricks

1) Visi Turn-Based Scripting API chapter to find out events with more methods and features.

21) If you have matches list UI in your game, you should subscribe at least to the following events:

  • MatchUpdatedEvent
  • MatchesListLoadedEvent
  • InvitationAccepted
  • InvitationDeclined

To make it a bit more comfortable for you, you can subscribe to the single MatchesListUpdated event, which is always called after match or invitation data is updated, and before other corresponded event occurs.

Updated Matches and Invitations list can always be retrieved as shown on the code snippet below:

foreach(UM_TBM_Match match in TBM.Matchmaker.Matches) {

foreach(UM_TBM_Invite invite in TBM.Matchmaker.Invitations) {

3) Instead of using methods from Matchmaker, it can be also used from the match object, for example, following lines of code performing same actions:

UM_TBM_Match Match = GetMatch();


4) UM_TBM_Match and UM_TBM_Participant has lot's of features that can be used to make your life easier especially if you are making TBM match for 2 player.