5.10 Tutorials: Multi Chat
The source FLA of this example is available under the Examples/AS2/multiChat folder. |
» Introduction
In this new article we'd like to discuss a particular feature of SmartFoxServer: the ability to join one user in multiple rooms at the same time.
» Requirements
Before proceeding with this tutorial it is necessary that you're already
familiar with the basic SmartFoxServer concepts explained
in the previous articles.
» Objectives
In this article I will demonstrate how the "MultiChat" example
file works.
The "MultiChat" is a simple chat application that
allows each user to talk in a room called "Main Lobby" and also
to create and join other custom rooms where you can chat simultaneously.
As soon as the user logs in the chat he's automatically joined in the "Main
Lobby" using the autoJoin() command.
He will be able to create new chat rooms and join one of those without leaving
the "Main Lobby" keeping two public chats open at the same time.
» The basics
This new demo stays consistent with the other examples in terms of code organization,
so the main timeline should look familiar when you will see it the first time.
As usual we have a frame labeled "connect" where
we setup the basic variables and object needed to initialize the application
and connect to SmartFoxServer.
For this application we'll use a zone called "MultiChat" that is defined in the config.xml file on the server side:
<Zone name="multiChat"> <Rooms> <Room name="Main Lobby" maxUsers="50" isPrivate="false" isTemp="false" autoJoin="true" /> </Rooms> </Zone>
The code in the "connect" section is exactly the same we've been using in the other tutorials, so we can safely move to the next frame labeled "chat".
» Handling multiple rooms:
In one of the previous examples we mentioned a property of the SmartFoxClient class
called "activeRoomId".
This property keeps track of the latest
joined room and it is used by the client API in order to know where the user
is located.
Even if this property is not used very much by the Flash developer who is working with SmartFoxServer it is very important behind the scenes because every message that is sent to the server has a roomId property that tells the server from which room the message is coming from.
In other words when you call the server.sendPublicMessage("hello!") the client API sends your text and the room id of the room where the user is currently in. If you inspect the API or just read the API documentation provided in the SFS package you will notice that all methods have an optional roomId parameter that can be used to specify the room from which the message is coming from.
With this in mind the complete form of the sendPublicMessage() method is: server.sendPublicMessage(message, roomId)
The reason why we've never passed the second parameter is because all the other examples can log the user in one room at a time, so the client API already know where the user is located and automagically sends the roomId if we don't specify it.
Now that we want to be present in more than one room at the same time we will have to keep track ourselves of the different rooms where the user is located and send the appropriate id. For example if you're simultaneously connected in the "Main Lobby" and in the "Soccer Room" you will need to specify in which of the two rooms you want your message to be sent to.
In this "MultiChat" example we're going to be automatically joined
in the "Main Lobby" right after the login and we'll be able to join
another room keeping two public chat windows on screen at the same time.
If you inspect the stage contents at the frame labeled "Chat" you
will see how the "double-view" interface is organized: the left
and right parts of the screen are symmetrical with a list box on top for user
names, a text area in the middle for the public chat messages and a single
line input box for sending messages.
In the middle is located another list box that will show all the available rooms, together with a button for creating new ones (labeled NEW) and a button for leaving the "secondary" room. (labeled LEAVE)
» Room ID Variables
At the very beginning of the code located under the "chat" label you will find these two variables:
var mainLobby:Number = -1 var privRoom:Number = -1
We will use these two values to track the roomId number of the "Main
Lobby" and the one of the secondary chat room.
At start up the variables are set to -1 to indicate that you're currently
not logged in any of the two and we'll assign them the right values as soon
as the user joins the "Main Lobby" and the secondary room.
As usual we handle the onRoomListUpdate event by populating the room list box:
smartfox.onRoomListUpdate = function(roomList:Object) { roomList_lb.removeAll() for (var i:String in roomList) { var room:Room = roomList[i] roomList_lb.addItem(room.getName() + " (" + room.getUserCount() + ")", room.getId()) } roomList_lb.sortItemsBy("label", "ASC") // Join the default room this.autoJoin() }
The last line in the method calls the autoJoin() requesting to be joined
in the default room of the current zone.
Now let's have a look at the onJoinRoom handler:
smartfox.onJoinRoom = function(roomObj:Room) { var txtObj:Object var box:Object if (roomObj.getName() == "Main Lobby") { mainLobby = roomObj.getId() txtObj = mainChat_txt box = mainList_lb } else { privRoomName_txt.text = roomObj.getName() privRoom = roomObj.getId() txtObj = privChat_txt box = privList_lb } var roomId:Number = roomObj.getId() var userList:Object = roomObj.getUserList() resetRoomSelected(roomId) _global.currentRoom = roomObj // Clear text area txtObj.htmlText = "" // Clear current list box.removeAll() // Add items to the listbox for (var i:String in userList) { var user:User = userList[i] box.addItem(user.getName(), user.getId()) } // Sort names box.sortItemsBy("label", "ASC") // Add a notice in the chat box txtObj.text += "<font color='#cc0000'>>> Room [ " + roomObj.getName() + " ] joined</font>"; }
As you can notice the code checks if we've joined the "Main Lobby" or
just one of the other available rooms.
In the first case the mainLobby variable is assigned the roomId and the box
variable is pointed to the listbox on the left side of the screen. If we've
joined another room we store its roomId in the privRoom variable and box is
pointed to the listbox on the right side of the screen.
The rest of the code just populates the appropriate list box with the names of the users in the room.
» The Join() command
The smartFox.join() method has already been inspected in the past tutorials and we know it is pretty simple to use: you just pass the name or id of the room you'd like to join.
In the previous examples we have seen how a room called "The Hall" could be joined simply by using this line of code:
smartFox.joinRoom("The Hall")
Now it is time to see the advanced usages of this command. Here follows the complete set of paramaters that you can pass to the method:
smartFox.joinRoom(roomId, password, isSpectator, dontLeave, oldRoom)
roomId | the id of the room you want to join | |
password | the password for the room (needed if the room is password protected) | |
isSpectator | (optional booelan flag) If true joins the user as a spectator in a game room | |
dontLeave | (optional boolean flag) If true the user will not leave the room where he/shw is currently in | |
oldRoom | (optional) the roomId of the room to leave |
As you can see the last two arguments are those we need to instruct the server that we don't want to leave the room we're currently in, while we're joining a new room. Actually the last one allows the developer to specify the id of the room he'd like to leave when he has joined the new one.
Let's take a look at the changeRoom() method which handles the room change request when a user clicks in the room list box:
function changeRoom(evtObj) { if(!_global.isBusy) { // new Room id var newRoom:Number = evtObj.target.value if (newRoom != mainLobby && newRoom != privRoom) { // Check if new room is password protected var priv:Boolean = smartfox.getRoom(newRoom).isPrivate() if (priv) { // Save newroom as _global for later use _global.newRoom = newRoom showWindow("passwordWindow") } else { // Pass the room id if (privRoom == -1) smartfox.joinRoom(newRoom, "", false, true) else smartfox.joinRoom(newRoom, "", false, false, privRoom) } } } }
As you may recall the _global.isBusy variable is a flag
that tells us if the application GUI is currently busy, so we check it before
proceeding with the rest of the code. In the next line we get the value of
the item selected in the list box and we check it against the two room Ids
we've stored previously.
First of all we verufy if the clicked room is different from the current ones,
then we have to see if we're trying to log in a private room: if so we'll
show the password dialog box and ask the user to type a valid password.
The
approach used here is the same of the previous tutorials: we store the id of
the selected room in a _global.newRoom variable, we launch
the dialog box by using the showWindow() function and we handle
the user input in the loginProtectedRoom() method.
Let's analyze the remaining four lines of code: before sending the join request
we have to check if this is the first time we are logging in a "secondary" room.
If privRoom is equal to -1 then we can just join the new
room using the dontLeave flag
set to TRUE, otherwise we have should slightly modify the joinRoom request
telling the server that we want to leave the previous secondary room.
If you
forget to do that, you will join the other rooms without leaving the current
one keeping your user present in as many room as you want at the same time.
In general this is a bad idea since the more rooms you join simultaneously
the more traffic will be generated on the server to send your client all the
events from all the connected rooms.
Also handling all those events from so many rooms can make your application
difficult to code.
Usually two or three rooms at the same time can be more than enough for any
advanced multiuser applications.
An example of using this technique could be a chat with turn-based games where
you can keep talking in public chat rooms while waiting the move of your opponent
in a game of chess, checkers etc...
doc index |