boardgame.io

repository·main·Indexed 11 days ago

https://github.com/boardgameio/boardgame.io

A JavaScript engine for creating turn-based games (version 0.50.2). It abstracts networking, storage, and state synchronization, allowing developers to focus on game logic through state-transition functions.

Tokens
52.9K
Snippets
199
Records
249
Agent score
92%

What's inside boardgame.io

  1. Overview of boardgame.io features

    main

    boardgame.io is an engine for creating turn-based games using JavaScript. It allows you to write simple functions describing how game state changes when moves are made, and automatically handles the following:

    • State Management: Seamlessly manages game state across clients, servers, and storage.
    • Multiplayer: Keeps game state in sync in real-time across different platforms.
    • AI: Provides automatically generated bots to play your game.
    • Game Phases: Supports different rules and turn orders per phase.
    • Lobby: Includes player matchmaking and game creation capabilities.
    • Prototyping: Provides an interface to simulate moves before rendering the game.
    • Extendable: Features a plugin system for new abstractions.
    • View-layer Agnostic: Works with a vanilla JS client or specific bindings for React and React Native.
    • Logs: Supports game logs with time-travel capabilities to view previous states.
  2. Available storage backends for boardgame.io

    main

    boardgame.io is storage agnostic. While the core library provides the interface, you can use various community-maintained adapters for different backends:

    • Flatfile: Uses node-persist (see Flatfile setup guide).
    • Firebase: Available via bgio-firebase.
    • Azure Storage: Available via bgio-azure-storage.
    • Postgres: Available via bgio-postgres.
    • MongoDB: Support is currently unavailable/coming soon.

    To use these, you typically pass an instance of the adapter to the db property in the Server configuration object.

  3. Explore boardgame.io documentation and guides

    main

    The boardgame.io documentation is organized into three main sections to help you build multiplayer games:

    1. Getting Started: Includes core Concepts and a step-by-step Tutorial to help you build your first game.
    2. Guides: Detailed technical guides covering essential game mechanics and engine features:
      • Game Logic: Multiplayer, Turn Order, Phases, Stages, Events, and Randomness.
      • State Management: Secret State, Immutability, Undo / Redo, and Storage.
      • Development: Plugins, Debugging, Testing, TypeScript support, and Deployment.
      • Features: Chat functionality.
    3. Reference: API documentation for the core engine components:
      • Game
      • Client
      • Server
      • Lobby
  4. Explore notable boardgame.io projects

    main

    The boardgame.io ecosystem includes a wide variety of projects ranging from simple dice games to complex 3D board games and card games. You can use these projects as inspiration for implementation patterns, UI/UX design, or as reference implementations for specific game types (e.g., card games, puzzle games, or strategy games).

    Notable categories include:

    • Card Games: Arknights: The Card Game, Battle Line, Black Jack, Chinchon, Coup, Unstable Unicorns.
    • Board/Strategy Games: Camelot, Santorini (3D with three.js), SixPieces (3D), Territories.
    • Puzzle/Single-player: 2048, Garden, Chessweeper, Wizard Duel.
    • Frameworks/Tools: boardgame.io-angular (unofficial Angular client), FreeBoardGames.org (PWA framework), and Lewis' House of Games (lobby framework).

    For developers looking to learn how to implement specific mechanics, checking the source code of these projects is recommended.

  5. Generate dynamic <meta> tags on the server

    main

    Since Create React App does not support server-side rendering, you can implement dynamic <meta> tags by using placeholders in your index.html file.

    1. Add placeholders like __OG_TITLE__ or __OG_DESCRIPTION__ to your HTML template.
    2. On your server, read the index.html file into memory.
    3. Replace the placeholders with actual values based on the current URL before sending the response.

    Important: Always sanitize and escape interpolated values to prevent XSS attacks.

    <!doctype html>
    <html lang="en">
      <head>
        <meta property="og:title" content="__OG_TITLE__">
        <meta property="og:description" content="__OG_DESCRIPTION__">
  6. How Stages work in boardgame.io

    main

    A Stage is a subdivision of a turn that allows for different sets of moves. While a turn typically only allows the currentPlayer to make moves, Stages enable multiple players to be 'active' simultaneously.

    When players enter a stage, the framework allows moves only from those specific active players. Each player can be in a different stage.

    Key behaviors:

    • When no stage mechanism is active, ctx.activePlayers is null and only currentPlayer can move.
    • When stages are active, ctx.activePlayers is an object mapping player IDs to stage names.
    • A stage with its own moves section completely overrides the global moves for players in that stage. If a stage has no moves section, players can still use global moves.
    // Inside a move, use playerID to identify who made the move
    const move = ({ G, ctx, playerID }) => {
      console.log(`move made by player ${playerID}`);
    };
  7. Understand chat message persistence and permissions

    main

    When implementing chat, be aware of the following behaviors:

    Ephemeral Nature

    Chat messages are not stored by the boardgame.io server.

    • Connection timing: A client only receives messages sent while it is actively connected. If a player joins after messages were sent, they will not see the history.
    • Session loss: Refreshing the page or reconnecting will result in the loss of previously received messages.

    Permissions

    • Players: Can send and receive messages. Sending is authenticated using the same logic as game actions (assuming the match is authenticated via the Lobby server).
    • Spectators: Can receive and view messages, but are prohibited from sending them.
  8. Understand the game state structure (G and ctx)

    main

    boardgame.io manages game state using two distinct objects: G and ctx.

    • G: This is the game state managed by you. It should contain all the data specific to your game (e.g., player hands, board positions, decks). Crucially, G must be a JSON-serializable object; it must not contain classes or functions because it is sent between the client and server.
    • ctx: This is read-only metadata managed by the framework. It tracks game-wide information such as turn, currentPlayer, and numPlayers. It also supports advanced features like game phases and complex turn orders.

    You can manage all state manually in G if you prefer, as ctx is incrementally adoptable.

    {
      // The game state (managed by you).
      G: {},
    
      // Read-only metadata (managed by the framework).
      ctx: {
        turn: 0,
        currentPlayer: '0',
        numPlayers: 2,
      }
    }
  9. Use Events to advance game flow

    main

    Events are framework-provided functions used to advance the game state by modifying ctx. While moves are for player-driven state changes in G, events are typically used for structural changes like ending a turn or changing a game phase.

    Dispatching Events from the Client:

    • Plain JS: client.events.eventName()
    • React: props.events.eventName()
    // Plain JS
    client.events.endTurn();
    
    // React
    props.events.endTurn();
  10. How to implement Secret State in boardgame.io

    main

    To prevent sensitive information (like card hands) from being sent to the client, use the playerView setting in your game object. playerView is a function that receives { G, ctx, playerID } and must return a version of G that is stripped of information the specific player should not see.

    Note: For this to be effective, you must ensure that game clients are associated with individual players (see the Multiplayer documentation).

    const game = {
      // `playerID` could also be null or undefined for spectators.
      playerView: ({ G, ctx, playerID }) => {
        // Return a version of G that is stripped of secrets for this player
        return StripSecrets(G, playerID);
      },
      // ...
    };
  11. How randomness works in boardgame.io

    main

    Randomness in boardgame.io is handled through a random object passed into moves and other game logic functions. This design ensures several critical properties for multiplayer games:

    • Server-side Security: The Pseudo-Random Number Generator (PRNG) state is maintained on the server. Clients cannot predict future random outcomes, preventing cheating.
    • Determinism and Purity: Because boardgame.io uses a Redux-based architecture, game logic must be composed of pure functions. The random API provides controlled randomness that avoids the side effects of Math.random(), ensuring moves remain idempotent and the game state can be replayed exactly.
    • Reproducibility: By using a seed, games can be replayed with the exact same sequence of random events, which is useful for AI training and debugging.
  12. Define and use Moves to modify game state

    main

    Moves are functions defined in your game configuration that describe how to modify the G state.

    Rules for Moves:

    • They must take ({ G, ctx }) as arguments.
    • They must not depend on external state.
    • They must not have side-effects other than modifying G.

    Dispatching Moves from the Client:

    • Plain JS: Access moves via the client instance: client.moves.moveName().
    • React: Access moves via component props: props.moves.moveName().
    moves: {
      drawCard: ({ G, ctx }) => {
        const card = G.deck.pop();
        G.hand.push(card);
      },
    }
    
    // Usage in Plain JS
    client.moves.drawCard();
    
    // Usage in React
    props.moves.drawCard();