[ READY TO PLAY? ] 
              Now we can analyze the code in the "game" 
              label. Please open the actionscript panel (F9).  
              The first lines of code are mostly initialization stuff: 
            - inGame = true
 
- moveCount = 0
 
- _global.gameStarted = false
 
- _global.whoseTurn = 1
 
-  
  
            The inGame flag is finally set, then the moveCount 
              counter is initialized together with two more _global vars: 
            _global.gameStarted: a flag that tells us if the 
              game is started 
              _global.whoseTurn: a number telling whose player 
              turn is 
             
              The code below shows the player name on screen and the set the opponentID 
              variable: 
           - _root["player" + _global.myID].name.text = _global.myName
 
- opponentID = (_global.myID == 1) ? 2 : 1
  
            As you may have noticed the application can dynamically behave 
              like if it was player one or player two.  
              This is achieved using the _global.myID variable 
              which in turn is a copy of the smartfox.playerId 
              variable: by knowing which player is currently playing we can easily 
              play both sides. 
            The line where we set the opponentID may look 
              a little tricky if you're not used to this type of syntax, however 
              the same line 
              could have been written like this: 
            - if (_global.myID == 1)
 
- opponentID = 2
 
- else
 
- opponentID = 1
 
-  
  
               
              It's a 4 line block of code compressed into a single line!
            We've already commented the following lines: here the room variable 
              for the player is created.  
            - vObj = new Array()
 
- vObj.push({name:"player" + _global.myID, val:_global.myName})
 
-  
 
- smartfox.setRoomVariables(vObj)
  
               
              This is where we notify our arrival to the room and this is also 
              the mechanism that will enable us to control the 
              game flow.
            To see why, please check the onRoomVariablesUpdate 
              handler: 
            - smartfox.onRoomVariablesUpdate = function(roomObj)
 
- {
 
	- if (inGame)
 
	- {
 
		        
                  - var rVars 
                    = roomObj.variables
 
                  - if (rVars["player1"].length 
                    > 0 
                    && rVars["player2"].length 
                    > 0)
 
                  - {
 
                  
                    - if (!_global.gameStarted)
 
                    - {
 
                    
                      - _global.gameStarted 
                        = true
 
                      - hideWindow("gameMessage")
 
                      - _root["player" 
                        + opponentID].name.text 
                        = rVars["player" 
                        + opponentID]
 
                      - _global.whoseTurn 
                        = 1
 
                      - waitMove()
 
                     
                    - }
 
                   
                  - }
 
                  - else
 
                  - {
 
                  
                    - // Reset game status
 
                    - _global.gameStarted 
                      = false
 
                    - resetGameBoard()
 
                    - moveCount = 
                      0
 
                    - var win 
                      = showWindow("gameMessage")
 
                    - win.message_txt.text 
                      = "Waiting 
                      for player " + ((_global.myID 
                      == 1) 
                      ? "2" 
                      : "1") 
                      + newline 
                      + newline 
                      + "press 
                      [cancel] to leave the game"
 
                   
                  - }
 
                 
	- }
  
- }
  
              
              The code above handles three possible cases: 
            1) We are the first user to enter the room, so we need to wait 
              for our opponent  
              2) We are playing the game but our opponent leaves the room or gets 
              disconnected 
              3) The second player has entered and we can start the game. 
            If only one player variable exists in the room we will show a small 
              dialog box that will tell the user to wait his/her opponent. 
              This will also hanlde the case in which one of the two players exits 
              from the room during the game. Also the game board is cleared and 
              the moveCount is set back to zero. 
            If both player variables exist in the room we can set the _global.gameStarted 
              to true, remove the dialog box and initialize the game. Player one 
              will always move first in the first game, then the first move will 
              be done by the client who won the previous game. 
            The control is then passed to the waitMove() method: 
            - function waitMove()
 
- {
 
	- var msg = (_global.whoseTurn == _global.myID) ? "It's your turn" : "It's your opponent turn"
 
	- _root.turn.text = msg 
  
- }
  
            The simple code above shows the turn message based on the player 
              Id and then the application will wait for user interaction. 
            When a user clicks on one of the squares in the game board this 
              code is executed: 
            - on (release)
 
