任何模式的棋盘游戏?

为了好玩,我试图把我儿子最喜欢的一款棋盘游戏写成一个软件。 最终,我期望在其上构build一个WPF UI,但是现在我正在构build模拟游戏及其规则的机器。

当我这样做的时候,我一直看到许多棋盘游戏常见的问题,也许其他人已经比我更好地解决了这些问题。

(请注意,AI玩游戏,高性能模式对我来说并不有趣。)

到目前为止,我的模式是:

  • 在游戏框中代表实体的几个不可变types,例如骰子,跳棋,卡片,棋盘,棋盘上的空格,金钱等

  • 每个玩家的对象,包含玩家资源(例如金钱,分数),他们的名字等等。

  • 一个代表游戏状态的对象:玩家,轮到谁,棋盘上的peices的布局等等。

  • pipe理转弯顺序的状态机。 例如,很多游戏都有一个小游戏,每个玩家都会先看看谁先走; 这是开始状态。 当一个玩家轮到他们时,他们先滚动,然后他们移动,然后他们必须跳起来,然后其他玩家猜测他们是什么品种的鸡,然后他们得到分数。

有一些我可以利用的现有技术吗?

编辑:我最近意识到的一件事是游戏状态可以分为两类:

  • 游戏神器状态 。 “我有$ 10”或“我的左手是蓝色的”。

  • 游戏顺序状态 。 “我打了两次双打,下一次把我关进监狱”。 状态机可能在这里有意义。

编辑:我真正在这里寻找的是实现多人回合制游戏如国际象棋或拼字游戏或垄断的最佳方式。 我相信我可以通过开始完成这个游戏来创build这样一个游戏,但是像其他的devise模式一样,可能有一些方法可以让事情变得更加顺利,没有经过仔细的研究就不是很明显。 这就是我所希望的。

看来这是我刚才注意到的一个2个月大的线程,但是到底是什么。 之前,我devise和开发了一个商业networking游戏的游戏玩法框架。 我们有一个非常愉快的经验与它合作。

因为玩家A有多less钱,玩家B有多less钱等等,所以你的游戏可能处于(接近)无限多的状态。所以,我很确定你想要远离状态机。

我们的框架背后的想法是将游戏状态表示为结构,所有数据字段一起提供完整的游戏状态(即:如果要将游戏保存到磁盘,则将该结构写出)。

我们使用命令模式来表示玩家可以做出的所有有效的游戏动作。 这将是一个示例操作:

class RollDice : public Action { public: RollDice(int player); virtual void Apply(GameState& gameState) const; // Apply the action to the gamestate, modifying the gamestate virtual bool IsLegal(const GameState& gameState) const; // Returns true if this is a legal action }; 

所以你看到要决定一个移动是否有效,你可以构造这个动作,然后调用它的IsLegal函数,传递当前的游戏状态。 如果它是有效的,并且玩家确认动作,则可以调用应用function来实际修改游戏状态。 通过确保您的游戏代码只能通过创build和提交合法的动作来修改游戏状态(换句话说,Action :: Apply系列方法是唯一直接修改游戏状态的方法),那么您可以确保游戏状态永远不会失效。 此外,通过使用命令模式,可以序列化玩家所需的动作,并通过networking发送给其他玩家的游戏状态。

结果是这个系统有一个问题,原来有一个相当优雅的解决scheme。 有时行动会有两个或更多的阶段。 例如,玩家可能在“大富翁”的土地上登记,现在必须作出新的决定。 玩家掷骰子之前和决定购买房产之前的游戏状态是什么? 我们通过设置游戏状态的“Action Context”成员来pipe理这种情况。 动作上下文通常为空,表示游戏目前不处于任何特殊状态。 当玩家掷骰子并且将掷骰动作应用于游戏状态时,将认识到玩家已经落在非拥有的属性上,并且可以创build包含玩家的索引的新的“PlayerDecideToPurchaseProperty”动作上下文我们正在等待一个决定。 在RollDice动作完成的时候,我们的游戏状态代表它正在等待指定玩家决定是否购买一个物业。 除了“BuyProperty”和“PassPropertyPurchaseOpportunity”操作之外,所有其他操作的IsLegal方法都很容易返回false,这些操作仅在游戏状态具有“PlayerDecideToPurchaseProperty”操作上下文时才合法。

通过使用动作上下文,在棋盘游戏的生命周期中,游戏状态结构并不完全代表游戏中当时正在发生的事情,从来没有一个单一的点。 这是您的棋盘游戏系统非常理想的属性。 只要检查一个结构就可以find所有你想知道游戏中发生的事情的代码,这会让你更容易编写代码。

此外,它非常适合于networking环境,客户可以通过networking向主机提交他们的动作,主机可以将动作应用到主机的“官方”游戏状态,然后将该动作回送给所有其他客户端让他们将其应用到他们复制的游戏状态。

我希望这是简洁和有益的。

游戏引擎的基本结构使用状态模式 。 你的游戏盒的物品是各种类的单身 。 每个状态的结构可以使用策略模式或模板方法 。

工厂被用来创build插入到玩家列表中的玩家,另一个单身人士。 GUI将通过使用观察者模式继续监视游戏引擎,并通过使用命令模式创build的几个Command对象之一与之交互。 Observer和Command的使用可以在被动视图的上下文中使用,但根据您的偏好,可以使用任何MVP / MVC模式。 当您保存游戏时,您需要获取当前状态的纪念品

我build议查看一下这个网站上的一些模式,看看他们中的任何一个是否抓住你的出发点。 再次,你的游戏板的核心将是一个状态机。 大多数游戏将由游戏前/安装和实际游戏中的两个状态来表示。 但是如果你正在build模的游戏有几种不同的游戏模式,你可以有更多的状态。 各国并不一定是连续的,例如战争游戏“轴心战”有一个战斗牌,玩家可以用来解决战斗。 所以有三个国家在游戏前,主板,战斗板之间不停地切换主板和战斗板。 转弯顺序当然也可以用状态机来表示。

我刚刚完成了使用多态的devise和实现基于状态的游戏。

使用一个名为GamePhase的基本抽象类有一个重要的方法

 abstract public GamePhase turn(); 

这意味着每个GamePhase对象都保持游戏的当前状态,并且调用turn()查看其当前状态并返回下一个GamePhase

每个具体的GamePhase都有构造函数来保存整个游戏状态。 每个turn()方法都有一些内部的游戏规则。 虽然这些规则围绕着这些规则进行传播,但是它将相关的规则保持在一起 每个turn()的最终结果就是创build下一个GamePhase ,并将整个状态传递到下一个阶段。

这允许turn()非常灵活。 根据你的游戏,一个给定的状态可以分支到许多不同types的阶段。 这形成了所有游戏阶段的图表。

在最高级别上,驱动它的代码非常简单:

 GamePhase state = ...initial phase while(true) { // read the state, do some ui work state = state.turn(); } 

这是非常有用的,因为我现在可以轻松地创build任何状态/阶段的游戏进行testing

现在回答你的问题的第二部分,这是如何工作在多人游戏? 在某些需要用户input的GamePhase ,来自turn()的调用会根据当前状态/阶段向当前Player询问他们的StrategyStrategy只是一个Player可以做出的所有可能决定的接口。 这个设置也允许使用AI实现Strategy

另外Andrew Top说:

因为玩家A有多less钱,玩家B有多less钱等等,所以你的游戏可能处于(接近)无限多的状态。所以,我很确定你想要远离状态机。

我认为这个说法是非常具有误导性的,虽然确实有很多不同的游戏状态,但只有几个游戏阶段。 为了处理他的例子,所有它将是我的具体GamePhase的构造函数的整数参数。

垄断

一些GamePhase的例子是:

  • GameStarts
  • PlayerRolls
  • PlayerLandsOnProperty(FreeParking,GoToJail,Go等)
  • PlayerTrades
  • PlayerPurchasesProperty
  • PlayerPurchasesHouses
  • PlayerPurchasesHotels
  • PlayerPaysRent
  • PlayerBankrupts
  • (所有机会和社区胸卡)

GamePhase一些州GamePhase是:

  • 玩家名单
  • 当前玩家(轮到谁)
  • 玩家的钱/财产
  • 住房/酒店的属性
  • 球员位置

然后有些阶段会根据需要logging自己的状态,例如PlayerRolls会logging一个玩家连续翻两番的次数。 一旦我们离开PlayerRolls阶段,我们不再关心连续的滚动了。

许多阶段可以重复使用并链接在一起。 例如, GamePhase CommunityChestAdvanceToGo会用当前状态创build下一阶段PlayerLandsOnGo并返回它。 在PlayerLandsOnGo的构造函数中,当前玩家将移动到Go,他们的钱将增加200美元。

当然,这个话题有很多,很多,很多,很多,很多的资源。 但是我认为,你正在划分对象并让它们处理自己的事件/数据等等。

在做基于平铺的棋盘游戏时,你会发现有很多例程可以在棋盘arrays和行/列之间进行映射,还可以沿着其他function进行映射。 我记得我第一次玩棋盘游戏(很久以前),当时我正想着如何从板arrays5获得排/列。

 1 2 3 4 (5) 6 BoardArray 5 = row 2, col 2 7 8 9 

Nostalgy。 ;)

无论如何, http://www.gamedev.net/是一个信息的好地方。; http://www.gamedev.net/reference/

我可以在网上find的大部分材料都是已发表参考文献的列表。 游戏devise模式的出版物部分链接到PDF版本的文章和论文。 其中许多看起来像“游戏devise模式”这样的学术论文。 亚马逊至less也有一本书,游戏devise模式 。

三环提供LGPL'd Java库。 Nenya和Vilya是游戏相关的东西的图书馆。

当然,如果你的问题提到了你可能有的平台和/或语言限制,这将会有所帮助。

我同意Pyrolistical的回答,我更喜欢他的做法(我只是略过了其他答案)。

巧合的是我也用他的“GamePhase”命名。 基本上我会在回合制棋盘游戏的情况下做的是你的GameState类包含Pyrolistical所提到的抽象GamePhase的对象。

比方说游戏状态是:

  1. 移动
  2. 买/不买
  3. 监狱

你可以有每个状态的具体派生类。 至less有以下的虚拟function:

 StartPhase(); EndPhase(); Action(); 

在StartPhase()函数中,您可以设置一个状态的所有初始值,例如禁用其他玩家的input等等。

当roll.EndPhase()被调用时,确保GamePhase指针被设置为下一个状态。

 phase = new MovePhase(); phase.StartPhase(); 

在这个MovePhase :: StartPhase()中,例如你可以将活动玩家的剩余移动量设置为上一阶段滚动的数量。

现在,在这个devise中,您可以在Roll阶段内理清“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中处理这一切。 这是因为如果你有太多的顺序阶段,玩家很可能会觉得太“引导”。 例如,如果有一个阶段,玩家只能购买物业,然后只购买酒店,然后只买房子,就像没有自由。 只要将所有这些部分砸成一个BuyPhase,并让玩家自由地购买任何他想要的东西。 BuyPhase类可以很容易地处理哪些购买是合法的。

最后我们来讨论一下这个游戏板。 虽然二维数组是好的,但我build议有一个瓦片图(瓦片是在板上的位置)。 就monoppoly而言,它宁愿成为一个双向链表。 那么每一个瓷砖将有一个:

  1. previousTile
  2. nextTile

所以做这样的事情会容易得多:

 While(movesRemaining>0) AdvanceTo(currentTile.nextTile); 

AdvanceTo函数可以处理你一步一步的animation或任何你喜欢的。 当然也会减less剩下的动作。

RS Conley对GUI的观察者模式的build议是很好的。

我以前没有发过多的 希望这有助于某人。

有一些我可以利用的现有技术吗?

如果你的问题不是语言或平台特定的。 那么我会build议你考虑AOP模式的状态,纪念,命令等

什么是.NET答案的AOP?

也尝试find一些很酷的网站,如http://www.chessbin.com