模式以避免在虚拟调用上循环

时间:2012-11-02 20:31:28

标签: c++ design-patterns

在我的游戏中,我通常会让每个NPC /项目等都来自基类"实体"。然后他们基本上都有一个名为" update"的虚拟方法。我会在每一帧的游戏中为每个实体分类。我假设这是一个有很多缺点的模式。 有哪些其他方法可以管理不同的游戏对象"整场比赛?还有其他众所周知的模式吗? 我基本上试图找到更好的模型,而不是从基类派生所有内容,这将跨越一个巨大的继承树和虚拟函数无处不在

2 个答案:

答案 0 :(得分:2)

还有另一种涉及继承行为的模式。

例如:剑(在幻想风格的游戏中)可以从Describable继承,以便能够向玩家描述;它还将继承DoDamage来处理损失;它进一步继承自Grabable,因此玩家可以“抓住”它。

一件盔甲可以继承DamageReduction以降低伤害,以及Wearable所以玩家可以佩戴它。

您可以获得许多更小更浅的继承树,而不是大而深的继承树。缺点当然是你必须创建许多类,并考虑可能发生的不同行为和事件。

答案 1 :(得分:1)

让您的对象在将来的某个时间点请求更新。

struct UpdateToken {
  UpdateToken() {}
  /* ... */
};
class Updater {
  // ...
  struct UpdateEntry
  {
    UpdateToken token;
    Time when;
    bool repeats;
    Time frequency
    std::function<void()> callback;
  };
  // Various indexes into a collection of UpdateEntries
  // sorted by when and by token so you can look up both ways quickly
public:
  UpdateToken RegisterUpdate( Time t, std::function<void()> callback ); // once after time t
  UpdateToken RegularUpdate( Time t, std::function<void()> callback ); // every time t

  void UnregisterUpdate( UpdateToken );
};
Updater* GetUpdater();

// use:
class Foo
{
  UpdateToken token;

  void DoUpdate()
  {
    std::cout << "I did it!\n";
  }

  void PlanRepeatingUpdate( Time t )
  {
    if (!GetUpdater())
      return;
    if (token.valid())
      GetUpdater()->UnregisterUpdate(token);
    token = GetUpdater()->RegularUpdate( t, [&]()->void
    {
      this->DoUpdate();
    });
  }
  ~Foo() { if (token.valid() && GetUpdater()) GetUpdater()->UnregisterUpdate(token); }
};

这里我们有一个未来事件的来源(Updater())和j随机类Foo,可以在其中为一个重复或一系列重复注册回调。

您可以在0.1秒,1秒或1小时内要求更新。如果您碰巧被销毁,或者不想要更新,您可以取消注册,但它永远不会到达。

必须在Updater中加入一些功能,以便它可以找到下一个要快速调用的事件,并可以通过令牌查找更新。我已经看过一个Boost双重索引容器,或者你可以通过主std :: set(或无序集)手动处理它,并且第二组迭代器的第二组具有唯一的排序,你管理得非常谨慎(你必须注意使迭代器无效的原因,并确保迭代器集合不包含任何内容)。

上面也有效地使用了一个全局的Updater()实例,这通常不是理想的。