boardgame.ioというボードゲーム作成用フレームワークを使ったブラウザゲーム作成の手順です

関連記事

今回は、ターン、フェーズ、ステージといった段階制御を行っていきます。

ターン

ターンに関しては何もしていない状態では以下の動作となります。

  • endTurnイベントでターンを終了
  • Player0,1,2,…n → 0,1,2..n の順でターンを交代

ゲームによってはターンの順を制御したい場合もあると思いますが、boardgame.io上にこれを設定できる項目があります。
Gにturnを設定します。

import { TurnOrder } from 'boardgame.io/core';

export const TicTacToe = {
  turn: {
    order: TurnOrder.CUSTOM(['0', '2']),
  },

上記で、Player0,2→0,2といった順番で遷移します。
またendTurn({ next: playerID });といった形でentTurn時に動的に次プレイヤーを指定する方法もあります。

orderに設定できる値は色々ありますが、次のフェーズの制御に関わるものが多いのでフェーズの説明に移ります。

フェーズ

フェーズとはゲームの工程ごとの動作のイメージです。
ターンとの関係は以下のようなイメージです。

  • フェーズ1 カードを引く
    • ターン:Player1
    • ターン:Player2
  • フェーズ2 カードを見せる
    • ターン:Player1
    • ターン:Player2

基本編ではGmovesを一つだけ定義しましたが、phasesを定義してその中にmovesを定義しなおします。

  phases: {
    draw: {
      start: true, //最初に始めるフェーズ
      next: 'play', //次フェーズ(固定文字列ではなく関数で動的に返すことも可)
      moves: { /* draw用のmoveを記載 */ },
    },

    play: {
      moves: { /* play用のmoveを記載 */ },
    },
  },

この状態ですとdrawで定義したフェーズがずっと続くこととなるので、フェーズ終了条件を定義します。
フェーズ終了条件は以下のようにphaseの中に定義するか

  phases: {
    draw: {
      start: true, //最初に始めるフェーズ
      next: 'play', //次フェーズ(固定文字列ではなく関数で動的に返すことも可)
      moves: { /* draw用のmoveを記載 */ },
+     endIf: ({ G }) => (G.deck <= 0), //Trueを返したとき次フェーズ
    },

    play: {
      moves: { /* play用のmoveを記載 */ },
    },
  },

あるいは前項のturnで以下のようにONCEなどを設定すると一度ターンを回すとフェーズが終了します。

  turn: {
    order: TurnOrder.ONCE,
  },

turnの種類は以下に記載があります。
https://boardgame.io/documentation/#/turn-order?id=changing-the-turn-order

フェーズ突入/終了時に何らかの処理をしたい場合はonBegin/onEndを使用します

phases: {
  phaseA: {
    onBegin: ({ G, ctx }) => { ... },
    onEnd: ({ G, ctx }) => { ... },
  },
};

ステージ

フェーズ/ターンではプレイヤーずつ順番にmoveを行っていきましたが、各プレイヤーが順番ではなく同時にmoveするような場合もあると思います。

そのような場合はStageを定義します。

turn: {
  stages: {
    stageAAA: {
      moves: { /* 同時に行わせたいmoveを定義 */ },
    },
  },
}

任意のタイミングでsetActivePlayersを実行します。eventsがとれるところならば、Client内でもGame内でも実行可能です。
(setActivePlayerをコールしたタイミングがプレイヤーのターン中の場合、そのターンが終了させられてからステージに移行するようです)

  const goStage = (events)=>{
    events.setActivePlayers({ all: 'stageAAA', minMoves: 1, maxMoves: 1 });
  }

この状態だと全プレイヤーが操作可能になります。maxMovesを設定しているので1回のみ行動可能ですが、maxMovesを外せば何回でも行動できます。
また第一引数にallを設定しているので全員が行動可能になりますが、これをOtherなどにすればcurrentPlayer以外のみ行動可能となったりします。
endStage()をコールすることでステージを抜けます。

上記のようにフェーズ/ターンは親子の関係ですが、ステージは一時的に別の状況に飛ばすようなイメージの動きとなっています。