0

ゲームでは、フレームごとに多くのエンティティを更新する必要があります。これを実現するために、さまざまなデザインパターンをいじっています。これまで、Ive にはすべての Logic インスタンスが追加されるシングルトン マネージャー クラスがありました。しかし、ロジッククラス自体の静的リストである次のことを検討しています。プロジェクトからクラスを削除するので、これは素晴らしいことです。この例の「エンジン」は、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);
    }
};
  • このパターンに名前はありますか?
  • これは、シングルトン マネージャー クラスよりも優れたアプローチだと思いますか?
  • その他のコメントや注意事項はありますか?
4

6 に答える 6

2

これにはオブザーバーパターンを使用することもできます

于 2009-03-23T15:28:13.560 に答える
2

まず、remove()代わりに使用する必要erase()があります (後者には引数としてイテレータが必要です)

次のようなわずかに異なるループを使用する場合

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

siukurninが言及した問題 (update() 中の Logic オブジェクトの削除) を克服することもできます。list::remove()削除された要素を指すものを除いて、反復子を無効にしません。

これとは別に、私はこれがシングルトン パターンのバリエーションであることに投票します。また、異なるデルタ時間または明示的なマルチスレッド サポート (異なるスレッド上の異なる Logic オブジェクト) などを将来的に使用する 2 つのループが必要な場合に備えて、別の管理クラスを使用して元のソリューションを維持することをお勧めします。

私の意見では、これは静的メソッド(常に使用できる)に対するシングルトンクラスの一般的な利点です。将来的に機能を増やしたい場合は、簡単に機能を増やすことができます...

于 2009-03-23T15:41:46.553 に答える
1

一般に、更新呼び出しごとにゲーム内のすべてのエンティティを処理する必要があるため、先に進んで、ルート ノードを持つコンポジット パターンを使用できます。そこから、ノードを再帰的に調べて、各エンティティの update() メソッドを呼び出します。あなたのコードからわかることから、既にリストがありますが、複合パターンを使用すると、代わりにエンティティのグループを作成できるため、タスクが簡素化される可能性があります。

私の理解では、エンジンはルート ノードの Update() メソッドを呼び出すだけです (複合パターンを使用する場合)。そこから、ルート ノードは update() を使用して後続のノードを呼び出します。複合ツリーのある時点で、自分自身を正しく更新する方法を知っているリーフに到達します。

rootNode->Update(); を呼び出す関数 UpdateAll() (またはその他のもの) を持つエンジン内のルート ノードへのポインタのみが必要です。次に、前の段落で説明したことを実行します。

于 2009-06-05T21:44:21.993 に答える
1

まだシングルトンだと思います:「1つしかありません」

シングルトンはパターン、概念です。さまざまな方法で実装できます...

静的クラス メンバーまたはグローバル インスタンスは、同じアイデアの 2 つの可能な実装です。

問題は、なぜ変更したいのかということです。

于 2009-03-23T15:15:24.073 に答える
1

私見、これはオブザーバーパターン(updateすべてのサブスクライバーへの呼び出しを参照)であり、サブジェクトはたまたまシングルトンです。

オブザーバーの更新中に登録を解除するという「警告」は難しいものです。私は何度もそれに苦労していることに気づきました。

その問題に対するエレガントな解決策は、それに関する私の質問に対するこの回答で示唆されました。すべてのオブザーバーに対して、「実際の」オブザーバーへのポインターを含む中間の「プロキシ」を追加します。登録解除は、プロキシのポインタを (アトミックに) 交換することと同じです。更新後、null ポインタを持つすべてのプロキシは安全に削除できます。

于 2009-03-23T15:42:25.040 に答える
0

1 つの注意点は、このパターン (現在) では、update_all の呼び出し中にロジック インスタンスを削除できないことです。これは、反復子ポインターが無効になるためです。

解決策は、デストラクタを非公開にし、インスタンスを削除する必要があるかどうかを示すフラグを update に返させることでしょうか?

于 2009-03-23T15:13:10.990 に答える