1
\$\begingroup\$

I am following the boardgame.io tutorial, but I do not want to use either of the two implementation options covered in the tutorial (React and Parcel).

The tutorial requires a framework or bundling method because the client web application has dependencies on node.js modules which cannot be directly imported into browser scripts.

\$\endgroup\$
1
\$\begingroup\$

boardgame.io and webpack This tutorial is derived from the official Boardgame.io Tutorial. It uses Webpack as an alternative to using React or Parcel.

Tutorial

This tutorial walks through implementing a simple game of Tic-Tac-Toe.

Setup

We’re going to use node.js modules with our web client, so we’ll need to use some kind of build system to compile our code for the browser. In this version of the tutorial, we will use Webpack to package the javascript code our web client needs into a single file dist/main.js

Let’s create a new Node project from the command line:

mkdir bgio-tutorial
cd bgio-tutorial
npm init -yes

We’re going to add boardgame.io and Webpack modules to help us build our app:

npm install boardgame.io
npm install --save-dev webpack webpack-cli

Now, let’s create a basic HTML page that will load our app:

index.html:

<!DOCTYPE html>
<html>
  <head>
    <title>boardgame.io Tutorial</title>
    <meta charset="utf-8" />
  </head>
  <body>
    <div id="app"></div>
    <script src="./dist/main.js"></script>
  </body>
</html>

Next, create a basic http-server to share our html and javascript files:

server.js:

const PORT = 3004;                                       

const fs = require('fs');                                
    http = require('http');                              

http.createServer(function (req, res)
{
  console.log(`Request for url:${req.url}`);             

  if (req.url == '/')                                    
    req.url = '/index.html';                             

  fs.readFile(__dirname + req.url, function (err,data) { 
    if (err) {                                           
      res.writeHead(404);                                
      res.end(JSON.stringify(err));                      
      return;                                            
    }                                                    
    res.setHeader('Cache-Control', 'no-store');          

    if (req.url.endsWith('.js'))                         
      res.setHeader('Content-Type', 'text/javascript');  

    res.writeHead(200);                                  
    res.end(data);                                       
  });                                                    
}).listen(PORT);                                         

console.log(`Server started on port ${PORT}`);   

Create a src folder to hold our game files:

mkdir src

Our completed project directory will look like this:

bgio-tutorial/
├── dist
│   └── main.js
├── index.html
├── node_modules/
├── package-lock.json
├── package.json
├── server.js
└── src/
    ├── App.js
    └── Game.js

Defining a Game

We define a game by creating an object whose contents tell boardgame.io how your game works. More or less everything is optional, so we can start simple and gradually add complexity. To start, we’ll add a setup function, which will set the initial value of the game state G, and a moves object containing the moves that make up the game.

A move function receives the game state G and updates it to the desired new state. It also receives ctx, an object managed by boardgame.io that contains metadata like turn and currentPlayer. After G and ctx, moves can receive arbitrary arguments that you pass in when making the move.

In Tic-Tac-Toe, we only have one type of move and we will name it clickCell. It will take the ID of the cell that was clicked and update that cell with the ID of the player who clicked it.

Let’s put this together in src/Game.js to start defining our game:

src/Game.js:

export const TicTacToe = {
  setup: () => ({ cells: Array(9).fill(null) }),

  moves: {
    clickCell: (G, ctx, id) => {
      G.cells[id] = ctx.currentPlayer;
    },
  },
};

NOTE: The setup function will receive ctx as its first argument. This is useful if you need to customize the initial state based on some field in ctx — the number of players, for example — but we don’t need that for Tic-Tac-Toe.

Creating a Client

We’ll start by creating a class to manage our web app’s logic in src/App.js.

In the class’s constructor we’ll create a boardgame.io client and call its start method to run it. src/App.js:

import { Client } from 'boardgame.io/client';
import { TicTacToe } from './Game';

class TicTacToeClient {
  constructor() {
    this.client = Client({ game: TicTacToe });
    this.client.start();
  }
}

const app = new TicTacToeClient();

Let’s also add two scripts to package.json to make serving the web app simpler:

package.json:

{
  "scripts": {
    "webpack": "webpack-cli --mode=development src/App.js",
    "start": "node server.js"
  }
}

Pack our classes and packages for distribution to client browsers:

npm run webpack

Open port 3004 on your firewall if necessary. On my CentOS 8 server I run:

sudo firewall-cmd --zone dmz --add-port 3004/tcp
sudo firewall-cmd --zone dmz --add-port 3004/tcp --permanent

You can now serve the app from the command line by running:

npm start

You should now be able to view the site in your browser. If you started the server on the same machine, just browse: http://localhost:3004

Although we haven’t built any UI yet, boardgame.io renders a Debug Panel. This panel means we can already play our Tic-Tac-Toe game!

You can make a move by clicking on clickCell on the Debug Panel, entering a number between 0 and 8, and pressing Enter. The current player will make a move on the chosen cell. The number you enter is the id passed to the clickCell function as the first argument after G and ctx. Notice how the cells array on the Debug Panel updates as you make moves. You can end the turn by clicking endTurn and pressing Enter. The next call to clickCell will result in a “1” in the chosen cell instead of a “0”.

enter image description here

Note: You can turn off the Debug Panel by passing debug: false in the Client config.

Next Steps

This is the end of the WebPack-specific content of the tutorial. You can now complete the "Plain JS" version of the official tutorial continuing from the Game Improvements section.

\$\endgroup\$
1
  • \$\begingroup\$ Does it still work when you try to use boardgame.io/server? \$\endgroup\$ Dec 30 '20 at 23:13

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.