- {
 
	- if (gameStarted)
 
	- {
 
		- if (_global.myID == _global.whoseTurn)
 
		- {
 
			- if (this.status != "R" && this.status != "G")
 
			- {
 
				    
                      - var stat 
                        = (_global.myColor 
                        == "red") 
                        ? "R" 
                        : "G"
 
                      - this.status 
                        = stat
 
                      - this.ball.gotoAndStop(_global.myColor)
 
                      - _root.moveDone(this)
 
                     
			- }
  
		- }
  
	- }
  
- }
 
-  
  
               
              We have three nested if(s) to see if the game is started, if it's 
              the user's turn and finally if the clicked item was not yet taken.
            Each square has a "status" property that can have 3 different 
              values: 
            undefined : if never clicked before 
              "R" : if it contains a red ball 
              "G" : if it contains a green ball 
            If the board cell is free we set it to the user color and invoke 
              the moveDone() method in the main timeline passing 
              a reference 
              to the square movieclip. 
            The moveDone function uses the sendObject 
              API method to send the move data to our opponent: 
            - var x = tile._name.substr(3,1)
 
- var y = tile._name.substr(5,1)
 
-  
 
- smartfox.sendObject({type:"move", x:x, y:y})
 
-  
 
- moveCount++
 
-  
 
- checkBoard()
 
- nextTurn()
 
-  
  
               
            The x and y vars are extracted from 
            the _name String property: as you may remember each 
            square has an instance name like "sq_x_y" By respectively 
            taking the 3rd and 5th char from the instance name we obtain the x 
            and y values. 
            These values are then passed to the sendObject 
              function together with a property called "type" 
              that can have two values: 
            "move", when we're sending a game board 
              move 
              "restart" when we're restarting the game 
              at the end of it. 
            After each move is peformed the checkBoard() function 
              will loop through the board to see if there's a winner and in such 
              case it will  
              stop the game showing the win/lose message. We'll take a closer 
              look to it later. 
            If no winner is found the nextTurn() function 
              is called: 
            - function nextTurn()
 
- {
 
	- _global.whoseTurn = (_global.whoseTurn == _global.myID) ? ((_global.myID == 1) ? 2:1) : _global.myID
 
	- waitMove()
  
- }
 
-  
  
               
               
            What this does is pretty strightforward: the whoseTurn 
            variable is inverted and then we go back to the waitMove() 
            At this point the game flow should be clear:  
            1) Wait for player move 
              2) Check if there's a winner 
              3) If no winner is found switch the active player and go back to 
              1 else the game is over 
            Now that we've seen how the player move is sent to the opponent 
              is time to check the code that handles the reception 
              of a move from the other player(s): 
            - smartfox.onObjectReceived = function(o)
 
- {
 
	- if (inGame)
 
	- {
 
		- // we received a move from the opponent
 
		- if (o.type == "move")
 
		- {
 
			- // Visualize opponent move
 
			- var tile = "sq_" + o.x + "_" + o.y
 
			- var ballColor = (_global.myID == 1) ? "red" : "green"
 
-  
 
			- board[tile].ball.gotoAndStop(ballColor)
 
			- board[tile].status = ballColor.substr(0,1).toUpperCase()
 
-  
 
			- moveCount++
 
-  
 
			- checkBoard()
 
			- nextTurn()
  
		- }
 
		- else if (o.type == "restart")
 
		- {
 
			- restartGame()
  
		- }
  
	- }
  
- }
  
              
              If the "type" property is set to "move" 
              we have to display the opponent move in our board to keep all client's 
              boards in sync. 
            The "tile" variable represents the movieclip 
              name of the cell in the board where the client clicked and the "ballColor" 
              is found 
              by assigning the opposite color to the one we're using. 
            The status property is set by taking the first uppercase char in 
              the ballColor variable ("R" or "G") 
              then the moveCount is incremented 
              and the checkBoard() and nextTurn() 
              methods are called, just like we did previously. 
            You will be able to send a "restart" 
              command when the game finishes and you will be presented a dialog 
              box were you can return 
              in the main chat area or continue playing. 
            The restartGame() method will clear all current 
              game values and start a new game: 
            - function restartGame()
 
- {
 
	- hideWindow("gameEnd")
 
-  
 
	- resetGameBoard()
 
	- moveCount = 0
 
-  
 
	- _global.gameStarted = true
 
-  
 
	- nextTurn()
  
- }
  
               
               
            Now that we've described the flow of the application, we can take 
            a closer look to the checkBoard() function: 
            - function checkBoard()
 
