为了好玩,我试着把我儿子最喜欢的棋盘游戏之一写成一款软件。最终,我希望在此基础上构建一个WPF用户界面,但现在我正在构建一台机器,该机器可以对游戏及其规则进行建模。
当我这样做的时候,我不断地看到我认为很多棋盘游戏都很常见的问题,也许其他人已经比我更好地解决了它们。
(请注意,AI玩游戏,和模式周围的高性能是我不感兴趣的。)
到目前为止,我的模式是:
有什么我可以利用的现有技术吗?
编辑:最近我意识到,游戏状态可以分为两类:
编辑:我在这里真正要寻找的是实现基于多人游戏的最佳方法,比如国际象棋、拼字游戏或垄断游戏。我相信我可以通过开始完成游戏来创建这样一个游戏,但是,和其他设计模式一样,有一些方法可以让事情变得更顺利,如果不仔细研究的话,这些方法是不明显的。这正是我所希望的。
发布于 2009-02-17 19:45:14
这似乎是我刚刚注意到的一个2个月前的帖子,但到底是怎么回事。我设计并开发了一个商业的,联网的棋盘游戏的游戏框架。我们有一段非常愉快的工作经历。
你的游戏可能会处于(接近)无限状态,因为A玩家有多少钱,B玩家有多少钱,等等。因此,我很确定你想远离状态机。
我们的框架背后的想法是将游戏状态表示为包含所有数据字段的结构,这些数据字段一起提供完整的游戏状态(也就是说,如果您想将游戏保存到磁盘中,则将该结构写出)。
我们使用指挥模式来表示玩家可以进行的所有有效的游戏操作。下面是一个示例操作:
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函数,传递当前的游戏状态。如果它是有效的,并且玩家确认了这个动作,你可以调用Apply函数来修改游戏状态。通过确保您的游戏代码只能通过创建和提交法律行为来修改游戏状态(换句话说,操作:应用一系列方法是唯一可以直接修改游戏状态的东西),那么您就可以确保您的游戏状态永远不会无效。此外,通过使用命令模式,您可以序列化玩家想要的动作,并通过网络将它们发送到其他玩家的游戏状态上执行。
这个系统最终得到了一个很好的解决方案。有时行动会有两个或两个以上的阶段。例如,玩家可能会降落在垄断的一个财产,现在必须作出一个新的决定。玩家掷骰子的时候和他们决定买不买财产之间的游戏状态是什么?我们通过一个游戏状态的“动作上下文”成员来管理这样的情况。操作上下文通常为null,表示游戏当前没有处于任何特殊状态。当玩家滚动骰子并将骰子滚动动作应用到游戏状态时,它将意识到玩家已经降落在一个不属于自己的属性上,并且可以创建一个新的"PlayerDecideToPurchaseProperty“操作上下文,其中包含我们正在等待决策的玩家的索引。当RollDice操作完成时,我们的游戏状态表示它目前正在等待指定的玩家来决定是否购买一个属性。现在,所有其他操作的IsLegal方法都很容易返回false,除了"BuyProperty“和"PassPropertyPurchaseOpportunity”操作,它们只有在游戏状态具有"PlayerDecideToPurchaseProperty“操作上下文时才是合法的。
通过使用动作上下文,在棋盘游戏的生命周期中,从来没有一个点的游戏状态结构不完全代表当时游戏中发生的事情。这是一个非常理想的属性,您的棋盘游戏系统。当你只检查一种结构就能找到你想知道的游戏中发生的事情时,编写代码就容易多了。
此外,它还很好地扩展到网络环境,客户端可以通过网络将其操作提交给主机,主机可以将操作应用到主机的“正式”游戏状态,然后将该操作反馈到所有其他客户端,让它们将其应用于复制的游戏状态。
我希望这是简明扼要和有用的。
发布于 2009-02-17 17:59:38
游戏引擎的基本结构使用状态模式。游戏盒中的项目是不同类的单身汉。每个状态的结构可以使用战略模式或模板法。
工厂用于创建插入到播放机列表(另一个单例)中的播放机。GUI将通过使用观测器模式来监视游戏引擎,并使用使用指挥模式创建的几个命令对象之一与其进行交互。观察者和命令的使用可以在被动视点的上下文中使用,但是根据您的喜好,几乎任何MVP/MVC模式都可以使用。保存游戏时,需要获取当前状态的纪念品
我建议查看一下这个站点上的一些模式,看看其中是否有任何一个模式可以作为起点。再一次,你的棋盘的核心将是一个状态机。大多数游戏将代表两种状态,赛前/设置和实际游戏。但是,如果您正在建模的游戏有几种不同的游戏模式,您可以有更多的状态。国家不必是连续的,例如,战争的轴心&战斗有一个战斗板,玩家可以用它来解决战斗。因此,游戏分为三种状态:主板、主板、棋盘,游戏在主板和主板之间不断切换。当然,转弯序列也可以用状态机来表示。
发布于 2009-02-21 09:24:18
我刚刚完成了一个使用多态性的基于状态的游戏的设计和实现。
使用一个名为GamePhase的基类,它有一个重要的方法
abstract public GamePhase turn();这意味着每个GamePhase对象都保存游戏的当前状态,对turn()的调用将查看其当前状态并返回下一个GamePhase。
每个具体的GamePhase都有包含整个游戏状态的构造函数。每个turn()方法都有一些游戏规则。虽然这传播了规则,但它使相关规则紧密结合在一起。每个turn()的最终结果就是创建下一个GamePhase,并将完整的状态传递到下一个阶段。
这允许turn()非常灵活。根据您的游戏,一个给定的状态可以分支到许多不同类型的阶段。这形成了所有游戏阶段的图表。
在最高级别,驱动它的代码非常简单:
GamePhase state = ...initial phase
while(true) {
// read the state, do some ui work
state = state.turn();
}这是非常有用的,因为我现在可以轻松地为测试创建游戏的任何状态/阶段。
现在要回答你问题的第二部分,这是如何在多人游戏中工作的?在某些需要用户输入的GamePhase中,turn()的调用会在当前状态/阶段的情况下询问当前Player的Strategy。Strategy只是一个Player可以做出的所有可能决策的接口。这个设置还允许Strategy与AI一起实现!
安德鲁·托普还说:
你的游戏可能会处于(接近)无限状态,因为A玩家有多少钱,B玩家有多少钱,等等。因此,我很确定你想远离状态机。
我认为这种说法非常误导人,虽然确实有很多不同的游戏状态,但只有几个游戏阶段。为了处理他的示例,它将是我的具体GamePhase的构造函数的一个整数参数。
垄断
一些GamePhase的例子是:
基本GamePhase中的一些状态是:
然后,一些阶段会根据需要记录自己的状态,例如,PlayerRolls会记录球员连续翻滚的次数。一旦我们离开了PlayerRolls阶段,我们不再关心连续的滚动。
许多阶段可以重用并连接在一起。例如,GamePhase CommunityChestAdvanceToGo将创建具有当前状态的下一个阶段PlayerLandsOnGo并返回它。在PlayerLandsOnGo的构造函数中,当前的播放器将被移走,他们的钱将增加200美元。
https://stackoverflow.com/questions/361002
复制相似问题