-
Notifications
You must be signed in to change notification settings - Fork 0
Concepts
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 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.
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.
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
.
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
.
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
.
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.
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.