Game Tutorial: Guess the Number Client
From EsWiki
Game Tutorial: Guess the Number built a plugin for a Guess the Number game. This article will build a simple client for the game.
Contents |
What You'll Learn
- How to create a multiplayer game client
- How to send messages to the server
- How to process messages from the server
Prerequisites
- You must have ElectroServer 4 installed and running.
- You need the client-side ElectroServer 4 API.
- Joining Games Tutorial
- Game Tutorial: Guess the Number
Download
If you wish to simply download the entire set of Guess The Number files (both server and client, source code and compiled), it is found in GuessTheNumberTutorial.zip.
Let's Get Started!
In the steps below you'll learn how to make the client for the Guess The Number game.
User Interface
This tutorial uses the files from the Joining Games tutorial as a base, so it is recommended you complete that tutorial or use those source files as a starting point.
Planning
We will first briefly discuss what the game will look like to the player.
- The player will join the game from the quick join menu
- The player will see a list of users in the room and be able to chat
- Once at least two players are in the room, a count down will begin until the next round
- The player will have x amount of time to choose a number between 0 and 99
- Once the time is up, the list of winners and their guesses will be displayed
- Once a countdown has finished, the display of winners will be removed
- Countdown to start next round begins
So this is what will happen for the users. The first thing we are going to look at is setting up the UI for this game.
GuessTheNumber frame
Go into the .fla from the Joining Rooms tutorial and go into the Interface movieclip.
Somewhere after all the other frames ( say frame 36 ), add a blank key frame for all layers. Label it GuessTheNumber.
On the GuessTheNumber frame, insert a new movieclip and call it GuessTheNumberGame. Export it for ActionScript with a class name of GuessTheNumberGame (which we will create later). (Just don't add it to the timeline on the frame, as we will add it through code later).
Now inside that movieclip, add three layers called Labels, Actions and Content. In the Content layer we are going to add all the chat pieces that will be used throughout the game. Add a textArea and label it c_chatBox, a textInput and label it c_messageInput, and a List and call it c_userList. Also add a dynamic text box and label it t_timer, it will show how much time is left for each part the game.
More frames
Now add 5 more key frames spaced out with 10-15 frames inbetween. Label frame 1 as Wait, frame 16 as WaitingForPlayers, frame 31 as BeforeGame, then BeforeAnswer, AfterAnswer and finally AfterGame. Remove the timer textbox from the Wait frame and the WaitingForPlayers frame, as it won't be used there.
BeforeAnswer frame
Now on the BeforeAnswer frame we are going to need the ability to both select an item and submit it as your choice. Add a Numeric Stepper component and label c_numberChooser. Set the maximum number to 99, minimum to 0 and the step size to 1. Also add a Button and label it c_submitChoice.
Code for the frames
Now we are going to need to add a bit of code to each frame. Some might wonder why any code needs to be on the frame, but the reason is the code that is executed on that frame needs the content of that frame, but if one just codes gotoAndStop and then calls the appropriate function, things seem not work properly (does not instantly load).
Add the following code to the appropriate frame.
//Frame Wait stop(); //Frame WaitingForPlayers startWaiting(); //Frame BeforeGame startCountDown(); //Frame BeforeAnswer startRound(); //Frame AfterAnswer startWaitingAfterGuess(); //Frame AfterGame startGameOver();
We will define these functions later, but they mainly initiate the actions of the particular sections.
Also, add a button to the AfterGame, WaitingForPlayers, and Wait frame, call it c_leaveGameButton and place it in the same position in both frames (otherwise there may be an issue of components not changing positions).
For now, we are finished the necessary UI.
Note: Make sure that when using the same components over multiple frames that you copy and paste them between frames, so Flash knows they are the same component (Control-Shift-V pastes in the same place). Sometimes there are issues of even though things look the same, Flash does not recognize them as the same. This causes things like the chat box to be cleared between frames, and for our Modules class to have issues since the event listeners on the objects will be removed. If these problems arise, try to copy and paste the components from one frame to all others.
Now we will look at the addition to the Modules class.
Modules class
One functionality that will be used in different game situations is allowing the user to leave the game room. Since this idea will be used by many things, it makes it an ideal candidate for addition to the modules class.
Imports and class variables
Add the following imports and variables to the Modules class:
import com.electrotank.electroserver4.message.request.LeaveRoomRequest; private var m_leaveGameButton:Button; private var m_leaveGameMainInstance:Main; private var m_gameRoomToLeave:Room;
Functions
The enableLeaveGameRoom and disableLeaveGameRoom functions are similar to the other enable and disable functions: they initialize/nullify the variables and add/remove the listeners. The button passed in is the one which must be clicked to leave, the room is the one to leave, and the instance of Main is to be able to send the movie timeline to the prechat frame. It should be noted that this module does not track what room the user is in past the initial one, as it is unlikely that it would change during the game. This functionality could be added, but is unneeded at the moment.
When the user clicks the designated button, a leaveRoomRequest is sent to the server with the appropriate information. Then we attempt to join the main chat room. A listener is added to listen for when the chat room is successfully joined. Once it has been joined, the frame is changed. (If we did not wait, and instantly changed the frame, the Modules functionality would think the current room was still the game room, though we were in the lobby. Thus, maybe for just a moment, the list of users in the game room would show up in the chat room).
The function disable is called once the user has joined the chat room. This function is blank in the Modules class, but the classes that extend Modules can override it to do any necessary disabling, which we will see later on.
protected function enableLeaveGameRoom( leaveGameButton:Button, gameRoomToLeave:Room, mainInstance:Main )
{
//Note: This module does NOT track if the players changes room
//Assumes the room will not change was enabled (but could be changed to allow it)
m_leaveGameButton = leaveGameButton;
m_gameRoomToLeave = gameRoomToLeave;
m_leaveGameMainInstance = mainInstance;
m_leaveGameButton.addEventListener( MouseEvent.CLICK, leaveGameRoom );
}
protected function disableLeaveGameRoom()
{
//Remove listeners
m_leaveGameButton.removeEventListener( MouseEvent.CLICK, leaveGameRoom );
//nullify variables
m_leaveGameButton = null;
m_gameRoomToLeave = null;
m_leaveGameMainInstance = null;
}
public function leaveGameRoom( event:MouseEvent )
{
//Leaves the game room, then joins the main chat room
//Once joined, switches to the chat frame
var leaveRequest:LeaveRoomRequest = new LeaveRoomRequest();
leaveRequest.setRoomId( m_gameRoomToLeave.getRoomId() );
leaveRequest.setZoneId( m_gameRoomToLeave.getZoneId() );
m_es.send( leaveRequest );
m_es.addEventListener( MessageType.JoinRoomEvent, "chatRoomJoined", this );
//Join the main chat room
var crr:CreateRoomRequest = new CreateRoomRequest();
crr.setRoomName( Main.MainChatRoomName );
crr.setZoneName( Main.MainChatZoneName );
//send it
m_es.send(crr);
}
public function chatRoomJoined( e:JoinRoomEvent )
{
if( e.getRoomName() == Main.MainChatRoomName && e.getZoneName() == Main.MainChatZoneName )
{
//Correct room is joined
m_es.removeEventListener( MessageType.JoinRoomEvent, "chatRoomJoined", this );
m_leaveGameMainInstance.gotoAndStop( "Prechat" );
disable(); //Likely calls childs disable function
}
}
public function disable()
{
}
Now we will look at the new class we will make for the GuessTheNumberGame.
GenericGame interface
Create a new class named GenericGame, where the whole class will be the following:
package
{
public interface GenericGame
{
function enableLogic( toSet:Main ):void;
function disableLogic():void;
function enableDisplay():void;
function disableDisplay():void;
}
}
The enableLogic function will turn on the logic of the game, and be passed the instance of Main, so it can access it when needed. The enableDisplay will set up any modules or anything that works with the display, that is not directly the logic of the game. The disable functions will disable their respective things.
GuessTheNumberGame class
Create a new class and call it GuessTheNumberGame and have it extend Modules and implement GenericGame, which will look like this:
public class GuessTheNumberGame extends Modules implements GenericGame
What this means is that the GuessTheNumberGame class will extend the Modules class, but also define all the functions that are in the GenericGame interface. An interface lists a set of functions that must all be defined in anything that implements it. In this case, the GenericGame interface will only have four functions for now, but this will allow the Main class to use those functions later on (since we can assume every game implements GenericGame).
The GuessTheNumberGame class will make use of all the different modules we made in the Joining Games Tutorial.
Imports
We will need these imports:
import flash.text.TextField; import com.electrotank.electroserver4.room.Room; import com.electrotank.electroserver4.ElectroServer; import com.electrotank.electroserver4.esobject.EsObject; import com.electrotank.electroserver4.message.request.PluginRequest; import com.electrotank.electroserver4.message.MessageType; import com.electrotank.electroserver4.message.event.PluginMessageEvent; import flash.events.MouseEvent; import flash.events.Event; import flash.utils.getTimer;
Class variables
And these variables:
private var m_currentRoom:Room;
private var m_gameState:int;
private var m_playersGuess:int;
private var m_Main:Main;
private var m_isScoreSent:Boolean;
private var m_isTimer:Boolean;
private var m_startTime:Number;
private var m_timerLength:Number;
private var m_isDisplay:Boolean;
private var m_resultsArray:Array;
private var m_secretNumber:int;
private var m_timeLeft:int;
public static var TAG_GUESS:String = "guess";
public static var TAG_ACTION:String = "action";
public static var TAG_TIME_LEFT:String = "time";
public static var TAG_PLAYERS:String = "players";
public static var TAG_NAME:String = "name";
public static var TAG_WINNER:String = "won";
public static var TAG_SECRET:String = "secret";
public static var TAG_ACTION_COUNTDOWN:String = "countdown";
public static var TAG_ACTION_START:String = "start";
public static var TAG_ACTION_STOP:String = "stop";
public static var TAG_ACTION_CURRENTSTATE:String = "currentstate";
public static var TAG_GAMESTATE:String = "gamestate";
public static var STATE_WAITING:int = 0;
public static var STATE_COUNTING_DOWN:int = 1;
public static var STATE_IN_PLAY:int = 2;
public static var STATE_GAME_OVER:int = 3;
public static var STATE_ATTEMPT_JOIN:int = 4;
These variables will be used as we progress through the tutorial. You may notice that a lot of these are from the server side portion and that is so the messages sent between client and server can be easily be retrieved from the EsObject. You may also notice there is an additional state then there is on the server side. This is because when the user joins, they will be in a state of limbo waiting for more players or for the next round to begin, and will be in this state.
Separation of logic and display
One problem that we will approach in this game is separating the logic of the game from the display. This class is the same as the display, but sometimes we may want the logic of the class without the display of it. The main example of that is this: If we send a request to the server to quick join a given game, we want to wait for the response to actually display joining the game. If we don't separate the logic from the display, we will wait to enable the logic also. The issue arises when we join a game and the plugin sends messages as we join, we won't be able to handle it since the logic is not set up as we wait to join the game, but after we know we have joined it. Thus what we need to do is set up the logic before we attempt to join a game of the given type, and then once we get the response, turn on the display. If for some reason we fail to join a game, we would have to delete the game and its logic, since it will be unused. In this example though, it should never fail as we are using QuickJoinGame.
We will thus have separate enable functions for each, and though there may be objects to display when just the logic is turned on (frame 1 has content), we won't add the MovieClip to the display list until later.
enableLogic
So lets take a look at the enableLogic function.
It first sets up the initial values of some of the member variables and then adds the listener for receiving plugin messages. It also saves the instance of Main that was passed in.
public function enableLogic( toSet:Main ):void
{
m_Main = toSet;
//Initialize values
m_isDisplay = false;
m_isScoreSent = false;
m_gameState = STATE_ATTEMPT_JOIN;
m_isTimer = false;
//Add custom variable and listeners
m_es.addEventListener( MessageType.PluginMessageEvent, "receiveMessage", this );
}
receiveMessage
The receiveMessage function contains a lot of the functionality of the whole game, as it is what handles what the server sends to the client.
The function first gets the EsObject from the PluginMessageEvent then checks to make sure the TAG_ACTION property exists on it. This is a simple test to validate that the correct information was received, and it isn't another plugin sending a message. (Though the other plugin could have an EsObject with a propery TAG_ACTION. You can also check the name of the plugin that sent the message, but in this case we assume it is the one we want). Then, depending on the message type, we perform the appropriate actions. This function mainly just saves the variables the EsObject contained for later use and then calls the updateGame function which will change the game state.
In each case the time remaining is extracted and the startAndSetTimer function is called with the appropriate time. The startAndSetTimer function, which we will look at later, sets how long the timer should run and when it started, which is when this function is called. It does not actually display the timer though. Depending on what action was done, the game state is set. In this case of the game being over, the secret number and the results array is also saved.
public function receiveMessage( e:PluginMessageEvent )
{
//This functions saves the variables, and then calls updateGame to change the frame as appropriate
var message:EsObject = e.getEsObject();
var m_timeLeft:int;
if( message.doesPropertyExist( TAG_ACTION ) )
{
var messageType:String = message.getString( TAG_ACTION );
if( messageType == TAG_ACTION_COUNTDOWN )
{
m_timeLeft = message.getInteger( TAG_TIME_LEFT );
startAndSetTimer( m_timeLeft );
m_gameState = STATE_COUNTING_DOWN;
updateGame();
}
else if( messageType == TAG_TIME_LEFT )
{
m_timeLeft = message.getInteger( TAG_TIME_LEFT );
startAndSetTimer( m_timeLeft );
//Don't need to try to change anything if time remaining just sent
}
else if( messageType == TAG_ACTION_START )
{
m_gameState = STATE_IN_PLAY;
m_timeLeft = message.getInteger( TAG_TIME_LEFT );
startAndSetTimer( m_timeLeft );
updateGame();
}
else if( messageType == TAG_ACTION_STOP )
{
m_gameState = STATE_GAME_OVER;
m_timeLeft = message.getInteger( TAG_TIME_LEFT );
startAndSetTimer( m_timeLeft );
m_resultsArray = message.getEsObjectArray( TAG_PLAYERS );
m_secretNumber = message.getInteger( TAG_SECRET );
updateGame();
}
}
}
Changing the Game State
The updateGame function makes sure the game is displayed, then changes the frame to the appropriate one. If it is going to the game over state, it removes the event listener on the submit guess button and tells the user they didn't make a guess if they hadn't.
private function updateGame()
{
if( m_isDisplay )
{
//Game is ready to go, game state and time if applicable should be set
if( m_gameState == STATE_WAITING )
{
gotoAndStop( "WaitingForPlayers" );
}
else if( m_gameState == STATE_COUNTING_DOWN )
{
gotoAndStop( "BeforeGame" );
}
else if( m_gameState == STATE_IN_PLAY )
{
gotoAndStop("BeforeAnswer");
}
else if( m_gameState == STATE_GAME_OVER )
{
if( !m_isScoreSent )
{
c_submitChoice.removeEventListener( MouseEvent.CLICK, submitGuess );
output("You didn't make a guess!");
}
gotoAndStop( "AfterGame" );
}
else if( m_gameState == STATE_ATTEMPT_JOIN )
{
output( "Waiting for game to reset and for players to join. " );
}
//Must be hidden each time
hideTimer();
}
}
Finally, the disableLogic function just removes the event listener for plugin messages.
public function disableLogic():void
{
//Remove custom listeners
m_es.removeEventListener( MessageType.PluginMessageEvent, "receiveMessage", this );
}
Next we will look at enabling the display.
Enabling the Display
The enableDisplay function retrieves the current room (which is the game room, not the chat room when this is called) and then initializes the needed modules. Afterwards, it calls the updateGame function to move the frame to where it should be.
public function enableDisplay():void
{
m_isDisplay = true;
//Wait to get the current room until the display is called, which comes after the correct room is joined
m_currentRoom = m_Main.getCurrentRoom();
//Add specific modules
enableSendingPublicMessages( c_messageInput, m_currentRoom );
enableReceivingPublicMessages( c_chatBox );
enableReceivingPrivateMessages( c_chatBox );
enableDisplayOfUserList( c_userList, m_currentRoom );
enableLeaveGameRoom( c_leaveGameButton, m_currentRoom, m_Main );
updateGame();
}
The disableDisplay function is similar to other disable functions in that it disables the appropriate modules.
The other thing it does it remove itself from the Main movieclip, to which it was attached (and should be
when this is called).
public function disableDisplay():void
{
//Remove modules
disableSendingPublicMessages();
disableReceivingPublicMessages();
disableReceivingPrivateMessages();
disableDisplayOfUserList();
disableLeaveGameRoom();
m_Main.removeChild( this );
}
The disable function, which we talked about earlier will call both disableDisplay and disableLogic.
The disable function is called when the user leaves the room.
override public function disable()
{
disableLogic();
disableDisplay();
}
Next we will look at the timer.
The Timer
The timer is used to display the time left of any round.
The startAndSetTimer function sets the timer to the given length and specifies the start time as the current time.
The displayTimer function adds a function to be called every frame, if it is not already. It also calls the updateTimer function so that the time is not blank for one frame.
The hideTimer function removes the event listener to update the timer every frame.
The updateTimerEachFrame function just calls the updateTimer function.
The updateTimer function calculates the time that remains, makes the smallest possible value 0, and then assigns the text of the text box we created earlier to it.
private function startAndSetTimer( time:int )
{
m_timerLength = time;
m_startTime = getTimer()/1000;
}
private function displayTimer()
{
if( !m_isTimer )
{
m_isTimer = true;
addEventListener( Event.ENTER_FRAME, updateTimerEachFrame );
}
updateTimer();
}
private function hideTimer()
{
if( m_isTimer )
{
m_isTimer = false;
removeEventListener( Event.ENTER_FRAME, updateTimerEachFrame );
}
}
public function updateTimerEachFrame( e:Event )
{
updateTimer();
}
private function updateTimer()
{
//Round the value, and make sure it doesn't go below 0
m_timeLeft = Math.round(m_timerLength - (getTimer()/1000 - m_startTime));
m_timeLeft = Math.max( 0 , m_timeLeft );
t_timer.text = m_timeLeft.toString();
}
Another small function that we've seen before is the output function, which just adds
text to the chat box.
It colors the text blue, and then scrolls down as far as possible.
private function output(msg:String):void
{
c_chatBox.htmlText += "<FONT COLOR = '#0099FF'>" + msg + "</FONT>";
c_chatBox.verticalScrollPosition = c_chatBox.maxVerticalScrollPosition;
}
Next we will look at the functions that are called on the different frames.
Game State Functions
We will look at these functions chronologically, as a player progress through the game.
The startWaiting function simply enables the leave game button and outputs a message. It is called when a player is waiting for another to play with (though because of the logic setup, this not reached unless a game is played and the other users leave during the game).
You'll notice we do not actually disable the leaveGameRoom module and that is because it is automatically removed when the frame is changed to one where the button does not exist. (This is true for all event listeners on buttons, but it is much more clean to remove them explicitly ).
private function startWaiting()
{
enableLeaveGameRoom( c_leaveGameButton, m_currentRoom, m_Main );
output( "Waiting for at least two players." );
}
The startCountDown function is called during the period when two players are in the game, and waiting
for a time to allow more players to join. It sets the timer to display and then outputs a message.
private function startCountDown()
{
displayTimer();
output( "Starting count down timer." );
}
The startRound function is called when a round begin. It adds a listener to the button for sending
the guess to the server and displays the timer.
The submitGuess function gets the value to send from the numeric ticker and then creates a pluginRequest. It sets the name of the plugin and the room and zone ID of the plugin. It also attaches the EsObject that contains the guess and then sends it to the server. Finally, it removes the listener on the submit button, hides the timer (to stop the timer error) and changes the frame.
private function startRound()
{
output("The round has begun! Choose a number between 0 and 99!" );
c_submitChoice.addEventListener( MouseEvent.CLICK, submitGuess );
m_isScoreSent = false;
displayTimer();
}
public function submitGuess( event:MouseEvent )
{
m_isScoreSent = true;
m_playersGuess = c_numberChooser.value;
output("Your guess was " + m_playersGuess.toString()+ "." );
var message:EsObject = new EsObject();
message.setInteger( TAG_GUESS, m_playersGuess );
var sendGuess:PluginRequest = new PluginRequest();
sendGuess.setEsObject( message );
sendGuess.setPluginName( "GuessTheNumberGame" );
sendGuess.setRoomId( m_currentRoom.getRoomId() );
sendGuess.setZoneId( m_currentRoom.getZoneId() );
m_es.send( sendGuess );
c_submitChoice.removeEventListener( MouseEvent.CLICK, submitGuess );
hideTimer();
gotoAndStop( "AfterAnswer" );
}
The startWaitingAfterGuess function simply sets the timer to display.
private function startWaitingAfterGuess()
{
displayTimer();
}
Finally, when the game is over, the startGameOver function is called.
This displays the timer until the next round, and calls function to display
the secret number and the winners. It also enables the ability to leave the game.
We also know, looking at the server code, that if the time is not greater than 0, we are waiting for players. (If there are two or more players the time will be the amount of time until the next countdown begins).
The displaySecretNumber function outputs the secret number.
The displayWinners function loop through all the results and removes all those who are not winners. Then it loops through and outputs the name and guess of all the winners (and the appropriate text before hand).
private function startGameOver()
{
enableLeaveGameRoom( c_leaveGameButton, m_currentRoom, m_Main );
displayTimer();
displaySecretNumber();
displayWinners();
if( m_timeLeft > 0 )
{
output( "Round is over. Restarting soon." );
}
else
{
gotoAndStop("WaitingForPlayers");
}
}
private function displaySecretNumber()
{
output("The secret number was " + m_secretNumber.toString() +"." );
}
private function displayWinners()
{
var i:int = m_resultsArray.length;
var player:EsObject;
//First remove all the not winners from the array
while( --i > -1 )
{
player = m_resultsArray[i] as EsObject;
if( player.getBoolean( TAG_WINNER ) == false )
{
m_resultsArray.splice( i, 1 );
}
}
//Then loop through the array
i = m_resultsArray.length;
if( i == 0 )
{
output("No one made a guess! No one wins. ");
}
else if( i == 1 )
{
output("The winner is: ");
}
else
{
output("The winners are: ");
}
//Display all the winner
var playerName:String;
var guess:int;
while( --i > -1 )
{
player = m_resultsArray[i] as EsObject;
playerName = player.getString( TAG_NAME );
guess = player.getInteger( TAG_GUESS );
output(" " + playerName+" with a guess of " + guess.toString() );
}
}
Congratulations, the GuessTheNumberGame class is done. All we need to do now is make a few changes to
the Main class.
Update the Main Class
We will add add the following variables to the Main class.
private var gameType:String; public var currentGame:Modules; private var gameClassList:Array; private var userName:String;
We also need to edit the initialize function to define the gameList and gameClassList to include GuessTheNumberGame.
The gameClassList holds the name of the class to create when the corresponding gameList item is selected. In this
case the name of the class and name of the game is the same.
public function initialize(serverInfo:Object):void
{
gameList = ["GuessTheNumberGame"];
gameClassList = [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 );
}
We also need to edit the quickJoinGame and onCreateOrJoinGameResponse functions.
The quickJoinGame function will now create an instance of the selected game type and call its enableLogic function. Notice that it casts the object to the GenericGame interface we created earlier, to show it that the enableLogic function does exist.
The onCreateOrJoinGameResponse function will now disable the quick join game screen and change the frame to the one with the games name. It then adds the game to the display list, casts the game to the GenericGame class and calls the enableDisplay function on it.
public function quickJoinGame( event:MouseEvent )
{
//Get the gameName
gameType = c_gameList.selectedLabel;
var rowSelected:int = c_gameList.selectedIndex;
if( gameType != "" && !isQuickJoinGameRequestSent)
{
chatRoom = myRoom;
currentGame = new gameClassList[rowSelected]();
var game:GenericGame = currentGame as GenericGame;
game.enableLogic( this );
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 );
}
}
public function onCreateOrJoinGameResponse( e:CreateOrJoinGameResponse )
{
isQuickJoinGameRequestSent = false;
if( e.getSuccessful() )
{
leaveChatRoom();
disableQuickJoinGameScreen();
addChild( currentGame );
var game:GenericGame = currentGame as GenericGame;
game.enableDisplay();
gotoAndStop( gameType );
}
else
{
//Game should be deleted
}
}
For a bit of housekeeping, we will now keep track of the username of the player on the client side.
Change the onConnectionEvent function to save the username, as shown in the following code.
public function onConnectionEvent(e:ConnectionEvent):void {
isConnectionRequestSent = false;
if (e.getAccepted()) {
output("Connection accepted");
isConnected = true;
zoneManager = es.getZoneManager();
userName = c_loginInput.text;
attemptLogin( userName );
output("Attempting to login as: "+c_loginInput.text);
}
else
{
output("Connection failed: "+e.getEsError().getDescription());
}
}
The last thing we need to add is the getCurrentRoom and the getUserName functions, which just
return their respective values.
public function getCurrentRoom():Room
{
return myRoom;
}
public function getUserName():String
{
return userName;
}
Congratulations, you've finished your first game!
Finished!
You are now done your first multiplayer game and can now approach larger games.
