F. Real time multiplayer - myflashlab/GameServices-ANE GitHub Wiki

Starting a real-time multiplayer game

Your main screen is the player's primary entry point to start a real-time multiplayer game, invite other players, or accept a pending invitation. We recommend that at minimum you implement these UI components on the main screen of your game:

  • Quick Game button - Lets the player play against randomly selected opponents (via auto-matching).
  • Invite Players button - Lets the player invite friends to join a game session or specify some number of random opponents for auto-matching.
  • Show Invitations button - Lets the player see any pending invitations sent by another player. Selecting this option should launch the invitation inbox, as described in Handling invitations.

Listening to RealTime Events

If you are using the RealTime API in your game, it's a good idea to set the realtime listeners right after you initialized the ANE Games.init();

if(!Games.realtime.hasEventListener(GamesEvents.REAL_TIME_ROOM_CREATED))
{
	Games.realtime.addEventListener(GamesEvents.REAL_TIME_ROOM_CREATED, onRoomCreated);
	Games.realtime.addEventListener(GamesEvents.REAL_TIME_ROOM_CONNECTED, onRoomConnected);
	Games.realtime.addEventListener(GamesEvents.REAL_TIME_ROOM_JOINED, onRoomJoined);
	Games.realtime.addEventListener(GamesEvents.REAL_TIME_ROOM_LEFT, onRoomLeft);
	
	Games.realtime.addEventListener(GamesEvents.ROOM_STATUS_UPDATED, onRoomStatusUpdated);
	Games.realtime.addEventListener(GamesEvents.WAITING_ROOM_WINDOW_DISMISSED, onWaitingRoomDismissed);
	Games.realtime.addEventListener(GamesEvents.WAITING_ROOM_WINDOW_FAILURE, onWaitingRoomFailure);
	Games.realtime.addEventListener(GamesEvents.WAITING_ROOM_RESULT, onWaitingRoomResult);
	
	Games.realtime.addEventListener(GamesEvents.MESSAGE_SENT, onMessageSent);
	Games.realtime.addEventListener(GamesEvents.MESSAGE_RECEIVED, onMessageReceived);
	
	Games.invitations.addEventListener(GamesEvents.INVITE_PLAYERS_WINDOW_FAILURE, onInvitingPlayersWinFailure);
	Games.invitations.addEventListener(GamesEvents.INVITING_PLAYERS_RESULT, onInvitingPlayersResult);
	Games.invitations.addEventListener(GamesEvents.INVITATION_RECEIVED, onInvitationReceived);
	Games.invitations.addEventListener(GamesEvents.INVITATION_REMOVED, onInvitationRemoved);
}

Quick Game option

When the player selects the Quick Game option, your game should create a virtual room object to join players, auto-match the player to randomly selected opponents without displaying the player picker UI, and immediately start the game.

function startQuickGame():void
{
	var minAutoMatch:int = 1;
	var maxAutoMatch:int = 1;
	var exclusiveBitMask:int = 0;
	var variant:int = -1;
	
	Games.realtime.createRoom(minAutoMatch, maxAutoMatch, exclusiveBitMask, variant, null);
}

If your game has multiple player roles (such as farmer, archer, and wizard) and you want to restrict auto-matched games to one player of each role, add an exclusive bitmask to your room configuration. When auto-matching with this option, players will only be considered for a match when the logical AND of their exclusive bit masks is equal to 0.

Invite Players option

When the Invite Players option is selected, your game should launch a player picker UI that prompts the initiating player to select friends to invite to a real-time game session or select a number of random players for auto-matching. Your game should create a virtual room object using the player's criteria, then start the game session, once players are connected to the room.

To obtain the user's selection, your game can display the built-in player picker UI provided by Google Play games services. To launch the default player picker UI, call the showNativeWindowInvitePlayers method.

var minPlayers:int = 1;
var maxPlayers:int = 3;
var exclusiveBitMask:int = 0;
var variant:int = -1;

Games.realtime.showNativeWindowInvitePlayers(minPlayers, maxPlayers, exclusiveBitMask, variant);

Starting the game before all players are connected

