Part III: Read the game state and display information about the players

Overview

This is the 3rd post of a 5 parts series describing how to create a fully multiplayer TicTacToe game on Plynd:

  1. Setup and publish the skeleton of your application
  2. Setup the development environment
  3. Read the game state and display information about the players (this post)
  4. Update the game state with events
  5. Put the update logic server-side

Don’t hesitate to ask all your questions via the comments section or directly to info@plynd.com

Goal

In this section, we’ll explain how Plynd stores the game state, and how to read it in order to display information about the players. We’ll start from this code template and we will obtain this outcome at the end of the section

Plynd SDK

One of the advantages of Plynd is that it provides the backend for you. To communicate with Plynd servers, you just have to include the javascript SDK in your application page. There is no API authentication to handle, it is all done implicitly on your behalf!

First make sure that your application is linking to http://localhost:3000/work-directory (as seen in the previous section), then include the SDK at the bottom of work-directory/index.html. It should now read:

1
2
3
4
5
6
7
8
<html>
...

<script src='//cdnjs.cloudflare.com/ajax/libs/jquery/2.1.4/jquery.min.js'></script>
<script src='//sandbox.plynd.com/plynd-sdk-0.2-unstable.min.js'></script>
<script src='js/tictactoe.js'></script>

</html>

Game state and metadata

Whenever a game is created, Plynd manages two entities for it: state and metadata:

  • The state is whatever you want to store in order to describe your game. It is a JSON blob and can receive any kind of data. Plynd enforces no rules on it, and it will always return the latest state saved.
  • On the other hand, the metadata is composed of all the information surrounding the game, including the players in the game and their profiles information, as well as their current statuses (e.g. is it their turn to play?). The metadata is maintained up-to-date by Plynd, and should be considered read-only. It provides all the information that enrich the game experience.

The SDK function to retrieve the game information is

1
Plynd.getGame(successCallback, errorCallback)

and the successCallback function has the signature

1
function(state, metadata)

Show the players in the game and their statuses

Let’s modify /work-directory/js/tictactoe.js to use this information. At first, let’s just call the function and print the returned data.

1
2
3
Plynd.getGame(function(state, metadata) {
$("body").html(JSON.stringify(metadata));
});

Open the updated version of your application in the Playground, and see the output of this change. As you can see, metadata looks something like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
{
"name": "Playground #1",
"players": {
"11856": {
"playerID": 11856,
"playerName": "Roger Federer",
"playerColor": "#a73338",
"status": "waiting_turn",
"user": {
"userID": 932,
"firstName": "Roger",
"isoCountry": "CH",
"lastName": "Federer",
"name": "Roger Federer",
"picture": "http://picture.board-game.co/hYMugrxIMbpWimx7qJ82lFZipE6O28.jpg"
}
},
"11857": {
"playerID": 11857,
"playerName": "Rafael Nadal",
"playerColor": "#538f5b",
"status": "has_turn",
"user": {
"userID": 933,
"firstName": "Rafael",
"isoCountry": "ES",
"lastName": "Nadal",
"name": "Rafael Nadal",
"picture": "http://picture.board-game.co/PF5uBLNLz4ak8tD1trWMGlvAnMHDET.jpg"
}
}
},
"settings": {
"autoSurrender": 2592000
},
"status": "game_is_active",
"orderOfPlay": [
11857,
11856
],
"eventNumber": 15,
"boardID": 70,
"ownPlayer": {
"playerID": 11856,
"playerName": "Roger Federer",
"playerColor": "#a73338",
"status": "waiting_turn",
"user": {
"userID": 932,
"firstName": "Roger",
"isoCountry": "CH",
"lastName": "Federer",
"name": "Roger Federer",
"picture": "http://picture.board-game.co/hYMugrxIMbpWimx7qJ82lFZipE6O28.jpg"
}
}
}

Now, all we have to do is use the info we have in metadata.players to show the name and the picture for each player, as well as their current statuses.

The different statuses for players are maintained by Plynd backend, and can have 5 distinct values:

Status Meaning
has_turn the player can play. Several players can have turns simultaneously at a given time
waiting_turn the player is still in the game but has to wait for his turn
eliminated the player is out of the game, but the game is not over yet (some players are still active in it)
winner the game is over and this player is among the winners of it
defeated the game is over and this player is not among the winners

We are also going to put the info about the player currently viewing the game on the left, based on metadata.ownPlayer.

