Domanda

Ho un idea di organizzare un ciclo di gioco. Ho qualche dubbio circa le prestazioni. Può essere ci sono modi migliori di fare le cose.

Si consideri di avere una vasta gamma di componenti di gioco. Tutti sono chiamati a fare alcune cose ad ogni iterazione del gioco del ciclo. Ad esempio:

GameData data; // shared
app.registerComponent("AI", ComponentAI(data) );
app.registerComponent("Logic", ComponentGameLogic(data) );
app.registerComponent("2d", Component2d(data) );
app.registerComponent("Menu", ComponentMenu(data) )->setActive(false);
//...
while (ok)
{
//...
app.runAllComponents();
//...
}

Vantaggi:

  1. buona applicazione basata su componenti, senza dipendenze, buona modularità
  2. possiamo attivare / disattivare, registrare / componenti Usatela per eliminare dinamicamente
  3. alcune componenti può essere trasparente rimosso o sostituito e il sistema ancora dovrà lavorare come nulla hanno successo (cambiamento 2D a 3D) (lavoro di squadra: ogni programmatore crea le sue / suoi propri componenti e non richiede altri componenti per compilare il codice)

I dubbi:

  1. ciclo interno nel ciclo di gioco con le chiamate virtuali Component :: run ()
  2. Vorrei Component :: run () per restituire il valore booleano e verificare questo valore. Se ritornato falso, componente deve essere disattivata. Così ciclo interno diventa più costoso.

Bene, quanto è buono è questa soluzione? Hai usato in progetti reali?

È stato utile?

Soluzione

Alcuni programmatori C ++ hanno troppi timori circa il sovraccarico di funzioni virtuali. L'overhead della chiamata virtuale è generalmente trascurabile rispetto a qualsiasi funzione fa. Un controllo booleano non è molto costoso.

Do tutto ciò si traduce in codice più facile da mantenere. Ottimizzare dopo, solo se è necessario farlo. Se si fa trovare è necessario ottimizzare, eliminando le chiamate virtuali probabilmente non sarà l'ottimizzazione è necessario.

Altri suggerimenti

Nella maggior parte dei giochi "veri", non ci sono requisiti abbastanza rigorosi per interdipendenze tra i componenti, e l'ordinamento non importa.

Questo può o non effetto, ma è spesso importante avere la fisica abbiano effetto prima (o dopo) interazione con l'utente proecssing, a seconda dello scenario, ecc In questa situazione, potrebbe essere necessario un po 'di elaborazione aggiuntiva coinvolti per ordinare in modo corretto .

Inoltre, dal momento che si è più probabile intenzione di avere una qualche forma di grafico scena o il partizionamento spaziale, ti consigliamo di assicurarsi che i "componenti" in grado di trarre vantaggio da questo, pure. Questo probabilmente significa che, dato il vostro attuale descrizione, devi essere a piedi il vostro albero troppe volte. Anche in questo caso, però, questo potrebbe essere aggirato mediante decisioni di progettazione. Detto questo, alcuni componenti possono essere interessati solo a certe porzioni della partizione spaziale, e ancora una volta, che ci si vuole progettare in modo appropriato.

ho usato un approccio simile a un generatore di file audio sintetizzato modulare.

Mi sembra di ricordare notare che dopo la programmazione 100 moduli diversi, v'è stato un impatto su prestazioni quando codifica nuovi moduli in.

Nel complesso, però, mi è sembrato un approccio buono.

Forse sono oldschool, ma io davvero non vedo il valore in componenti generici, perché non vedo che vengano scambiati fuori in fase di esecuzione.

struct GameObject
{
   Ai* ai;
   Transform* transform;
   Renderable* renderable;
   Collision* collision;
   Health* health;
};

Questo funziona per tutto dal giocatore ai nemici a skybox e trigger; basta lasciare le "componenti" che non è necessario nella vostra data NULL oggetto. Si vuole mettere tutte le IA in un elenco? Poi basta fare che al momento della costruzione. Con il polimorfismo è possibile imbullonare tutti i tipi di comportamenti diversi in là (per esempio del giocatore "AI" sta traducendo l'ingresso del regolatore), e al di là di questo non c'è bisogno di una classe base generica per tutto. Che cosa avrebbe fatto, comunque?

Il tuo "update tutto" avrebbe dovuto chiamare esplicitamente ciascuna delle liste, ma questo non cambia la quantità di digitazione che devi fare, è semplicemente lo sposta. Invece di obfuscatorily impostare l'insieme di insiemi che hanno bisogno di operazioni globali, si sta enumerando in modo esplicito i set che hanno bisogno le operazioni al momento le operazioni sono fatte.

IMHO, non è che le chiamate virtuali sono lenti. E 'che "componenti" di un ente gioco non sono omogenei. Tutti fanno cose molto diverse, quindi ha senso trattarli in modo diverso. In effetti, non c'è sovrapposizione tra di loro, così ancora una volta chiedo, qual è il punto di una classe base, se non è possibile utilizzare un puntatore a tale classe base in modo significativo, senza il cast a qualcos'altro?

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