When creating the waiting room, your game can specify the minimum number of players required to start the game session. If the number of connected participants is more than or equal to the specified minimum to start the game, the system enables the Start Playing option in the waiting room UI.

When a player clicks the Start Playing option, the waiting room UI is not automatically dismissed for the other players in the game. To dismiss the waiting room for the other players, your game should send a reliable real-time message to the other players to indicate that the game is starting early. When your game receives the message, it should dismiss the waiting room UI dismissNativeWaitingRoom()

Handling room creation errors/events

To be notified of errors/events during room creation, your game can use the GamesEvents.REAL_TIME_ROOM_* listeners. If a room creation error occurred, your game should display a message to notify players and return to the main screen.

Games.realtime.addEventListener(GamesEvents.REAL_TIME_ROOM_CREATED, onRoomCreated);
Games.realtime.addEventListener(GamesEvents.REAL_TIME_ROOM_CONNECTED, onRoomConnected);
Games.realtime.addEventListener(GamesEvents.REAL_TIME_ROOM_JOINED, onRoomJoined);
Games.realtime.addEventListener(GamesEvents.REAL_TIME_ROOM_LEFT, onRoomLeft);

function onRoomCreated(e:RealTimeEvents):void
{
	if(e.status == Games.SUCCESS)
	{
		_room = e.room;
	}
	else if(e.status == Games.FAILURE)
	{
		trace("onRoomCreated failed: " + e.msg);
	}
}

function onRoomLeft(e:RealTimeEvents):void
{
	if(e.status == Games.SUCCESS)
	{
		trace("onRoomLeft roomId: " + e.roomId);
	}
	else if(e.status == Games.FAILURE)
	{
		trace("onRoomLeft failed: " + e.msg);
	}
}

function onRoomJoined(e:RealTimeEvents):void
{
	if(e.status == Games.SUCCESS)
	{
		_room = e.room;
	}
	else if(e.status == Games.FAILURE)
	{
		trace("onRoomJoined failed: " + e.msg);
	}
}

function onRoomConnected(e:RealTimeEvents):void
{
	if(e.status == Games.SUCCESS)
	{
		_room = e.room;
	}
	else if(e.status == Games.FAILURE)
	{
		trace("onRoomConnected failed: " + e.msg);
	}
}

Connecting players

To be notified when all players are connected, your game can use the GamesEvents.REAL_TIME_ROOM_CONNECTED callback. Your game can also use the GamesEvents.ROOM_STATUS_UPDATED listener to monitor the connection status of the participants. Based on the participant connection status, your game can decide whether to start or cancel the gaming session.

NOTE: The player ID is not the same as the participant ID. A player ID is a permanent identifier for a particular user and is consistent from game to game. A participant ID is a temporary identifier that is valid only for a particular room. Players who were directly invited by name may have both a player ID and a participant ID. Players who joined the room via auto-match will only have a participant ID and not a player ID, to preserve anonymity. Even if you require players to log in with Google+, their player ID can only be used in Games APIs.

Querying a participant's status

The Room.getParticipantStatus property returns the current status of the participant.

Your game can also detect if a participant is connected by calling isConnectedToRoom.

Make sure to construct your game logic carefully to take each participant's status and connectedness into account. For example, in a racing game, to determine if all racers have crossed the finish line, your game should only consider the participants who are connected. Your game should not wait for all players in the room cross the finish line, because not all participants might be connected (for example, one or more players might have left the room or declined the invitation).

Detecting when a player is disconnected

Your player might be disconnected from the room due to network connectivity or server issues. To be notified when the player is disconnected from the room, listen to GamesEvents.ROOM_STATUS_UPDATED and wait for the Room.ROOM_EVENT_DISCONNECTED event.

function onRoomStatusUpdated(e:GamesEvents):void
{
	trace("onRoomStatusUpdated: " + e.roomEvent);

	switch(e.roomEvent)
	{
		case Room.ROOM_EVENT_DISCONNECTED:
			
			// you will leave the room automatically when this happens

		break;
	}
}

Handling invitations

Once the player has signed in, your game may be notified of invitations to join a room created by another player. Your game should handle invitations for these scenarios. All you have to do is to listen to GamesEvents.INVITATION_RECEIVED and optionally join the room using the invitation ID as follow:

