5.8 Tutorials: Board game (part 1)

The source FLA of this example is available under the Examples/(ActionScript version)/smartFoxTris folder.

» Introduction

SmartFoxTris is a complete mutiplayer version of the famous "Tic-Tac-Toe" game.

Here's a list of features that we're going to achieve:

» users will log in and join a room called "The Entrance" by default;
» users will be able to create a game room where 2 clients can play the tic-tac-toe game;
» as soon as the user creates the game he/she will enter the new game room and wait for the second player;
» when the 2nd player joins, the game starts;
» the application will alternatively set the player's turn and after every move it will check if there's a winner;
» the game ends when no more moves are available or one of the player makes a row of three;
» at the end of a game the user will be able to either start a new game or to go back in the main chat room.

» The application Zone

In the source .FLA file you will notice that we have added a new frame label called "game": that's the frame where we will send the movie clip playhead when we join a game room.

Now bring the playhead on the "connect" label and open the ActionScript panel (F9). We didn't change much of the code here, however the zone name is different. We wanted our game application to have one main room, called "The entrance", users will enter by default: in this room they will be able to chat and create or join new games.

If you open the config.xml file in the SmartFoxServer folder you can better see how this zone is configured:

<Zone name="sftris">
    <Rooms>
        <Room name="The Entrance" maxUsers="50" isPrivate="false" isTemp="false" autoJoin="false" />
    </Rooms>
</Zone>

The zone is setup to contain only one room at start. Then clients will be able to dynamically create as many game rooms as they want from the smartFoxTris interface.

» Join and Chat

Let's move on to the next label and open the ActionScript panel (F9). As usual we will use the same application logic adopted so far, and you will notice that most of the code here is almost identical to the previous examples.

The following line of code setups a flag that will tell us if the user is currently playing a game:

//----------------------------------------------------------
// Setup global vars
//----------------------------------------------------------
inGame = false // flag to see if we're currently playing a game

The "inGame" flag will not be changed until we move to the "game" label so we'll talk about it later.

Next we have a look a the onJoinRoom event handler:

smartfox.onJoinRoom = function(roomObj)
{
        if (roomObj.isGame())
        {
                _global.myID = this.playerId
                
                if (_global.myID == 1)
                       _global.myColor = "green"
                else
                       _global.myColor = "red"
                
                // let's move in the "game" label
                gotoAndStop("game")
        }
        else
        {
                var roomId = roomObj.getId()
                var userList = roomObj.getUserList()
                resetRoomSelected(roomId)
                _global.currentRoom = roomObj
                
                // Clear current list
                userList_lb.removeAll()
                
                for (var i in userList)
                {
                        var user = userList[i]
                        var uName = user.getName()
                        var uId = user.getId()
                        
                        userList_lb.addItem(uName, uId)
                }
                
                // Sort names
                userList_lb.sortItemsBy("label", "ASC")
                
                chat_txt.htmlText += "<font color='#cc0000'>>> Room [ " + roomObj.getName() + " ] joined</font>";
        }
}

The first thing that we have to do is checking if the client has joined a game room. In fact this time we're dealing with two type of rooms: "regular" ones and "game" ones, so each time a room is joined we have to check what type of room the user joined and take the appropriate action.

The isGame() method returns true if the current room is a game room.

The code used to handle the non-game room is always the same used before so we can analyze the part used when a game room is detected.

The playerId variable is a new client API property that we haven't met before. It represent our unique player numeric id
in the room. This way we will be able to check which user is the client that is currently using the application and take the proper decision.

In this sample application every game room will have a capacity of 2 users so the playerId will only be assigned two possible
values: 1 or 2, depending on the room state.

We save the playerId in a _global variable and then, based on its value, we assign a player color and a player name. If playerId is 1, we'll be player 1 and we'll play with the green colored balls, otherwise we will impersonate player 2 and
we'll use red balls.

Then the playhead is stopped on the "game" label.

Before we analyze the ActionScript in the game section we need to take a look at the new createRoom function:

function createRoom(name, pwd, max)
{
        hideWindow("newGameWindow")
        
        gameRoom = {}
        gameRoom.name = name
        gameRoom.password = pwd
        gameRoom.maxUsers = 2
        gameRoom.isGame = true
        gameRoom.isTemp = true
        
        smartfox.createRoom(gameRoom)
}

As usual the "create game" dialog is closed and then we proceed creating the object representing the room that we are going to
create. This time the isGame flag is set to true: this will tell the server that the room will hold a game.

What's the difference between a "regular" room and a "game" one? Almost no difference, however there is a slight difference in the behaviour when the room is empty. In the "Advanced Chat" tutorial we said that "regular" rooms are removed only when the last user exits and the room creator is not connected anymore in the zone. If the creator is still around the room will not be destroyed.

A game room behaves a little differently because it will be removed as soon as the last user leaves it. This is the ony difference.

Also it is important that game rooms are recognizable from the others so that you can group them together for example
in a different list box. This is exactly what we've done in this demo game.

Also the sendChatMsg function was slightly modified:

function sendChatMsg()
{
        if (ingame)
        {
                if (_global.gameStarted && input_txt.text.length > 0)
                {
                        smartfox.sendPublicMessage(input_txt.text)
                        input_txt.text = ""
                }
        }
        else if (input_txt.text.length > 0)
        {
                smartfox.sendPublicMessage(input_txt.text)
                input_txt.text = ""
        }
}

In a moment we will see that that the game area also contains a small chat window where players can keep chatting while playing. The chat dynamic text field instance was named just like the one in the main chat to keep things simple.
However we have added some more checks to prevent text from being submitted if the game is not started yet.

» The game board

Move the playehead on the "game" label and inspect the game GUI:

We've added three new dynamic text fields that will show the names of the players and the one in the middle will show whose turn is. As mentioned before there's a new multiline text field with scrollbar for chatting and the most important movie clip is the game board.

The board movie is made up of nine square clips each one called according its grid position: the top-left one is called sq_1_1 and the bottom right one is called sq_3_3.

Now open the library (F11) and examine the item called "gridSquare", under the _GUI/_gameBoard folder.
The symbol is made up of a colored square, a button and an instance of the "ballElement" movieclip that can be found in the _Balls library folder.

Now open this symbol and you will notice that it has three states corresponding to name of the labels: "off", "red", "green".

We'll be able to control each of these clips inside the game board to show the right item when a user clicks on of the
squares.

» Room variables

Before analyzing the game logic code, we have to understand what "Room Variables" are, and the differences between the already known "User Variables".

The one and only big difference between the two is that Room Variables are values stored in the room object opposed of the user object.

To understand why we need to save variables in the Room object, you can think about how the game works: when a user enter the game room he/she will save a variable called "player1" or "player2" based on which player he is. In order to start the game we need that both variables (player1, player2) exist in the room otherwise the game will be "paused" until both values are present.

By having a "central" place to save our server values, it is very simple to keep track of the status of the game room.

Summing it up the "User variables" are great when you need to save user specific preferences regardless of which room the client is currently in. On the other hand "Room variables" are the right tool when you need to keep track of the status of the Room and this is always an important aspect in game Rooms.

Creating a "Room Variable" is similar to what we've seen so far:

vObj = new Array()
vObj.push({name:"player" + _global.myID, val:_global.myName})

smartfox.setRoomVariables(vObj)

You create an array of objects with two properties each, called "name" and "value", and then call the setRoomVariables() API method to set one or more "Room Variables" in one shot.

As with the "User Variables", every change in the room variables will be notified to all the clients in that room and you will need to implement a function to handle the "onRoomVariablesUpdate" event, which we'll encounter in the next tutorial.


doc index