parts/part-1-setup/js/tictactoe.js should now look something like:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
// getGame is the entry point. That's how we fetch data about the game
// It returns the state and the metadata of the game.
// So far the state is empty (it is what we will put into it) but the
// metadata contains info that we will use
Plynd.getGame(function(state, metadata{
// metadata contains a lot of information, among which
// * metadata.players contains the info about all the players in the game, given by their ID
// * metadata.ownPlayer contains the info about the player with the point of view on the game
// * metadata.orderOfPlay is the list of the player IDs in the game
var players = metadata.players;
var ownPlayer = metadata.ownPlayer;
var orderOfPlay = metadata.orderOfPlay;

for (var i = 0; i < orderOfPlay.length ; i++) {
var playerID = orderOfPlay[i];
var player = players[playerID];

// Select the left div for "ownPlayer", the right one for the other
var playerDiv;
if (playerID == ownPlayer.playerID) {
playerDiv = $('#player-left');
}
else {
playerDiv = $('#player-right');
}

// Show the name, the status and the player image
playerDiv.find('img').prop('src', player.user.picture);
playerDiv.find('.player-name').text(player.playerName);
playerDiv.find('.player-status').text(player.status);
}
});

If you go back to the Playground, you should see the expected result. Specifically, you should see the user on the left change when you switch the point of view.

Show the symbols for the players

In a TicTacToe game, usually the first player plays with a cross, and the second player plays with a circle.

First, let’s refactor a little the logic of displaying the players, to extract it in a function showPlayers:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// Keep the game state and the metadata globally so
// that they can be used in all the different functions
var state, metadata;

///////////////////////////////////////////////////////////////////////////////////////////
// The functions to update the UI according to the game state and metadata
///////////////////////////////////////////////////////////////////////////////////////////

// Show the players, based on the metadata object
function showPlayers() {
// metadata contains a lot of information, among which
// * metadata.players contains the info about all the players in the game, given by their ID
// * metadata.ownPlayer contains the info about the player with the point of view on the game
// * metadata.orderOfPlay is the list of the player IDs in the game
var players = metadata.players;
var ownPlayer = metadata.ownPlayer;
var orderOfPlay = metadata.orderOfPlay;

for (var i = 0; i < orderOfPlay.length ; i++) {
var playerID = orderOfPlay[i];
var player = players[playerID];

// Select the left div for "ownPlayer", the right one for the other
var playerDiv;
if (playerID == ownPlayer.playerID) {
playerDiv = $('#player-left');
}
else {
playerDiv = $('#player-right');
}

// Show the name, the status and the player image
playerDiv.find('img').prop('src', player.user.picture);
playerDiv.find('.player-name').text(player.playerName);
playerDiv.find('.player-status').text(player.status);
}
}

// getGame is the entry point. That's how we fetch data about the game
// It returns the state and the metadata of the game.
// So far the state is empty (it is what we will put into it) but the
// metadata contains info that we will use
Plynd.getGame(function(_state, _metadata{
state = _state;
metadata = _metadata;

showPlayers();
});

Next we can create the function getPlayerSymbol that will take a playerID in, and return the symbol that this player uses:

1
2
3
4
5
6
7
// The first player has the symbol "X"
// The second has the symbol "O"
// We use metadata.orderOfPlay to know who is the first player
function getPlayerSymbol(playerID) {
if (playerID == metadata.orderOfPlay[0]) return "X";
return "O";
}

In the end, we obtain the following code for tictactoe.js:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
// Keep the game state and the metadata globally so
// that they can be used in all the different functions
var state, metadata;

///////////////////////////////////////////////////////////////////////////////////////////
// The functions to update the UI according to the game state and metadata
///////////////////////////////////////////////////////////////////////////////////////////

// The first player has the symbol "X"
// The second has the symbol "O"
// We use metadata.orderOfPlay to know who is the first player
function getPlayerSymbol(playerID) {
if (playerID == metadata.orderOfPlay[0]) return "X";
return "O";
}

// Show the players, based on the metadata object
function showPlayers() {
// metadata contains a lot of information, among which
// * metadata.players contains the info about all the players in the game, given by their ID
// * metadata.ownPlayer contains the info about the player with the point of view on the game
// * metadata.orderOfPlay is the list of the player IDs in the game
var players = metadata.players;
var ownPlayer = metadata.ownPlayer;
var orderOfPlay = metadata.orderOfPlay;

for (var i = 0; i < orderOfPlay.length ; i++) {
var playerID = orderOfPlay[i];
var player = players[playerID];

// Select the left div for "ownPlayer", the right one for the other
var playerDiv;
if (playerID == ownPlayer.playerID) {
playerDiv = $('#player-left');
}
else {
playerDiv = $('#player-right');
}

// Show the name, the status and the player image
playerDiv.find('img').prop('src', player.user.picture);
playerDiv.find('.player-name').text(player.playerName);
playerDiv.find('.player-status').text(player.status);
playerDiv.find('.player-symbol').text("(" + getPlayerSymbol(player.playerID) + ")");
}
}

// getGame is the entry point. That's how we fetch data about the game
// It returns the state and the metadata of the game.
// So far the state is empty (it is what we will put into it) but the
// metadata contains info that we will use
Plynd.getGame(function(_state, _metadata{
state = _state;
metadata = _metadata;

showPlayers();
});

You can find the working version for this section at /parts/part-3-read-game-state.

Summary

In this post, we’ve seen:

  • how to connect to the Plynd backend and consume data using the javascript SDK
  • specifically how Plynd maintains the metadata of a game and makes it super easy to use

Next, let’s see how to update the game state.