[ 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.
This feature can be pretty useful when you need to develop medium complex applications
and games.
For example you could have a chat system where you can talk to other users in
the "Main Lobby" and simultaneously have other small windows where
you can chat in other public rooms. This could be easily achieved by using the
multi-room capability of SmartFoxServer.
Another idea would be to have a main window for chatting plus one ore more game
rooms where you can simultaneously play with your mates a turn-based game like
chess, checkers, connect-four and so on...
[ 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...
|