This exercise will step you through the process of developing a simple Lobby application to handle multiple chat rooms. Because this is the last introduction chapter, let's see how many UI components we can use?not because we have to, but because we can! This chapter will use relatively little ActionScript?just enough to keep it interesting.
The Flash UI components we'll use include the following:
RoomList
Chat
PeopleList
AVPresence
SimpleConnect
AudioConference
ConnectionLight
UserColor
Bandwidth
Just because a large gamut of UI components will be used, you should still build a "use case" scenario to help you when you are coding.
The user opens the Flash movie and is presented with a Login screen containing a Login prompt. There is no password authentication with this application. Everyone has access.
Flash Communication Server accepts all connection requests and signals the client to enter the Lobby screen. The Lobby contains a list of current rooms and an option for the user to create a new room.
Joining a room enters the user into the application instance of the selected room. The user can join a chat using text messaging or capture one of three video windows. Users who do not have video can participate using the Audio chat (audioConference) tool.
At any point, the user can exit the chat room to return to the lobby and connect or create another room.
If the user shuts down his browser, or disconnects during the visit to the room, the application cleans up all records of the user automatically.
As you did in Chapter 9, let's start by building the Flash user interface and then move on to the scripts. The artwork used in these examples is available on the web site for this book (http://flashcom.PangaeaNewMedia.ca/).
Start by preparing the Timeline. Use Figure 10.7 as a reference as you construct it.
Create a new document in Flash MX.
Create six new layers with the following names: Labels, Actions, Login, ConnectionLight, TextPrompts, and UIComponents.
Click Frame 30 on the Labels layer and drag across all layers to highlight them. Insert 30 frames across all layers (F5 or select Insert, Frame).
Create keyframes on all layers on Frames 10 and 20. You can use the same technique highlighting multiple frames. When they are highlighted, press F7 (select Insert, Keyframes).
Remove the keyframe at Frame 20 on the Login layer. Click the keyframe and press Shift+F6.
That's it for the Timeline. Now, assemble the interface components on the Flash stage. Remember to always know where your Timeline cursor is. This is a common mistake when developing in Flash.
The login interface is exactly the same as it was in Chapter 9. Use Figure 10.8 as your layout guide. Follow these steps:
Place your Timeline cursor at Frame 1 on the Login layer. Place the following elements on the Flash stage with this frame selected:
Text Input box with the instance name login_txt.
PushButton #1 (from the standard Flash Communication Server UI components) with the following properties set in the Properties window:
Label: "Login" ClickHandler: "app_Login"
Place your Timeline cursor at Frame 10 on the ConnectionLight layer. Place the following elements on the Flash stage with this frame selected:
PushButton #2 (from the standard Flash UI components) with the following properties set in the Properties window:
Label: "Logout" ClickHandler: "app_Close"
ConnectionLight #1 from the Flash Communication UI components with the instance name connectionLight_mc.
ConnectionLight #2 from the Flash Communication UI components with the instance name connectionLight_rooms_mc.
The ConnectionLights and Logout button will be available across all interfaces except the login, so there is no blank keyframe required on Frame 20. There are two ConnectionLights, so you can monitor two NetConnections (explained later in Exercise 10.2). Place a small text label next to the lights, as shown in Figure 10.8.
The Lobby interface is very simple. Use Figure 10.9 as your guide for layout. It only contains the RoomList UI component and a couple text prompts. Follow these steps:
Click on Frame 10 on the UIComponents layer.
Drag a RoomList UI component from the Communication UI Components panel.
Assign it the instance name of roomsList_mc.
If you want, add some text prompts to Frame 10 on the TextPrompts layer. We won't be using the Room Application Path parameter for this exercise, so just leave it blank.
Add some color to the background to make it friendly for your user, and you are off to the races (see Figure 10.10)!
The Chat Room interface is an assembly of UI components. Really, to demonstrate this tool, all you need is the Chat tool; but because this is the finale, let's have some fun. Each component will exist on the same layer on Frame 20. Use Figure 10.11 to help you build the interface:
Click Frame 20 on the UI Components layer and add the following UI components with their properties as noted:
Chat: | Audio Conference: |
|
|
PeopleList: peopleList_mc | |
Chat Color: | AVPresence: |
|
|
Bandwidth: | |
|
Add some text prompts (as noted in Figure 10.12) at Frame 20 on the Text Prompts layer for your users. Name the text objects: roomname_txt, description_txt, id_txt, username_txt, and roomname2_txt.
That's it for the interface. Add some color to the interface to liven it up and you're ready for coding! The next exercise will add the code.
The ActionScript for this project is straightforward. Because this application uses a lot of UI components, there is very little scripting required. All processes are encapsulated within a series of functions to make it easier to present. Certain methods may not be the most efficient because they are built with training in mind.
The concept behind a Lobby application is switching between application instances. You can maintain multiple NetConnection objects within a single Flash client; you can even be connected to any number of servers at the same time. Maintaining more than one connection exposes the Flash client to resources such as streams or SharedObjects across multiple application instances or servers.
This may not be your best option, especially if user licensing is an issue. Each connection made to the server is registered as a licensed seat. If each Flash client maintains two connections with the server, you have just cut the number of clients that can connect in half. A 10-user license server (Personal edition) supports only five users if each Flash client requires two connections.
Lobby applications must carefully manage their network connections to ensure there are not unnecessary connections being sustained. The ActionScript for this project handles the switching of the application instance connections between the Lobby instance and the rooms instance.
This project, as you already know, takes a much different approach to designing a chat room than is presented in the manual. The underlying difference is that this application is completely integrated within a single movie and application. The manual's application relies on HTML, two separate movies, and two separate applications. Your first job in ActionScript is to reprogram the join method of the RoomList component to not launch a separate browser window.
If you explore the RoomList component's class, you would come across the prototype method, joinRoom();. This method is called internally by the UI component when the Join Room button is clicked on the interface. When called, the prototype method uses getURL() to open a new web browser sending data through the URL scope to JavaScript handlers embedded within the HTML file. We don't want the web browser to be involved. When the user clicks the Join Room button, we want to have the method call a custom function outside the prototype so the processes can be changed easily. When selected, the details about the room are transferred from the SharedObject to a _global structure inside the Flash movie. This lets us access data that will become unavailable when the Lobby connection is closed. Reprogramming the prototype is your first job. Here's what to do:
Open the ActionScript Editor (F9) in Expert mode (Ctrl+Shift+E).
Click Frame 1 on the Actions layer in the Timeline.
Reprogram the joinList prototype. Place the following code as the first script in the editor:
/* FRAME 1: "LOGIN" */ // **REPROGRAM THE JOINROOM PROTOTYPE IN THE ROOMLIST CLASS FCRoomListClass.prototype.joinRoom = function() { var selectedRoom = this.rooms_lb.getSelectedItem().data; // transfer the room data to a local _global variable _global.activeRoom = this.so.data[selectedRoom]; // increment the user count this.so.data[selectedRoom].users++; // invoke a local function, "loginToRoom()" loginToRoom(); };
This method retrieves the selected room index from the component's listbox. It then transfers the selected room object stored in the remote SharedObject to the global structure, activeRoom (see Figure 10.13 for a look at what is stored within the activeRoom object). It increments the users accessing the room, and then calls the function loginToRoom that will be developed a little bit later.
Create a generic onStatus handler to trace the Information object codes; then, overwrite the prototypes for NetConnection, NetStream, and SharedObject:
// **REPROGRAM THE ONSTATUS EVENT PROTOTYPES onStatusTemplate = function (info) { trace("StatusChange: "+info.code); }; NetConnection.prototype.onStatus = onStatusTemplate; NetStream.prototype.onStatus = onStatusTemplate; SharedObject.prototype.onStatus = onStatusTemplate;
Set up two global variables: session is used to store information about the user during the session and FlashComURI is used to define the location of the Flash Communication Server. Because you will be doing a lot of switching between connections, it is helpful to assign the URI to a global variable. Figure 10.13 shows the session and Flash Communication Server objects in use:
// **INITIALIZE THE CLIENT _global.session = new object(); _global.FlashComURI = "rtmp://192.168.0.1/chapter10/";
Create two instances of the NetConnection: one for the lobby and one for the rooms. You could use a single NetConnection object, but for illustration purposes, it is useful to have them as separate instances. Note, you do not connect these objects until the user logs in or selects a room:
// Define the Lobby and Room NetConnections lobby_nc = new NetConnection(); room_nc = new NetConnection();
Attach the two connection lights to the relative NetConnection objects:
// Attach the Connection Lights connectionLight_mc.connect(lobby_nc); connectionLight_room_mc.connect(room_nc);
Create the app_Login function used by the Login button to connect the server to the lobby_nc NetConnection. This function moves the playhead to the Lobby interface, where the function loginToLobby() is called:
// **LOCAL APPLICATION FUNCTION HANDLERS app_Login = function () { // Login Button was clicked, make the connection with the server _global.session.username= login_txt.text; lobby_nc.connect(FlashComURI+"chatLobby", session.username); gotoAndPlay("Lobby"); };
Create the app_close function used by the Logout button to close the lobby_nc connection and move the playhead to the Login interface (Frame 1):
// ** APP_CLOSE app_close = function () { trace("function: app_close"); lobby_nc.close(); root.gotoAndStop("Login"); };
Create a function used by the Logout button to close the room and return to the Lobby interface:
// ** ROOM LOGOUT room_logout = function () { if (room_nc.isConnected) { room_nc.close(); } _root.gotoAndPlay("Lobby"); };
Create the loginToLobby function called by Frame 10, the Lobby interface. Because this function is run each time the playhead enters Frame 20 (or the Lobby interface is displayed), the first process is to determine if the lobby_nc connection is currently active. If it isn't, a connect command re-establishes the connection using the session.username value as the login. The RoomList must be connected.
After the roomsList_mc is (re)connected, you have access to its remote SharedObject. If the user is returning to the lobby from a room, the _global.activeRoom object will contain the room data. Test the object, read the room information, and decrement the users value of the corresponding slot in the SharedObject. When finished, clear the _global structure.
Finally, program the Logout button defining the Click Handler and the label:
// **SETUP THE LOBBY // (this function MUST be run by frame 10, with the RoomList on the stage!) loginToLobby = function () { // reconnect to the Lobby instance if returning from a room if (!lobby_nc.isConnected) { lobby_nc.connect(FlashComURI+"chatLobby", session.username); trace("logged back into the Lobby"); } // Connect the RoomList roomslist_mc.connect(lobby_nc); // decrement the Total users in the room, if the user was connected if (activeRoom != undefined) { roomsList_mc.so.data[activeRoom.id].users?; _global.activeRoom = undefined; } // Reset the Logout Button logout_pb.setClickHandler("app_close"); logout_pb.setLabel("Logout"); };
Create a handler that sets up the room selected by the user. When called, this function closes the Lobby connection and establishes the room connection using the _global.activeRoom object to acquire the instance name (ID) used in the connection string. Again, the session.username value is used to identify the user to the new instance.
Next, reprogram the Logout button defining a new Click Handler and label, and then move the playhead to the Room interface:
// **LOG INTO ROOM loginToRoom = function () { // close the connection to the Lobby Instance lobby_nc.close(); // AUTO-CONNECT TO THE ROOM INSTANCE, USING THE GLOBAL ALREADY DEFINED room_nc.connect(FlashComURI+activeRoom.id, session.username); // REPROGRAM THE LOGOUT BUTTON logout_pb.setClickHandler("room_logout"); logout_pb.setLabel("<< Lobby"); // PLAYHEAD CONTROL _root.gotoAndStop("Room"); };
Finally, ensure the playhead doesn't move until it's told to move. Insert a stop();command:
// CONTROL THE PLAYHEAD stop();
You have already programmed the script for the Lobby interface in Frame 1. The only script in this frame is the call back to the loginToLobby(); function and a playhead stop(); command:
/* FRAME 10: "LOBBY" */ loginToLobby(); stop();
Here is where you will really notice the convenience of using the Flash UI components. The script in this frame does nothing more than connect the UI components and assign the room information to the text objects on the screen. The only thing you need to remember is that the AVComponents need to run the function to assign the username to them before they are operable:
/* FRAME 20: "ROOM" */ // // Connect the UI Components to the new connection chat_mc.connect(room_nc); color_mc.connect(room_nc); peopleList_mc.connect(room_nc); bandwidth_mc.connect(room_nc); audioConf_mc.connect(room_nc); // // Connect the AVPresence Components av1_mc.connect(room_nc); av2_mc.connect(room_nc); av3_mc.connect(room_nc); av1_mc.setUsername(session.username); av2_mc.setUsername(session.username); av3_mc.setUsername(session.username); // // Set the Screen Text Data username_txt.text = session.username; roomName_txt.text = activeRoom.room; description_txt.text = activeRoom.description; owner_txt.text = activeRoom.id; // // **CONTROL THE PLAYHEAD stop();
Create a folder called chapter 10 in the Flash Communication Server's application folder.
There really is no processing done by the server for this application beyond the normal accepting the connection request and setting the username to the UI component framework. Add the following script to a new main.asc file and save it in the chapter 10 folder:
/* CHAPTER 10: LOBBY CHAT ROOM */ load("components.asc"); application.onConnect = function(newClient, newUserName) { gFrameworkFC.getClientGlobals(newClient).username = newUserName; application.acceptConnection(newClient); };
That's all there is to it! This project gives you the foundation for building great Lobby applications using the Flash Communication Server UI components. It has also paved the way for you to start exploring ways to extend the UI components' native functionality. Be sure to check out the book's web site (http://flashcom.PangaeaNewMedia.ca/) for a live example of the Chat room and the source code!