function onInvitationReceived(e:GamesEvents):void
{
	trace("id: " + e.invitation.id);
	(e.invitation.invitationType == Invitations.INVITATION_TYPE_REAL_TIME)?trace("type: realtime"):trace("type: turnbased");
	trace("inviter.displayName: " + e.invitation.inviter.displayName);
	trace("inviter.player.displayName: " + e.invitation.inviter.player.displayName);
	
	// we just received an invitation! so the player can now click a button and join the game...
	Games.realtime.joinRoom(e.invitation.id);
}

Another method to check for coming invitations is using the Games.invitations.load method.

Games.invitations.addEventListener(GamesEvents.INVITATION_LOAD_RESULT, onInvitationLoadResult);
Games.invitations.load(Games.SORT_ORDER_SOCIAL_AGGREGATION);

function onInvitationLoadResult(e:GamesEvents):void
{
	if(e.status == Games.SUCCESS)
	{
		trace("onInvitationLoadResult: " + e.invitations.length);
		
		for(var i:int=0; i < e.invitations.length; i++)
		{
			var invitation:Invitation = e.invitations[i];
			trace("\t creationTimestamp: " + invitation.creationTimestamp);
			trace("\t id: " + invitation.id);
			trace("\t invitationType: " + invitation.invitationType);
			trace("\t inviter.displayName: " + invitation.inviter.displayName);
		}
	}
	else if(e.status == Games.FAILURE)
	{
		trace("onInvitationLoadResult failure: " + e.msg);
	}
}

The Invitation Inbox

The Invitation Inbox is an optional UI component that your game can display by calling Games.invitations.showNativeWindow(). The Inbox displays all the available invitations that a player received. If the player selects a pending invitation from the Inbox, your game should accept the invitation and launch the game screen.

Sending messages

Your game can only send messages to connected participants. To send a message, your game can use either the Games.realtime.sendReliableMessage() or Games.realtime.sendUnreliableMessage method, depending on the kind of message to send.

For example, to send a reliable message to another participant:

Games.realtime.sendReliableMessage(
	"my reliable data... " + Math.random(),
	_roomId,
	_otherParticipantId,
	function ($tokenId:int, $error:Error):void
	{
		if($error)
		{
			trace("Games.realtime.sendReliableMessage failure: " + $error.message);
		}
		
		trace("Games.realtime.sendReliableMessage tokenId: " + $tokenId);
	}
);

You can be notified if the message was sent successfully or not by listening to GamesEvents.MESSAGE_SENT

function onMessageSent(e:GamesEvents):void
{
	if(e.status == Games.SUCCESS)
	{
		trace("tokenId " + e.tokenId);
		trace("recipientParticipantId " + e.recipientParticipantId);
	}
	else if(e.status == Games.FAILURE)
	{
		trace("onMessageSent Failure: " + e.msg);
	}
}

Alternatively, your game can use the Games.realtime.sendUnreliableMessage method to send a broadcast message to all participants or one or more particular participants.

Games.realtime.sendUnreliableMessage(
	"unreliable data... " + Math.random(),
	_roomId,
	[],
	function ($error:Error):void
	{
		if($error)
		{
			trace("Games.realtime.sendUnreliableMessage failure: " + $error.message);
		}
	}
);

Receiving messages

When your game receives a message, it is notified by the GamesEvents.MESSAGE_RECEIVED listener.

function onMessageReceived(e:GamesEvents):void
{
	trace("isReliable: " + e.realTimeMessage.isReliable);
	trace("messageData: " + e.realTimeMessage.messageData);
	trace("senderParticipantId: " + e.realTimeMessage.senderParticipantId);
}

Leaving the room

To leave the room, call Games.realtime.leave. After you leave the room, wait until you receive a call to the GamesEvents.REAL_TIME_ROOM_LEFT before attempting to start or join another room.


DISCRIMINATION: We have copied and when needed has modified the Google documents so it will fit the needs of Adobe Air community. If you wish to see the original documentations, visit here. But if you are interested to do things in Adobe Air, then you are in the right place.