Skip to content
dtrauma edited this page Jan 12, 2019 · 3 revisions

Concepts

Game State, and context

The framework captures the game state in two objects: G and ctx.

{
  // The game state (user-managed).
  G: {},

  // Read-only metadata managed by the framework.
  ctx: {
    turn: 0,
    currentPlayer: '0',
    numPlayers: 2
  }
}

These state objects are passed around everywhere and maintained on both client and server seamlessly.

If you want your game state to be serializable, which is a requirement for networked multiplayer using a server, you should only put primitive data like strings, numbers, arrays and simple objects in G. Functions, classes and objects with a class or custom prototype in particular are not safe. The rule of thumb is, if you wouldn't put it in a JSON file, don't put it into your state.

How, and if you use ctx in your code is up to you, you can track similar state manually in G if you so desire.

!> ctx contains other fields not shown here to support the more complex concepts introduced in Game Flow below.

Moves

Moves are how the players will interact with your game. For every possible action they should be able to do, you should provide a move function that tells the framework how to change G. They must not depend on external state or have any side-effects (except modifying G). See the guide on Immutability for how immutability is handled by the framework.

moves: {
  drawCard: function(G, ctx) {
    if (G.deck.length > 0) {
      const card = G.deck.pop();
      G.hand.push(card);
    } else {
      return INVALID_MOVE;
    }
  },

  ...
}

Moves are dispatched from the client in different ways depending on the platform you are developing on. If you are using React, for example, they are dispatched via an API provided through props.

onClick() {
  this.props.moves.moveA();
}

Everytime a move is made, onMove is called afterwards.

Game Flow

Besides describing what exactly happens when a move is made, game rules are mainly about which moves are legal, and when. Boardgame.io gives you a rich set of tools to painlessly implement them in your code.

Turn

The main purpose of turns is to distinguish between players that are active, and those waiting for their turn. The framework will only accept moves by active players.

In many classic board games like Chess and Go, there is one active player, and turns consist of making a single move, after which the next player becomes active. This is easy to do, but you also can allow multiple players to play during a turn, or have other criteria than the number of moves to switch active players.

See the guide on Turn Orders for more details on how to manage active players, and the API documentation for Game for related hooks like onTurnBegin, onTurnEnd and endTurnIf.

Phase

A game phase is a label that is associated with a particular game configuration. A phase can be configured with a custom turn order, enable a certain subset of moves and much more. The game can transition between different phases just like the turn can be passed between different players, which means that while repeating the same phases in order is possible, you have complete control over the phase flow if you need it.

Phases and turns are independent, i.e. you can design your game to have multiple phases per turn, like in Mafia (night and day), or multiple turns per phase, like in Go (playing and scoring). All your players will always be in the same phase.

Not using phases is fine, and just means that the game will stay in the default phase until it ends.

See the guide on Phases for more details, and the API documentation for Game for related hooks like onPhaseBegin, onPhaseEnd and endPhaseIf.

Mode (Subphase, PlayerPhase, Task)

What a phase is to a game, a mode is to a player. Just like phases you can use modes to switch configuration like the kind of, or number of moves possible, but unlike phases they only affect the players you want them to.

Just like phases, using them is completely optional. All players without a custom mode will remain in the default mode until the game ends.

See the guide for more details, and the API documentation for Game for related hooks like onModeBegin, onModeEnd and endModeIf.

Tying it all together (TLDR)

To recap:

  • Turns determine the active player(s). You can have any turn order you want, the default is round robin with a single active player.
  • Phases are labels with attached configuration. You can switch phases in your moves, or from a trigger (like onEndTurn). All players always are in the same phase. Nearly every setting you can do for a game, you can change in a phase.
  • Modes are similar to phases, but can be different for each player. They also let you change fewer settings.
  • A move is accepted and committed when:
    • The player is active, as determined by your turn order.
    • The move is allowed by the current phase.
    • The move is allowed by the moving player's current mode.
    • The move function doesn't return INVALID_MOVE.

Events

These are functions provided by the framework in order to change state in ctx. Think of these as pre-built moves provided by the framework that interact with the other concepts like turn and phase above, or end the game entirely. They can be disabled if giving your players access to them could violate game rules, like not being allowed to skip a move in Chess.

Events are dispatched from the client like moves, but live in a different namespace. Here is an example in React again:

onClick() {
  this.props.ctx.events.endTurn();
}

For more details, see the guide on Events.