逻辑设计模式

发布于 2024-07-15 19:14:54 字数 659 浏览 7 评论 0原文

在游戏中,许多实体应该每帧更新。 我正在尝试不同的设计模式来实现这一目标。 到目前为止,我已经有一个单例管理器类,每个逻辑实例都添加到其中。 但我正在考虑以下内容,逻辑类本身的静态列表。 这很好,因为它会从项目中删除一个类。 本例中的“Engine”将是调用 update_all 的主类。

class Logic
{
public:
    Logic() { all.push_back(this); }
    virtual ~Logic() { all.erase(this); }
    virtual void update(float deltatime) = 0;

private:
    friend Engine;
    static std::list<Logic*> all;
    static void update_all(float deltatime)
    {
        for (std::list::iterator i = all.begin(); i!=all.end(); ++i)
            (*i)->update(deltatime);
    }
};
  • 这个图案有名字吗?
  • 您认为这是比单例管理器类更好的方法吗?
  • 还有其他评论或警告吗?

In a game, many entities should be updated every frame. Im toying with different design patterns to achieve this. Up until now, Ive had a singleton manager class to which every Logic instance is added. But Im considering the following, a static list in the Logic class itself. This is nice since it would remove a class from the project. "Engine" in this example would be the master class calling the update_all.

class Logic
{
public:
    Logic() { all.push_back(this); }
    virtual ~Logic() { all.erase(this); }
    virtual void update(float deltatime) = 0;

private:
    friend Engine;
    static std::list<Logic*> all;
    static void update_all(float deltatime)
    {
        for (std::list::iterator i = all.begin(); i!=all.end(); ++i)
            (*i)->update(deltatime);
    }
};
  • Does this pattern have a name?
  • Do you consider this a nicer approach than a singleton manager class?
  • Any other comments or caveats?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

欢你一世 2024-07-22 19:14:54

首先,您需要使用 remove() 而不是 erase() (后者需要一个迭代器作为参数)

如果您使用稍微不同的循环,就像

std::list<Logic*>::iterator it = all.begin();
while (it != all.end()) {
  Logic* current = *it;
  ++it;
  current->update(deltatime);
}

您甚至可以克服提到的问题siukurnin(在 update() 期间删除逻辑对象)。 list::remove() 不会使迭代器无效,除了指向已删除元素的迭代器。

除此之外,我还投票支持这是单例模式的变体。 我建议将原始解决方案保留为单独的管理类,以防万一您希望拥有两个具有不同增量时间的循环或显式多线程支持(不同线程上的不同逻辑对象)或将来的任何情况。

在我看来,这是单例类相对于静态方法(您始终可以使用静态方法)的一般优势:如果您将来想这样做,您可以轻松地增加您的功能......

First, you need to use remove() instead of erase() (the latter would need an iterator as argument)

If you use a slightly different loop like

std::list<Logic*>::iterator it = all.begin();
while (it != all.end()) {
  Logic* current = *it;
  ++it;
  current->update(deltatime);
}

you can even overcome the problem siukurnin mentioned (deletion of a Logic object during update()). list::remove() doesn't invalidate iterators except of the ones pointing to the removed element.

Apart from this, I also vote for this being a variation of the singleton pattern. And I would suggest for keeping the original solution with a separate management class, just in case you want to have to have two loops with different delta times or explicit multithread support (different Logic objects on different threads) or whatever in the future.

In my opinion this is a general advantage of the singleton class over static methods (which you could always use): You can easily multiply your functionality if you want to do so in the future ...

青萝楚歌 2024-07-22 19:14:54

您还可以使用观察者模式来实现此目的

You can also use observer pattern for this

—━☆沉默づ 2024-07-22 19:14:54

我认为它仍然是一个单例:“只能有一个”

单例是一种模式,一个概念:你可以以不同的方式实现它......

静态类成员或全局实例是同一想法的两种可能的实现。

问题是:为什么要改变它?

I think its still a singleton : "there can be only one"

The singleton is a pattern, a concept : you can implement it different ways...

A static class member or a global instance are two possible implementations of the same idea.

The question is : why do you want to change it ?

不即不离 2024-07-22 19:14:54

恕我直言,这是一种观察者模式(参见对每个订阅者的更新调用),其中主题恰好是单例。

在更新观察者时取消注册的“警告”是一个困难的问题。 我发现自己多次陷入困境。

关于我的问题的这个答案暗示了该问题的一个优雅的解决方案关于它:对于每个观察者,添加一个中间“代理”,其中包含指向“真实”观察者的指针。 取消注册相当于交换(原子地)代理的指针。 更新后,所有带有空指针的代理都可以安全删除。

Imho, it's an Observer pattern (cfr the update call to every subscriber), in which the Subject happens to be a Singleton.

The 'caveat' of unregistering while updating the observers is a hard one. I found myself struggling with it many times.

An elegant solution to that problem was hinted in this answer on my question about it: for every observer, add an intermediate 'proxy' containing a pointer to the 'real' observer. Unregistering is then equivalent to swapping (atomically) the proxy's pointer. After updating, all proxies with null pointers can be removed safely.

只怪假的太真实 2024-07-22 19:14:54

一般来说,您希望在每次更新调用时遍历游戏中的每个实体,因此您可以继续使用 复合模式,其中您将有一个根节点。 由此,您将递归地遍历节点并调用每个实体的 update() 方法。 从我从您的代码中可以看到,您已经有了一个列表,但是使用复合模式,您可以创建实体组,这可能会简化您的任务。

据我了解,您的引擎只需调用根节点的 Update() 方法(如果您使用复合模式)。 由此,根节点将使用其 update() 调用后续节点。 在复合树的某个时刻,您将到达知道如何正确更新自身的叶子。

您只需要在引擎中拥有一个指向根节点的指针,该指针将具有一个函数 UpdateAll() (或其他函数),然后该函数将调用 rootNode->Update(); 反过来,它将执行我在上一段中描述的操作。

Generally, you want to go through every entities in your game each update call, thus you could go ahead and use a Composite pattern where you'd have a root node. From that, you'd go recursively through the node and call each entity' update() method. From what I can see from your code, you already have a list, but using the composite pattern, you'd be able to make groups of entities instead, which might simplify your task.

From what I understand, your Engine simply need to call the Update() method of the root node (if you use a composite pattern). From that, the root node will call subsequent node using their update(). At some point through the composite tree, you'll reach leafs who will know how to update themselves correctly.

You will only need to have a pointer to your root node in your engine which will have a function UpdateAll() (or something else) which will then call rootNode->Update(); which in turn, will do what I described in the previous paragraph.

第七度阳光i 2024-07-22 19:14:54

需要注意的是,此模式(当前)不允许在调用 update_all 期间删除 Logic 实例,因为这会使迭代器指针无效。

解决方案可能是将析构函数设为私有,并让 update 返回一个标志,说明是否应删除实例?

One caveat would be that this pattern (currently) doesnt allow Logic instances to be deleted during the call to update_all, since it would invalidate the iterator pointer.

A solution could be maybe to make the destructor private and letting update return a flag stating if the instance should be deleted or not?

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文