私はPyrolisticalの答えに同意し、彼のやり方を好む(私は他の答えを抜粋しただけだ)。
偶然にも彼の "GamePhase"ネーミングも使用しました。基本的に、ターンベースのボードゲームの場合は、Pyrolisticalによって言及されているように、GameStateクラスに抽象GamePhaseのオブジェクトを含めます。
ゲームの状態は次のとおりです:
- ロール
- 動く
- 購入する/購入しない
- 刑務所
各状態に対して具体的な派生クラスを持つことができます。少なくとも以下のための仮想関数を持っている:
StartPhase();
EndPhase();
Action();
StartPhase()関数では、他のプレイヤーの入力を無効にするなど、状態のすべての初期値を設定できます。
roll.EndPhase()が呼び出されたら、GamePhaseポインタが次の状態に設定されていることを確認してください。
phase = new MovePhase();
phase.StartPhase();
このMovePhase :: StartPhase()では、たとえば、アクティブプレーヤーの残りの移動を、前のフェーズでロールした量に設定します。
この設計が整ったら、ロールフェーズ内の「3 x double = jail」問題を整理できます。RollPhaseクラスは、独自の状態を処理できます。例えば
GameState state; //Set in constructor.
Die die; // Only relevant to the roll phase.
int doublesRemainingBeforeJail;
StartPhase()
{
die = new Die();
doublesRemainingBeforeJail = 3;
}
Action()
{
if(doublesRemainingBeforeJail<=0)
{
state.phase = new JailPhase(); // JailPhase::StartPhase(){set moves to 0};
state.phase.StartPhase();
return;
}
int die1 = die.Roll();
int die2 = die.Roll();
if(die1 == die2)
{
--doublesRemainingBeforeJail;
state.activePlayer.AddMovesRemaining(die1 + die2);
Action(); //Roll again.
}
state.activePlayer.AddMovesRemaining(die1 + die2);
this.EndPhase(); // Continue to moving phase. Player has X moves remaining.
}
私がPyrolisticalと異なるのは、プレイヤーがコミュニティの胸や何かに着地したときを含め、すべてのフェーズがあるはずです。これはすべてMovePhaseで処理します。これは、シーケンシャルフェーズが多すぎると、プレーヤーが「ガイドされすぎ」ていると感じる可能性が高いためです。たとえば、プレイヤーがプロパティのみを購入し、ホテルのみを購入し、次に家のみを購入できるフェーズがある場合、それは自由がないようなものです。これらすべてのパーツを1つのBuyPhaseにスラムし、プレイヤーが自由に購入できるようにします。BuyPhaseクラスは、どの購入が合法かを簡単に十分に処理できます。
最後に、ゲームボードについて説明しましょう。2D配列は問題ありませんが、タイルグラフを使用することをお勧めします(タイルはボード上の位置です)。独占の場合、それはむしろ二重にリンクされたリストになるでしょう。次に、すべてのタイルに:
- previousTile
- nextTile
したがって、次のようなことを行う方がはるかに簡単です。
While(movesRemaining>0)
AdvanceTo(currentTile.nextTile);
AdvanceTo関数は、ステップバイステップのアニメーションまたは好きなものをステップごとに処理できます。そして、もちろん残りの動きを減らします。
GUIのオブザーバーパターンに関するRS Conleyのアドバイスは優れています。
以前はあまり投稿していません。これが誰かを助けることを願っています。