Tutorials/TicTacToeJavaScript

From CubeiaWiki

Jump to: navigation, search

Contents

JavaScript Tic-tac-toe Client

Introduction and Prerequisites

In this tutorial, we will create a JavaScript tic-tac-toe client. It requires that you have Firebase running with the tic-tac-toe game deployed. Please follow the tic-tac-toe script tutorial.. You can stop after step 5, since you don't need to create the Flex client.

This tutorial is an extension of the JavaScript hello world tutorial, so if you want to learn the basics first, you might want to start there.

We are using jQuery in this tutorial, so if you know nothing about that, you might want to read up a bit, although it's not too hard to get the gist anyway.

Here's a peek at what the finished client will look like:

Protocol

The server protocol used in this tutorial will be JSON, which is very convenient to use in JavaScript. When we get a packet from the server, all we need to do is base64 decode it and create a string from the binary data, like so:

    var byteArray = FIREBASE.ByteArray.fromBase64String(packet.gamedata);
    var message = utf8.fromByteArray(byteArray);

The JSON received from the parsing above is actually a string, so before we can use it in code, we need to convert it, which jQuery can do for us:

json = jQuery.parseJSON(message);

Now we have the packet data as JSON. Here's an example of what a message might look like:

  { "action" : "start", "pid" :1, "board" : "ZOZZXZZZO" }

Where "pid" means playerId and points out the player who this message is related to, in this case whose turn it is to act.

The action defines what the client is supposed to do and can be one of:

  • start - a game is starting, make sure the board is empty
  • update - a player has made a move, update the board to reflect the new situation
  • act - it's your turn to act
  • win - someone has won, game over man
  • tie - it's a draw

The board is represented as an array of 9 characters where each character denotes one of the cells in the board, in this order:

0 1 2
3 4 5
6 7 8

Each cell can be either empty, which is denoted by a 'Z', a cross ('X') or a naught ('O'). The string "ZOZZXZZZO" thus represents the board:

+-+-+-+
| |O| |
+-+-+-+
| |X| |
+-+-+-+
| | |X|
+-+-+-+

The beauty of the JSON format is that we can simply do json.action to access the action field of the data, as in the code below.

Knowing when it is your turn

It's very helpful to show an indication to the player informing him whose turn it is. When it's someone's turn, you'll get a message with action = "act" and the pid set to the player whose turn it is. All we have to do is compare this pid to our pid, which we got from the server when we logged in.


    if (json.action == "act") {
        if (json.pid == myPlayerId) {
            gameMessage("My turn to act.");
            $('#turn').text("It's your turn!");
            myTurn = true;
        } else {
            $('#turn').text("It's not your turn.");
            myTurn = false;
        }

Acting

When the user clicks a cell, we need to send this action to the server. Here's the complete clickHandler function:


function clickHandler(e) {
    if (!myTurn) return;

    // We need to calculate the position with 0, 0 as the top left corner of the canvas.
    var relativeX = e.pageX - $("#board").offset().left;
    var relativeY = e.pageY - $("#board").offset().top;

    var x = Math.floor(relativeX / (width / 3));
    var y = Math.floor(relativeY / (height / 3));

    // The server counts the cells as this:
    // 0 1 2
    // 3 4 5
    // 6 7 8
    // So, to get the cell number, given the row and column, we multiply the row by 3 and add the column.
    var cell = y * 3 + x;
    connector.sendStringGameData(0, myTableId, "" + cell);
}

Note that we are checking whether it's our turn, since this is easy to do. We don't care to check if the cell clicked is empty. This is actually not needed, since the server will ignore illegal actions. This makes the client logic easier.

The relativeX and relativeY stuff is required to calculate the coordinates of the click relative to the canvas. We use the offset function from the jQuery library for this.

We then just convert from row / column format to the 0..8 representation and send the click to the server. The "" + cell is need for converting the number to a string.

Graphics

The graphics part of this tutorial is actually stolen from this tutorial by Eduardo Abreu. It uses an HTML5 canvas and the path painting functions to draw the board, the cross and the naught. Here's the code for drawing the naught:

function paintO(x, y) {

    context.beginPath();

    context.strokeStyle = '#0000ff';
    context.lineWidth = 4;

    var offsetX = (width / 3) * 0.1;
    var offsetY = (height / 3) * 0.1;

    var beginX = x * (width / 3) + offsetX;
    var beginY = y * (height / 3) + offsetY;

    var endX = (x + 1) * (width / 3) - offsetX * 2;
    var endY = (y + 1) * (height / 3) - offsetY * 2;

    context.arc(beginX + ((endX - beginX) / 2), beginY + ((endY - beginY) / 2), (endX - beginX) / 2, 0, Math.PI * 2, true);

    context.stroke();
    context.closePath();
}

Try It Out

To try this in action, make sure you have the server running and then head over here. To download the finished project, just get the zip file here. Again, make sure the server is up. If you haven't set up the server yet, head over here.

Good luck!

Known Issues

  • Denied join requests - the game logic on the server side currently denies leave attempts for players who are in an ongoing game. However, Firebase will remove those players after a while regardless, showing 0 players at the table in the lobby. The game might therefore deny join requests from players because it thinks the table is full, even though the Firebase lobby shows the table as empty.
  • Leaving tables - it's currently not possible to leave the table from the client. The only way to get back to the lobby is to reload the page.
Personal tools