Domanda

In un gioco, molte entità dovrebbe essere aggiornata ogni fotogramma. Im giocando con diversi modelli di progettazione per raggiungere questo obiettivo. Fino ad ora, Ive ha avuto una classe dirigente Singleton a cui si aggiunge ogni istanza Logic. Ma Im considerando il seguito, un elenco statico nella classe logica stessa. Questo è bello poiché eliminerebbe una classe dal progetto. "Motore" in questo esempio potrebbe essere la master class chiamando l'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);
    }
};
  • Questo modello ha un nome?
  • Lei ritiene che questo un approccio più bello di una classe dirigente Singleton?
  • Qualsiasi altro commento o avvertimenti?
È stato utile?

Soluzione

In primo luogo, è necessario utilizzare remove() invece di erase() (quest'ultimo avrebbe bisogno di un iteratore come argomento)

Se si utilizza un ciclo leggermente diversa come

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

si può anche superare il problema siukurnin menzionato (soppressione di un oggetto logico durante l'aggiornamento ()). list::remove() non invalida iteratori ad eccezione di quelli che puntano all'elemento rimosso.

Oltre a questo, ho anche votato per questo essere una variazione del pattern Singleton. E vorrei suggerire per mantenere la soluzione originale con una classe di gestione separata, nel caso in cui si desidera avere avere due anelli con diversi tempi di delta o sostegno esplicito multithread (diversi oggetti logici su diversi thread) o qualsiasi altra cosa in futuro.

A mio parere questo è un vantaggio generale della classe Singleton rispetto ai metodi statici (che si può sempre usare): Si può facilmente moltiplicare il vostro funzionalità se si vuole fare in futuro ...

Altri suggerimenti

È inoltre possibile utilizzare pattern Observer per questo

Credo che la sua ancora un Singleton: "non ci può essere un solo"

Il singleton è un modello, un concetto: è possibile implementare modi diversi ...

Un membro della classe statica o un'istanza globale sono due possibili implementazioni della stessa idea.

La domanda è: perché vuoi cambiarlo

?

IMHO, si tratta di un pattern Observer (cfr il update chiamata a ogni utente), in cui il soggetto sembra essere un Singleton.

Il 'avvertimento' di annullamento della registrazione durante l'aggiornamento degli osservatori è un duro. Mi sono trovato a lottare con lui molte volte.

Una soluzione elegante a questo problema è stato accennato in questa risposta sulla mia domanda a questo proposito: per ogni osservatore, aggiungere un 'delega' intermedio contenente un puntatore a un osservatore 'reale'. L'annullamento della registrazione è quindi equivalente a scambiare (atomicamente) puntatore del proxy. Dopo l'aggiornamento, tutti i proxy con puntatori nulli possono essere rimossi in tutta sicurezza.

In generale, si vuole passare attraverso ogni entità nel vostro gioco ogni chiamata di aggiornamento, in tal modo si potrebbe andare avanti e di utilizzare un composite in cui si avrebbe un nodo radice. Da questo, devi andare in modo ricorsivo attraverso il nodo e chiamare ogni metodo entità update'(). Da quello che posso vedere dal codice, si dispone già di una lista, ma utilizzando il composite, si sarebbe in grado di fare gruppi di entità, invece, che potrebbe semplificare il vostro compito.

Da quanto ho capito, il tuo motore semplicemente bisogno di chiamare il metodo Update () del nodo principale (se si utilizza un composite). Da questo, il nodo radice chiamerà successivo nodo mediante il loro aggiornamento (). Ad un certo punto attraverso l'albero composito, si raggiunge foglie che sapranno come aggiornare se stessi in modo corretto.

Sarà solo bisogno di avere un puntatore al nodo principale nel motore che avrà una funzione UpdateAll () (o qualcos'altro) che sarà poi chiamata rootNode-> Update (); che a sua volta, farà quello che ho descritto nel paragrafo precedente.

Un avvertimento sarebbe che questo schema (attualmente) pretende consentire istanze logiche da eliminare durante la chiamata a update_all, in quanto invaliderebbe il puntatore iteratore.

Una soluzione potrebbe essere forse per rendere il distruttore privato e aggiornamento lasciando restituire un flag che indica se l'istanza deve essere eliminato o no?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top