为这组对象寻找一个好的设计模式

时间:2010-10-17 15:15:45

标签: design-patterns language-agnostic

我最初在programmers.stackexchange.com上问过this question,因为我认为答案对于stackoverflow来说太主观了。但是,在评论Muad'Dib中指出了这一点:

  

这可能更适合StackOverflow ...这是一个与编程问题直接相关的问题,并讨论了编程解决方案。一种解决方案可能与另一种解决方案相同,其中它们之间的选择是主观的,但对整体问题本身的讨论并不是因为某些解决方案显然不适用。所以这个问题确实有一个或几个好的答案,而诸如“哪个是最好的文本编辑器?”之类的问题。没有......

所以,在稍微考虑一下这种情况之后(看一些似乎不适合的模式),这就是我的困境:

设置

我正在设计一款简单的战斗策略游戏。

  1. 两名战斗员互相攻击一段时间。
  2. 获胜者是时间到了之后最健康的人。
  3. 在比赛中没有球员的直接干预。在战斗之前,玩家为战斗员定义了一些策略,而“AI”(松散地使用的术语)决定了战斗员的行为。
  4. 战斗包括一个“嘀嗒”秒的任意计时器,战斗员的攻击速度(以及其他因素)决定了他们做某事的频率。
  5. 除了战斗物,还有一个“天气”物体,可以对战士的能力产生一些随机的环境影响。
  6. 整个事情只是循环每一秒,确定并执行环境影响和攻击,全部记录,然后日志作为逐个播放显示给用户。
  7. 问题

    我不确定哪种设计模式最能让我完成上述任务。我正在寻找一种模式,这将使我能够增加“战斗”的复杂性。可能通过在战斗中添加更多对象(更多战斗员,可能是新的环境对象等)

    起初我认为Observer模式可行。我会有一个代表“观察者/主体”的战斗对象。它跟踪一个计时器,当计时器递增时,它会更新所有参与者观察者对象。然而,很多后卫战斗员的参数会影响攻击者战斗员的行为,所以那个场景中的“观察者”需要彼此了解,所以我不确定这是否是正确的方法。

    最后,我并没有试图完美地设计出一种设计模式。也许没有“最合适的”。我只是在寻找一个坚实的基础来建立。

3 个答案:

答案 0 :(得分:2)

尝试为相当详细的情况找到一个“正确”的设计模式是徒劳无功的搜索。设计模式可以解决某些特定编程语言或语言中出现的常见低级情况 - 对于您可能找到的每种可能情况,都不一定存在特定的情况,也不一定只使用一个单独的情况来解决您的问题。问题

特别是这种情况并不是真正的设计模式 - 设计模式主要涉及类和对象之间的静态关系,而你在这里谈论的本质上是算法本质上。设计模式提供了实现算法的方法,但实际上并不是算法。

这应该非常简单。你有一个运行指定持续时间的while循环。每次迭代代表经过时间的一秒,并且在该迭代中,它将在战斗中涉及的每个相关对象上调用一个或多个方法 - 战斗员,天气等。(多少种方法和哪些是游戏设计问题,而不是(还)一个编程问题。)这些对象可以来自一个战斗对象,如果你愿意,它可以保存整个上下文。

这里没有真正需要观察者模式,事实上,通过将其从易于理解的迭代过程变为事件驱动过程,它将使事情变得非常复杂。如果需要访问各种属性,战斗员可以直接查询其他战斗员。

答案 1 :(得分:1)

如果你真的想在这里使用一个模式,我会考虑一个命令模式。 例如,您可以将一串命令“争取移动”排成一段时间来执行。您还可以根据对手的操作轻松而一般地轻松取消命令。随着您开发游戏,您可以轻松地添加移动/策略。

但这不是整个游戏的模式,它更像是一个方面的解决方案。

答案 2 :(得分:0)

好吧,一切都可以通过对象建模:)

让我们假设你不需要“真正的”秒 - 你可以计算整个战斗,保存日志中的每一步,在数据库中的某个地方保持日志,然后每秒向玩家显示一行“行”。你的日志不仅仅是字符串,而且可以包含“此刻”的序列化战斗员数据,因此你甚至可以进行“互动”战斗(玩家可以在战斗中改变他们的战斗策略,你可以重新计算作为新起点的反序列化战斗状态的战斗点)。

下一个。让每个战士都是对象:

class Combatant {
  public $strategy;
  public takeDamage($damageType,$damageAmount){
     if($this->strategy->tryAvoidDamage($damageType,$damageAmount)) return;
     $newDamageAmount=$this->reduceDamageByArmor($damageType,$damageAmount);
     $newDamageAmount=$this->reduceDamageByAbilities($damageType,$newDamageAmount);
     // change your health below...
  }

  public dealDamage($weapoon, $enemy){
     $damageType = $weapoon->damageType;
     $damageAmount = $weapoon->damageAmount;
     $damageAmount = this->applySkills($weapoon, $damageType, $damageAmount);
     $enemy->takeDamage($damageType, $damageAmount);
  }

}  

策略也是对象:

class Strategy{
   public $combatant;
   public tryAvoidDamage($damageType,$damageAmount){
     if($damageType=="melee" && $combatant->actionPoints>10){
       // try to block punch (roll dice for skills etc)
       return $combatant->tryBlockPunch();
     }
     return false; // can't avoid bullet
   }
   public DoAction($enviroment){
      if($combatant->hp<10){
         $combatant->tryCastHealing();
      } else {
        var $enemy = $enviroment->findEnemes()->whereDistanceLessThan(2)->mostWeak();
        if($enemy != null) {
           $combatant->dealDamage($combatant->hands, $enemy) 
        }
      }
   }   
}

您需要的下一件事是在运行循环时创建和初始化正确的对象

while($combatantA->isAlive() && $combatantB->isAlive()){
  $combatantA->strategy->DoAction(...)
  $combatantB->strategy->DoAction(...)
}