Joining Games Tutorial
From EsWiki
This is a tutorial that covers the steps to allow the user to join a game
Contents |
What You'll Learn
- How to let the user select a game type and join it
- How to set up a base system to easily add more games
Prerequisites
- You must have ElectroServer 4 installed and running.
- You need the client-side ElectroServer 4 API.
- Advanced Chat Tutorial
- EsObject and User Variables Tutorial are recommended
- Game Manager is useful, particularly the GMSInitializer section
Download
If you wish to simply download the entire set of Joining Games files (both server and client, source code and compiled), it is found in JoiningGamesTutorial.zip.
Let's Get Started!
In the steps below you will learn how to upgrade your Advanced chat to build a system that allows different games.
Outline the Goals
This tutorial, though it does cover the additional functionality of joining games (quick join, all that is selected is the game type), it is focused mainly on reworking the advanced chat in order to have a much more robust system. At the end, we will have a system where we can easily add new games/applications for the users to join.
One thing we will do is modularize any functionality that is tied to the Chat screen. What this means that if we have any intention to reuse parts (say showing a user list, or allowing the user to send or receive public messages) we should separate it from the Main class, and place it where it can be used by the games also. So what we will do is create a Modules class that will contain all of that reusable functionality. Then, the Main class and any game classes that are made will be children of it (they will extend the Modules class). The child class can set up any functionality they need, while leaving the unneeded modules dormant. (For instance, some of the game classes will "activate" the public messaging module, but not the room list module ). This way, we can easily customize each application or game without having to rewrite code.
The new functionality we will add is a button on the chat menu that leads to a screen where the user can select the type of game they want to join. In this tutorial we will not look at any specific game or application they could join, but just a simple placeholder game they can join. In the next few tutorials, we will look at different games, which we will be able to integrate fluidly due to the work we will do here.
So as a recap are goals are:
- Modularize the reusable parts of the Chat system
- Add the functionality to allow the user to join a game type from a list
Lets begin looking at what we can modularize.
Creating the Modules Class
First we should figure out what we need to move into the Modules class, those being:
- Sending public messages
- Receiving public messages
- Sending private messages
- Receiving private messages
- Display of users in room
- Display of rooms in zone
We are going to leave joining different rooms (though reusable, the method of selecting will be different) , and the clicking on user/rooms autofilling boxes as this is quite specific to a chat system.
Create the Class
Create a new Actionscript file called Module.as and create the Module class.
Add the following imports:
import flash.events.Event;
import fl.events.ComponentEvent;
import com.electrotank.electroserver4.message.event.ZoneUpdateEvent;
import fl.controls.Button;
import fl.controls.TextInput;
import fl.controls.TextArea;
import fl.controls.List;
import flash.events.MouseEvent;
import flash.display.MovieClip;
import com.electrotank.electroserver4.room.Room;
import com.electrotank.electroserver4.message.event.PublicMessageEvent;
import com.electrotank.electroserver4.message.event.PrivateMessageEvent;
import com.electrotank.electroserver4.message.request.PublicMessageRequest;
import com.electrotank.electroserver4.message.request.PrivateMessageRequest;
import com.electrotank.electroserver4.message.event.UserListUpdateEvent;
import com.electrotank.electroserver4.message.event.JoinRoomEvent;
import com.electrotank.electroserver4.message.event.JoinZoneEvent;
import com.electrotank.electroserver4.message.event.ZoneUpdateEvent;
import com.electrotank.electroserver4.message.MessageType;
import com.electrotank.electroserver4.ElectroServer;
import com.electrotank.electroserver4.user.User;
import com.electrotank.electroserver4.zone.Zone;
Also, we will be using these variables throughout the code:
private var m_sendPublicMessageTextInput:TextInput; private var m_sendPublicMessageRoom:Room; private var m_receivePublicMessagesTextArea:TextArea; private var m_sendPrivateMessageButton:Button; private var m_sendPrivateMessageTextInput:TextInput; private var m_sendPrivateMessageNameInput:TextInput; private var m_receivePrivateMessagesTextArea:TextArea; private var m_userDisplayList:List; private var m_displayUserListRoom:Room; private var m_roomDisplayList:List; private var m_displayRoomListZone:Zone; private static var m_es:ElectroServer;
Sending Public Messages
We will first look at the messaging systems. We want to be able to call functions like enableSendingPublicMessages and enableReceivingPrivateMessages, which is what we will add. Each of these enabling function will take parameters for the components which they will use (like a text area for receiving private messages etc). Sometimes you may not want to tie the display of messages into the handling of messages, but in this case, this is probably simplest way.
The enablingSendingPublicMessages function takes the text input box and the room to send from as parameters. It then sets up a listener on joining a room and will automatically update what room to send messages to when it changes.
The disableSendingPublicMessage function removes the event listeners we added before and sets the variables to null (so they can be removed by the garbage collector if possible).
The setPublicMessageRoom function simply sets the room to send messages to as the one that was just joined (it assumes the user is only is one room ). The sendPublicMessage function is similar to what we have in our Main class, except it uses the values received in the enableSendingPublicMessages.
And there you have it, one "module" is done already. You can simply enable it and disable it with a few lines of code.
Note: You'll see in this module and others that the current room is tracked separately in each module. This allows each module to be independent of each other, and need nothing from any other module.
protected function enableSendingPublicMessages( sendPublicMessageTextInput:TextInput, sendPublicMessageRoom:Room )
{
//Initialize variables
m_sendPublicMessageTextInput = sendPublicMessageTextInput;
m_sendPublicMessageRoom = sendPublicMessageRoom;
//Add listeners
m_sendPublicMessageTextInput.addEventListener( ComponentEvent.ENTER, sendPublicMessage );
m_es.addEventListener(MessageType.JoinRoomEvent, "setPublicMessageRoom", this);
}
protected function disableSendingPublicMessages()
{
m_sendPublicMessageTextInput.removeEventListener( ComponentEvent.ENTER, sendPublicMessage );
m_es.removeEventListener(MessageType.JoinRoomEvent, "setPublicMessageRoom", this);
//Nullify variables
m_sendPublicMessageTextInput = null;
m_sendPublicMessageRoom = null;
}
public function setPublicMessageRoom( e:JoinRoomEvent )
{
m_sendPublicMessageRoom = e.room;
}
private function sendPublicMessage( event:Event )
{
var msg:String = m_sendPublicMessageTextInput.text;
if (msg != "") {
//Empty the textbox
m_sendPublicMessageTextInput.text = "";
//create the request
var pmr:PublicMessageRequest =new PublicMessageRequest();
pmr.setRoomId(m_sendPublicMessageRoom.getRoomId());
pmr.setZoneId(m_sendPublicMessageRoom.getZone().getZoneId());
pmr.setMessage(msg);
//send it
m_es.send(pmr);
}
}
One function that will be used before any module is setup is the setElectroServer function,
which simply sets what the electroserver object is (since it won't change, this one cross-link
between all modules does not break our ability to enable and disable different modules).
protected function setElectroServer( es:ElectroServer )
{
m_es = es;
}
Receiving Public Messages
The module that deals with receiving public messages is set up much the same. The enable function sets up the needed values and listeners. The disable function removes the listeners and nullifies the values. The displayOnPublicMessageEvent is similar to what is in the Main class. It just takes the name of who sent it and the message, and outputs to the appropriate textArea.
Note: You'll see that the enable and disable functions are mark as protected. This means that child classes can access them, and this class itself but no one else. (If a function is marked private, not even the children classes can use it). For instance, this will allow the Main class to use these functions, as it will extend Modules. The functions related to event listeners are marked public because the event listener calls it externally and thus to access it, it must be public.
protected function enableReceivingPublicMessages( receivePublicMessagesTextArea:TextArea )
{
//Initialize variables
m_receivePublicMessagesTextArea = receivePublicMessagesTextArea;
//Add listeners
m_es.addEventListener(MessageType.PublicMessageEvent, "displayOnPublicMessageEvent", this);
}
protected function disableReceivingPublicMessages()
{
//Remove listeners
m_es.removeEventListener(MessageType.PublicMessageEvent, "displayOnPublicMessageEvent", this);
//Nullify variables
m_receivePublicMessagesTextArea = null;
}
public function displayOnPublicMessageEvent(e:PublicMessageEvent):void
{
var from:String = e.getUserName();
var msg:String = e.getMessage();
var toAppend:String = from+": "+msg;
m_receivePublicMessagesTextArea.htmlText += toAppend;
}
Next we will look at private messages.
Sending Private Messages
To enable send private messages, the button to press, the textInput containing the message and the textInput containing the name must be given. The enable and disable functions work as in the other examples. The sendPrivateMessage just gets the name and message from the correct text boxes and sends the message to the server.
protected function enableSendingPrivateMessages( sendPrivateMessageButton:Button, sendPrivateMessageTextInput:TextInput, sendPrivateMessageNameInput:TextInput )
{
//Initialize variables
m_sendPrivateMessageButton = sendPrivateMessageButton;
m_sendPrivateMessageTextInput = sendPrivateMessageTextInput;
m_sendPrivateMessageNameInput = sendPrivateMessageNameInput;
//Add listeners
m_sendPrivateMessageButton.addEventListener( MouseEvent.CLICK, sendPrivateMessage );
}
protected function disableSendingPrivateMessages()
{
//Remove listeners
m_sendPrivateMessageButton.removeEventListener( MouseEvent.CLICK, sendPrivateMessage );
//Nullify variables
m_sendPrivateMessageButton = null;
m_sendPrivateMessageTextInput = null;
m_sendPrivateMessageNameInput = null;
}
public function sendPrivateMessage( event:MouseEvent )
{
var name:String = m_sendPrivateMessageNameInput.text;
var message:String = m_sendPrivateMessageTextInput.text;
if( name != "" && message != "")
{
m_sendPrivateMessageTextInput.text = "";
var pm:PrivateMessageRequest = new PrivateMessageRequest();
pm.setUserNames( [name] );
pm.setMessage( message );
m_es.send( pm );
}
}
Receiving Private Messages
Receiving public messages just requires the textArea to output to. The correct listener is added, and when fired, the displayOnPrivateMessageEvent function outputs the message.
protected function enableReceivingPrivateMessages( receivePrivateMessagesTextArea:TextArea )
{
//Initialize variables
m_receivePrivateMessagesTextArea = receivePrivateMessagesTextArea;
//Add listeners
m_es.addEventListener(MessageType.PrivateMessageEvent, "displayOnPrivateMessageEvent", this);
}
protected function disableReceivingPrivateMessages()
{
//Remove listeners
m_es.removeEventListener(MessageType.PrivateMessageEvent, "displayOnPrivateMessageEvent", this);
//Nullify variables
m_receivePrivateMessagesTextArea = null;
}
public function displayOnPrivateMessageEvent( e:PrivateMessageEvent )
{
var from:String = e.getUserName();
var msg:String = e.getMessage();
//Makes the font red and italicized
var toAdd:String = "<FONT COLOR='#FF0000'><I>" + from+": "+msg + "</I></FONT>";
m_receivePrivateMessagesTextArea.htmlText += toAdd;
}
Next we will look at displaying the user list and room list.
Displaying the User List
To enable the user display list, the current room and the list component must be passed in. Then when either the user joins a new room or when a user list update event is fired, the updateUserList function is called. The updateUserList function gets the users from the current room and adds them to the list. (Also, when a new room is joined, that becomes the room to display the user list of).
protected function enableDisplayOfUserList( userDisplayList:List, displayUserListRoom:Room )
{
//Initialize variables
m_userDisplayList = userDisplayList;
m_displayUserListRoom = displayUserListRoom;
//Add listeners
m_es.addEventListener(MessageType.UserListUpdateEvent, "displayOnUserListUpdateEvent", this);
m_es.addEventListener(MessageType.JoinRoomEvent, "changeUserListOnRoomChange", this);
updateUserList();
}
protected function disableDisplayOfUserList()
{
//Remove listeners
m_es.removeEventListener(MessageType.UserListUpdateEvent, "displayOnUserListUpdateEvent", this);
m_es.removeEventListener(MessageType.JoinRoomEvent, "changeUserListOnRoomChange", this);
//Nullify variables
m_userDisplayList = null;
m_displayUserListRoom = null;
}
public function changeUserListOnRoomChange( e:JoinRoomEvent )
{
m_displayUserListRoom = e.room;
updateUserList();
}
public function displayOnUserListUpdateEvent(e:UserListUpdateEvent)
{
updateUserList();
}
private function updateUserList()
{
var users:Array = m_displayUserListRoom.getUsers();
m_userDisplayList.removeAll();
for (var i:int=0;i<users.length;++i)
{
var u:User = users[i];
m_userDisplayList.addItem({label:u.getUserName(), data:u});
}
}
Displaying the Room List
The display of the room list works very similarly except instead of listening for room changes, it listens for changes in the zone. It first takes the list to display to and the currrent zone. Then, when the user joins a new zone or a zone update event is sent, the room list is updated.
protected function enableDisplayOfRoomList( roomDisplayList:List, displayRoomListZone:Zone )
{
//Initialize variables
m_roomDisplayList = roomDisplayList;
m_displayRoomListZone = displayRoomListZone;
//Add listeners
m_es.addEventListener(MessageType.ZoneUpdateEvent, "displayOnZoneUpdateEvent", this);
m_es.addEventListener(MessageType.JoinZoneEvent, "changeRoomListOnZoneChange", this);
updateRoomList();
}
protected function disableDisplayOfRoomList()
{
//Remove listeners
m_es.removeEventListener(MessageType.ZoneUpdateEvent, "displayOnZoneUpdateEvent", this);
m_es.removeEventListener(MessageType.JoinZoneEvent, "changeRoomListOnZoneChange", this);
//Nullify variables
m_roomDisplayList = null;
m_displayRoomListZone = null;
}
public function changeRoomListOnZoneChange( e:JoinZoneEvent )
{
m_displayRoomListZone = e.zone;
updateRoomList();
}
public function displayOnZoneUpdateEvent(e:ZoneUpdateEvent)
{
//If a room has been created or destroyed
if(e.getActionId() == 0 || e.getActionId() == 1)
{
updateRoomList();
}
}
private function updateRoomList()
{
var rooms:Array = m_displayRoomListZone.getRooms();
m_roomDisplayList.removeAll();
for (var i:int=0;i<rooms.length;++i) {
var u:Room = rooms[i] as Room;
m_roomDisplayList.addItem({label:u.getRoomName(), data:u});
}
}
Congratulations, you have finished creating the Modules class. You now have a lot of reusable code.
Next we will look at updating the Main class to use this functionality.
Updating the Main Class
First of all make the Main class extend the Modules class instead of MovieClip.
First we will look at the enableChatScreen function.
private function enableChatScreen()
{
setElectroServer( es );
enableReceivingPublicMessages( c_chatBox );
enableSendingPublicMessages( c_sendButton, c_textInput, myRoom );
enableReceivingPrivateMessages( c_chatBox );
enableSendingPrivateMessages( c_privateMessage, c_textInput, c_userName );
enableDisplayOfUserList( c_userList, myRoom );
enableDisplayOfRoomList( c_roomList, myZone );
addEventListener(MouseEvent.CLICK, onButtonClick);
}
As you can see now, for the most part the need to add event listeners has been removed (except two).
First the ElectroServer object is set, and then each of the needed modules (in this case all of them), is enabled
and given the starting values. The MouseEvent listener is still set, because some functionality is still used
in it (auto-filling user names, etc.. ). The calls to update the user list and room list at the start were also removed,
as those modules do it on being enabled.
The disableChatScreen function also needs to be updated. This function now just calls the disable function for all the modules and removes the event listener for the mouse and joining rooms.
private function disableChatScreen()
{
disableReceivingPublicMessages();
disableSendingPublicMessages();
disableReceivingPrivateMessages();
disableSendingPrivateMessages();
disableDisplayOfUserList();
disableDisplayOfRoomList();
removeEventListener(MouseEvent.CLICK, onButtonClick);
}
Finally, we need to update the onButtonClick and onJoinRoomEvent functions to remove their functionality that is now in the modules.
In onButtonClick, the ability to send private and public messages is removed. In onJoinRoomEvent, updating the user list and room list is
removed (we will be linking this function to a listener shortly).
private function onButtonClick(e:MouseEvent):void
{
if(e.target == c_joinRoom )
{
attemptToJoinRoom();
}
else if(getQualifiedClassName(e.target) == "fl.controls.listClasses::CellRenderer")
{
//Object is of type CellRenderer
var cell:CellRenderer = e.target as CellRenderer;
var data:ListData = e.target.listData as ListData;
if(data.owner == c_userList )
{
autoFillUserName( data.label );
}
else if(data.owner == c_roomList )
{
autoFillRoomName( data.label );
}
}
else if(e.target == c_logoutButton )
{
logoutUser();
}
}
public function onJoinRoomEvent(e:JoinRoomEvent):void
{
myRoom = e.room;
myZone = zoneManager.getZoneById( e.getZoneId() );
}
Now in the initialize function, add the JoinRoomEvent listener (now this will keep track of what room the
user is in everywhere, not only when in the chat screen).
es.addEventListener( MessageType.JoinRoomEvent, "onJoinRoomEvent", this );
And in the logoutUser function, add the code for removing it.
es.removeEventListener( MessageType.JoinRoomEvent, "onJoinRoomEvent", this );
A lot of functions in the Main class are now not needed and can be removed (though it is not necessary, it is a good idea to clean up).
These include: attemptToSendPrivateMessage, attemptSendMessage, onPublicMessageEvent, onUserListUpdateEvent, showUserList,
onZoneUpdateEvent, showRoomList and onPrivateMessageEvent.
Also, quite a few imports are unneeded. The needed electroserver related imports should now be:
//ElectroServer imports import com.electrotank.electroserver4.message.request.LogoutRequest; import com.electrotank.electroserver4.message.event.JoinRoomEvent; import com.electrotank.electroserver4.message.event.ConnectionEvent; import com.electrotank.electroserver4.message.request.LoginRequest; import com.electrotank.electroserver4.message.response.LoginResponse; import com.electrotank.electroserver4.message.MessageType; import com.electrotank.electroserver4.message.request.LeaveRoomRequest; import com.electrotank.electroserver4.message.request.CreateRoomRequest; import com.electrotank.electroserver4.entities.RoomVariable; import com.electrotank.electroserver4.ElectroServer; import com.electrotank.electroserver4.zone.ZoneManager; import com.electrotank.electroserver4.zone.Zone; import com.electrotank.electroserver4.room.Room;
Congratulations, you have now updated your Main class to use your reusable code.
The current state of the chat application should be exactly what it was when you started (to the user),
except now it is much more flexible.
Now we will look at joining a new game.
Creating the Quick Join Game Menu
Adding the User Interface
We will take a break from the coding side of the things for a moment, and add the necessary UI for joining a game. On the Chat screen, add a Button and label it c_quickJoinGameButton.
Now add a two new blank frames for all layers somewhere in the Interface movieclip (say frame 19 and 20). Label the frame 20 QuickJoinGame and add the code enableQuickJoinGameScreen() to the Actions layer. This function will eventually be similar to the enableChatScreen function. Label frame 19 Prequickjoingame and add the code gotoAndStop("QuickJoinGame") to Actions layer. This will be the frame that is just gone to and immediately left to stop any component issues of sharing names.
For this tutorial, the only functionality we are going to have for quick join game screen is a list of possible game types, a join button and a back button. (Though you could have different options for each game type you select: eg a preferred map).
On the QuickJoinGame frame, add a ComboBox and label it c_gameList. Then add a two Buttons, labelling them c_backButton and c_joinGameButton.
Next, we will look at the changes we will make in the code.
Changing to the Quick Join Menu Screen
First, we need to add a function to detect the press of the QuickJoinGame button and go to that appropriate frame.
We are going to edit the onButtonClick function and also adding the gotoQuickJoinGameScreen. If the QuickJoinGame button is pressed, the gotoQuickJoinGameScreen function is called. This function disables the chat screen, then changes the frame to the Prequickjoingame, which will go to the QuickJoinGame frame and call enableQuickJoinGameScreen().
private function onButtonClick(e:MouseEvent):void
{
if(e.target == c_joinRoom )
{
attemptToJoinRoom();
}
else if(getQualifiedClassName(e.target) == "fl.controls.listClasses::CellRenderer")
{
//Object is of type CellRenderer
var cell:CellRenderer = e.target as CellRenderer;
var data:ListData = e.target.listData as ListData;
if(data.owner == c_userList )
{
autoFillUserName( data.label );
}
else if(data.owner == c_roomList )
{
autoFillRoomName( data.label );
}
}
else if(e.target == c_logoutButton )
{
logoutUser();
}
else if(e.target == c_quickJoinGameButton )
{
gotoQuickJoinGameScreen();
}
}
private function gotoQuickJoinGameScreen()
{
disableChatScreen();
gotoAndStop( "Prequickjoingame" );
}
Now we need to define the enableQuickJoinGameScreen and disableQuickJoinGameScreen functions.
As in the other examples, these function set up and remove the listeners. (Here we are
using a separate listener for each button, but we could just use one function
then test which was clicked). The enable function also populate the list of games
by calling the populateGameList function which we will look at next.
private function enableQuickJoinGameScreen()
{
c_backButton.addEventListener( MouseEvent.CLICK, goFromQuickJoinGameToChat );
c_joinGameButton.addEventListener( MouseEvent.CLICK, quickJoinGame );
es.addEventListener( MessageType.CreateOrJoinGameResponse, "onCreateOrJoinGameResponse", this );
populateGameList();
isQuickJoinGameRequestSent = false;
}
private function disableQuickJoinGameScreen()
{
c_backButton.removeEventListener( MouseEvent.CLICK, goFromQuickJoinGameToChat );
c_joinGameButton.removeEventListener( MouseEvent.CLICK, quickJoinGame );
es.removeEventListener( MessageType.CreateOrJoinGameResponse, "onCreateOrJoinGameResponse", this );
}
Adding to the Main Class
First we need to add some new variables to our Main class and add their declaration to the initialize function.
private var gameList:Array;
private var isQuickJoinGameRequestSent:Boolean;
static public var MainChatZoneName:String = "Chat";
static public var MainChatRoomName:String = "Lobby";
private var chatRoom:Room; //Used to hold the chat room, when myRoom is taken over
public function initialize(serverInfo:Object):void
{
gameList = ["GuessTheNumberGame"];
isQuickJoinGameRequestSent = false;
isConnectionRequestSent = false;
isLoginRequestSent = false;
isConnected = false;
this.serverInfo = serverInfo;
//Create the ElectroServer instance
es = new ElectroServer();
es.addEventListener( MessageType.JoinRoomEvent, "onJoinRoomEvent", this );
}
The array gameList will hold the name of all the games that are available for the user. The isQuickJoinGameRequestSent
stops the user from sending more than one request at a time. The MainChatZoneName and MainChatRoomName will hold those
variables, so we can easily change these values in one place for all the places it is used. Finally, the chatRoom
variable will hold the chatRoom in a special instance.
In the initialize function, we set it to just initialize the requestSent value to false, and the array of possible games to just one game option.
The populateGameList traverses this array, and adds an item in the drop down menu for each game.
private function populateGameList()
{
c_gameList.removeAll();
var i:int = -1;
var length:int = gameList.length;
while( ++i < length )
{
c_gameList.addItem( { label:gameList[i] } );
}
}
Joining a Game
The quickJoinGame function is called when the user clicks the Join Game button. This function gets the name of the selected game then creates a QuickJoinGameRequest instance. When a QuickJoinGameRequest is sent to the server, it looks at the games of that type in the server, if any have room left and are open to be joined, the user is placed in that room. If not, a new room is created. So either way, the user should join a game after this request is sent (unless there is an error). We set the game type and zone name for the QuickJoinGameRequest to create if one matching the search criteria is not found. The search criteria is then added to the request, but only sets the desired game type (custom information could be set up). Then the request is sent to the server.
Note: In order for the server to be able to find a game of a given type, it must be registered on the server, likely by a server-level plugin. This is what the GMSInitializer article shows and is needed for this to work.
We also saved the chatRoom, because after a modification we will make, myRoom will track the current room even when not in the chat. If we did not do this, we would lose track of the chat room and be unable to leave it once we join a game.
public function quickJoinGame( event:MouseEvent )
{
//Get the gameName
var gameType:String = c_gameList.selectedLabel;
if( gameType != "" && !isQuickJoinGameRequestSent)
{
chatRoom = myRoom;
isQuickJoinGameRequestSent = true;
//Send a request to the server to quick join a game of that type
var gameRequest:QuickJoinGameRequest = new QuickJoinGameRequest();
gameRequest.setGameType( gameType );
gameRequest.setZoneName( gameType );
var criteria:SearchCriteria = new SearchCriteria();
criteria.setGameType( gameType );
gameRequest.setSearchCriteria( criteria );
es.send( gameRequest );
}
}
Main Class Code Cleanup
Before we go any farther, we are going to change a few things to make them more general.
Change the joinRoom function to also accept the zoneName parameter, so it is no longer hardcoded in. Then where needed (in a couple of places), set that parameter to MainChatZoneName. Also, change all uses of "Chat" to MainChatRoomName instead. The joinRoom function will look like the following:
private function joinRoom( roomName:String, zoneName:String ):void
{
//tries to create a room. if it already exists, then you join that room
//create the request
var crr:CreateRoomRequest = new CreateRoomRequest();
crr.setRoomName( roomName );
crr.setZoneName( zoneName );
//send it
es.send(crr);
}
Leaving the Chat Room
Now that that is set up, we need to define the onCreateOrJoinGameResponse function.
This function resets the ability to send another request, and if successful, leaves the chat room. The leaveChatRoom function leaves the last chat room and is basically a copy of leaveCurrentRoom. These functions could be combined into one, with a parameter passed in, but passing in the value myRoom does not seem as clear as leaveCurrentRoom (though myRoom could be renamed).
public function onCreateOrJoinGameResponse( e:CreateOrJoinGameResponse )
{
isQuickJoinGameRequestSent = false;
if( e.getSuccessful() )
{
leaveChatRoom();
}
}
private function leaveChatRoom()
{
//NOTE: Can only be used if chatRoom variable was just set
var leaveRequest:LeaveRoomRequest = new LeaveRoomRequest();
leaveRequest.setRoomId( chatRoom.getRoomId() );
leaveRequest.setZoneId( chatRoom.getZoneId() );
es.send( leaveRequest );
}
Returning to the Chat Room
Finally, the player may decide to leave the quick join game screen, which would call the goFromQuickJoinGameToChat.
This function disable the quick join game screen, then if the user had changed rooms out of the chat zone, it leaves the current room and attempts to join the chat room again. Once it has been joined, it changes to the chat screen. (If you did not wait to change screens, while the user joins the room, the data displayed by the modules would be from the game room). If they never left the chat room, it just returns to the chat screen.
public function goFromQuickJoinGameToChat( event:MouseEvent )
{
disableQuickJoinGameScreen();
if( myZone.getZoneName() != MainChatZoneName )
{
leaveCurrentRoom();
es.addEventListener( MessageType.JoinRoomEvent, "chatRoomRejoined", this );
joinRoom( MainChatRoomName, MainChatZoneName );
}
else
{
gotoAndStop("Prechat");
}
}
public function chatRoomRejoined( e:JoinRoomEvent )
{
es.removeEventListener( MessageType.JoinRoomEvent, "chatRoomRejoined", this );
gotoAndStop("Prechat");
}
And that's it! Though you don't have much to show at the moment for all your work,
it will now be easy to add new games. Now is the time to look at setting up the GMSInitializer
plugin if you have not yet done so, as you should be able to successfully join a game room now (though the screen won't
change and there is no game to it). For now, just create a game type of "GuessTheNumberGame" in the GMSInitializer class without any plugins attached to it.
Finished!
Congratulations, your chat and game system is now much more flexible and games can be added more quickly. The next lesson is Game Tutorial: Guess the Number.