- {
 
-  
 
	          
                - var solution 
                  = []
 
                - // All Rows
 
                - for (var 
                  i = 
                  1; i 
                  < 4; 
                  i++)
 
                - {
 
                
                  - solution.push(board["sq_1_" 
                    + i].status 
                    + board["sq_2_" 
                    + i].status 
                    + board["sq_3_" 
                    + i].status)
 
                 
                - }
 
                - // All Columns
 
                - for (var 
                  i = 
                  1; i 
                  < 4; 
                  i++)
 
                - {
 
                
                  - solution.push(board["sq_" 
                    + i 
                    + "_1"].status 
                    + board["sq_" 
                    + i 
                    + "_2"].status 
                    + board["sq_" 
                    + i 
                    + "_3"].status)
 
                 
                - }
 
                - // Diagonals
 
                - solution.push(board["sq_1_1"].status 
                  + board["sq_2_2"].status 
                  + board["sq_3_3"].status)
 
                - solution.push(board["sq_1_3"].status 
                  + board["sq_2_2"].status 
                  + board["sq_3_1"].status)
 -  
 
                - var winner 
                  = null
 -  
 
                - for (var 
                  i in 
                  solution)
 
                - {
 
                
                  - var st 
                    = solution.pop()
 
                  - if (st 
                    == "RRR")
 
                  - {
 
                  
                    - winner = 
                      "red"
 
                    - break
 
                   
                  - }
 
                  - else if 
                    (st 
                    == "GGG")
 
                  - {
 
                  
                    - winner = 
                      "green"
 
                    - break
 
                   
                  - }
 
                 
                - }
 
                - // TIE !!!
 
                - if (winner 
                  == null 
                  && moveCount 
                  == 9)
 
                - {
 
                
                  - var win 
                    = showWindow("gameEnd")
 
                  - opaqueCover._visible 
                    = true
 
                  - win.message_txt.text 
                    = "Tie !"
 
                 
                - }
 
                - else if 
                  (winner 
                  != null)
 
                - {
 
                
                  - // There is a winner !
 
                  - _global.gameStarted 
                    = false
 
                  - var win 
                    = showWindow("gameEnd")
 
                  - opaqueCover._visible 
                    = true
 
                  - if (_global.myColor 
                    == winner)
 
                  - {
 
                  
                    - // I WON! In the next match, it 
                      will be my turn first
 
                    - var message 
                      = "You 
                      WIN !"
 
                    - _global.whoseTurn 
                      = _global.myID 
                    
 
                   
                  - }
 
                  - else
 
                  - {
 
                  
                    - // I LOST! Next match i will not 
                      move first
 
                    - var message 
                      = "You 
                      LOOSE !"
 
                    - _global.whoseTurn 
                      = (_global.myID 
                      == 1) 
                      ? 2 
                      : 1
 
                   
                  - }
 
                  - win.message_txt.text 
                    = message
 
                 
                - }
 
                -  
 
               
- }
  
               
            Even if there is a lot of code the function works in a very simple 
            way: it creates an empty array called "solutions" 
            and fills it with  
              all possible rows and columns where you can put three items in a 
              row. 
             
            The available solutions are 8 in total: 3 columns + 3 rows + 2 diagonals. 
             
            When the array is populated we loop through it and if one combinantion 
            of three is found then we have a winner! Also we check if  
            there's no more moves available. In that case we'll have a tie. When 
            the game ends the "gameEnd" window is shown and you will 
            be able to start a new game or just leave the room. 
             
            Leaving the room is done by calling the quitGame() 
            method which in turn will call the "leaveGameRoom" 
            function 
            - function leaveGameRoom()
 
- {
 
	          
                - inGame = 
                  false
 
                - gotoAndStop("chat")
 
                - smartfox.getRoomList()
 
               
- }
  
            The inGame flag is put back to "false" 
              and we're sent back to the chat label. The last line of code will 
              refresh the roomList in the current zone and automatically join 
              us in the main chat room called "The Entrance" 
             
              [ CONCLUSIONS ] 
              We have analyzed some of the techniques for building a simple multiplayer 
              turn-based game and what you have learned so far can be applied 
              to many different types of games, not just board ones. 
              Also the limit of two users in very game room can be expanded for 
              games with 4, 6, 8 or more players. 
               
              As usual we'd like to suggest you to analyze the code samples and 
              experiment your own variations, and then in a few time you'll be 
              able to create your own multiplayer games from scratch! 
            Have fun! :-) 
            Lapo 
             
             |