代码之家  ›  专栏  ›  技术社区  ›  Jay Bazuzi Buck Hodges

有没有模拟棋盘游戏的图案?[闭门]

  •  89
  • Jay Bazuzi Buck Hodges  · 技术社区  · 16 年前

    为了好玩,我试着把我儿子最喜欢的一款棋盘游戏作为一个软件来编写。最终我希望在上面构建一个WPF用户界面,但现在我正在构建一台模拟游戏及其规则的机器。

    (请注意,我对玩游戏的AI和围绕高性能的模式不感兴趣。)

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

    • 代表游戏盒中实体的几种不可变类型,例如骰子、跳棋、卡片、棋盘、棋盘上的空格、货币等。

    • 每个玩家的一个对象,包含玩家资源(如金钱、分数)、姓名等。

    • 代表游戏状态的对象:玩家、轮到谁、棋盘上的棋子布局等。

    • 管理转弯顺序的状态机。例如,许多游戏都有一个小的赛前游戏,每个玩家都要掷骰子看谁先去;这是开始状态。当一个玩家的回合开始时,首先他们滚动,然后他们移动,然后他们必须在原地跳舞,然后其他玩家猜他们是什么品种的鸡,然后他们得到分数。

    我最近意识到,游戏状态可以分为两类:

    • 游戏工件状态 . “我有10美元”或“我的左手是蓝色的”。

    • 博弈序列状态 . “我打了两次双打,下一次我就进监狱了。”。在这里,状态机可能是有意义的。

    编辑: 我在这里真正想要的是 实现多人回合游戏的方法,如国际象棋、拼字游戏或垄断游戏。我相信我可以通过从头到尾的工作来创建这样一个游戏,但是,像其他设计模式一样,可能有一些方法可以让事情进行得更加顺利,如果不仔细研究,这些方法是不明显的。这就是我所希望的。

    8 回复  |  直到 16 年前
        1
  •  117
  •   Andrew Top    16 年前

    这似乎是一个2个月前的线程,我刚刚注意到,但什么见鬼。我以前为一款商业的、网络化的棋盘游戏设计并开发过游戏玩法框架。我们有一个非常愉快的工作经验。

    你的游戏可能处于(接近)无限的状态,因为玩家a有多少钱,玩家B有多少钱,等等。。。因此,我很确定你想远离国家机器。

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

    我们使用了 Command Pattern 表示玩家可以执行的所有有效游戏操作。下面是一个示例操作:

    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
    };
    

    这个系统最终被证明有一个相当优雅的解决方案。有时行动会有两个或多个阶段。例如,玩家可能会在垄断的财产上着陆,现在必须做出新的决定。从玩家掷骰子到他们决定是否购买房产之间的博弈状态是什么?我们通过在游戏状态中加入一个“动作上下文”成员来管理这样的情况。动作上下文通常为空,表示游戏当前未处于任何特殊状态。当玩家掷骰子并将掷骰动作应用于游戏状态时,它将意识到玩家已降落在未拥有的财产上,并可以创建一个新的“PlayerDecideToPurchaseProperty”动作上下文,其中包含我们正在等待决定的玩家的索引。当掷骰子动作完成时,我们的游戏状态表示它正在等待指定的玩家决定是否购买房产。除了“BuyProperty”和“PassPropertyPurchaseOpportunity”操作外,所有其他操作的IsLegal方法现在都很容易返回false,这两个操作只有在游戏状态具有“PlayerDecideToPurchaseProperty”操作上下文时才合法。

    通过使用动作上下文,在棋盘游戏的生命周期中,没有一个点的游戏状态结构不能完全准确地表示在该时间点游戏中发生的事情。这是棋盘游戏系统非常理想的特性。当你只通过检查一个结构就可以找到你想知道的关于游戏中发生的事情的所有信息时,你编写代码就会容易得多。

    此外,它还可以很好地扩展到网络环境,在网络环境中,客户端可以通过网络将其操作提交给主机,主机可以将该操作应用于主机的“正式”游戏状态,然后将该操作回显给所有其他客户端,让它们将其应用于复制的游戏状态。

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

        2
  •  19
  •   RS Conley    16 年前

    游戏引擎的基本结构使用 State Pattern . 游戏盒中的项目如下所示: singletons 各种各样的。每个州的结构可以使用 Strategy Pattern the Template Method .

    A. Factory 用于创建插入到播放器列表中的播放器,另一个单件。GUI将使用 Observer pattern 并通过使用 Command Pattern . 观察者和命令的使用可以在 Passive View memento 它的当前状态

    site 看看他们有没有抓住你作为出发点。同样,游戏板的核心将是一个状态机。大多数游戏将由两个状态表示:游戏前/设置和实际游戏。但是如果你正在建模的游戏有几种不同的游戏模式,你可以有更多的状态。状态不必是连续的,例如战争游戏轴&战斗有一个战斗板,玩家可以使用它来解决战斗。所以游戏前有三种状态:主板、战斗板,游戏在主板和战斗板之间不断切换。当然,转弯顺序也可以用状态机表示。

        3
  •  17
  •   Pyrolistical    16 年前

    我刚刚使用多态性设计并实现了一个基于状态的游戏。

    GamePhase 这有一个重要的方法

    abstract public GamePhase turn();
    

    这意味着 配子期 对象保存游戏的当前状态,并调用 turn() .

    配子期 具有持有 游戏状态。每个 转() 方法中有一点游戏规则。在传播规则的同时,将相关规则保持在一起。每个项目的最终结果是什么 正在创建下一个 配子期 进入下一阶段。

    这允许 转()

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

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

    现在回答问题的第二部分,这在多人游戏中是如何工作的?在一定范围内 配子期 转() 我会问电流 Player Strategy 给定当前状态/阶段。 只是所有可能决策的接口 游戏者 我能做。此设置还允许 要用AI实现!

    安德鲁·托普还说:

    你的游戏可能处于(接近)无限的状态,因为玩家a有多少钱,玩家B有多少钱,等等。。。因此,我很确定你想远离国家机器。

    配子期 s

    垄断

    配子期 这将是:

    • 游戏者
    • PlayerLandsOnProperty(免费停车场、GoToJail、Go等)
    • PlayerTrades
    • PlayerPurchaseProperty
    • PlayerPurchaseHouse
    • PlayerPurchaseHotels酒店
    • (所有机会卡和公益金卡)

    配子期 是:

    • 球员名单
    • 玩家的金钱/财产
    • 球员位置

    然后一些阶段会根据需要记录自己的状态,例如PlayerRolls会记录一名球员连续翻滚双打的次数。一旦我们离开PlayerRolls阶段,我们就不再关心连续掷骰了。

    许多阶段可以重用并链接在一起。例如 配子期 CommunityChestAdvanceToGo 将创建下一个阶段 PlayerLandsOnGo PlayerLandsOnGo 当前玩家将被移动到Go,他们的钱将增加200美元。

        4
  •  9
  •   Stefan    16 年前

    但是我认为您在正确的道路上划分对象,让它们处理自己的事件/数据等等。

    在进行基于平铺的棋盘游戏时,你会发现在棋盘阵列和行/列之间以及在其他功能之间映射例程很好。我记得我的第一次棋盘游戏(很久以前),当时我绞尽脑汁研究如何从boardarray 5中获取行/列。

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

    占卜术

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

        5
  •  6
  •   Eric Weilnau    16 年前

    我能在网上找到的大部分资料都是已发表参考文献的列表。政府刊物出版组 Game Design Patterns 链接到文章和论文的PDF版本。其中许多看起来像是学术论文 Design Patterns for Games . 亚马逊上至少有一本书, Patterns in Game Design .

        6
  •  4
  •   jmucchiello    16 年前

    Three Rings 提供LGPL的Java库。Nenya和Vilya是游戏相关资料的库。

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

        7
  •  3
  •   Reasurria    10 年前

    巧合的是,我也用了他的“游戏阶段”命名。基本上,对于基于回合的棋盘游戏,我会做的是让您的GameState类包含Pyrolistical提到的抽象GamePhase的对象。

    假设游戏状态为:

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

    您可以为每个状态创建具体的派生类。至少具有以下虚拟功能:

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

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

    调用roll.EndPhase()时,请确保游戏阶段指针设置为下一个状态。

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

    例如,在此MovePhase::StartPhase()中,您可以将活动玩家的剩余移动设置为前一阶段的滚动量。

    现在有了这个设计,你就可以在翻滚阶段解决你的“3xdouble=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的不同之处在于,每件事都应该有一个阶段,包括玩家在社区公益金或其他东西上落地的时候。我会在移动阶段处理这一切。这是因为如果你有太多的连续阶段,玩家很可能会觉得太“引导”。例如,如果有一个阶段,玩家只能购买房产,然后只能购买酒店,然后只能购买房屋,这就像没有自由一样。只需将所有这些部分塞入一个购买阶段,就可以让玩家自由购买任何他想要的东西。BuyPhase类可以很容易地处理哪些购买是合法的。

    最后,让我们谈谈游戏板。虽然2D阵列很好,但我建议使用一个平铺图(其中平铺是电路板上的一个位置)。在垄断的情况下,它宁愿是一个双链表。然后每个瓷砖都会有一个:

    1. 以前的瓷砖
    2. 奈克斯提尔

    因此,这样做更容易:

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

    RS Conley关于GUI的观察者模式的建议是好的。

    我以前没发过多少帖子。希望这对别人有帮助。

        8
  •  2
  •   zotherstupidguy    15 年前

    是否有我可以利用的现有技术?

    如果您的问题不是特定于语言或平台的。然后我建议您考虑AOP模式的状态、纪念品、命令等。

    AOP的.NET答案是什么???

    还可以尝试找到一些很酷的网站,比如 http://www.chessbin.com