Il modo migliore per memorizzare variabili a livello di gioco


23

Ho una schermata di opzioni per cose come difficoltà, risoluzione, schermo intero, ecc., Ma faccio fatica a trovare il modo "migliore" per archiviare / ottenere queste variabili in fase di esecuzione.

Attualmente, ho implementato una Constantsclasse che contiene tutti gli GameOptionenum, ma come faccio a scegliere un valore predefinito per tutte queste opzioni? Inoltre, come posso ottenere l'enum attualmente selezionato?

Per quanto riguarda la risoluzione, in particolare, ho deciso di memorizzare i valori, ma non sono sicuro di come ottenere i valori predefiniti o attualmente memorizzati. Qualsiasi direzione sarebbe fantastica; Grazie! :)

namespace V1.test.RPG
{
  public class GameOptions
  {
    public enum Difficulty { EASY, MEDIUM, HARD }
    public enum Sound { ON, QUIET, OFF }
    public enum Music { ON, QUIET, OFF }
    public enum ResolutionWidth
    {
        SMALL      = 1280,
        MEDIUM     = 1366,
        LARGE      = 1920,
        WIDESCREEN = 2560
    }
    public enum ResolutionHeight
    {
        SMALL      = 800,
        MEDIUM     = 768,
        LARGE      = 1080,
        WIDESCREEN = 1080
    }
    public Boolean fullScreen = false;
  }
}

NB: ho chiesto a SO e mi hanno indicato questo posto. C'è un commento lì, ma mi piacerebbe sentire diversi modi di farlo / i modi più usati.


1
Hai chiesto nel posto giusto; chiunque ti abbia mandato qui si è sbagliato. Ho comunque risposto alla domanda per aiutarti, ma questa non è una domanda specifica sullo sviluppo del gioco, questa è una domanda di programmazione generale.
jhocking

Ho appena letto il thread SO; Mi piace la risposta di Scott Chamberlin.
derisione

@jhocking L'ho indicato in questo modo nel caso in cui ci siano aspetti particolari dello sviluppo del gioco che potrebbero differire da una normale applicazione. Ho anche pensato che voi ragazzi potreste già avere una domanda e risposta canonica su questo argomento poiché è così comune.
Chris Hayes,

Tangenziale alla vera domanda sui globi, per favore non dare per scontato che ci sia una serie fissa di risoluzioni là fuori.
Lars Viklund,

Risposte:


32

Pianificazione della crescita: le
costanti hardcoded vanno bene per i piccoli progetti ma, alla fine, man mano che il software aumenta di dimensioni, vorrai poter modificare quelle impostazioni senza dover ricompilare tutto. Ci sono molte volte che vorresti cambiare le impostazioni mentre il gioco è in esecuzione e non puoi farlo con costanti codificate.

CVars: una
volta che il tuo progetto cresce, potresti dare un'occhiata ai CVAR . Una CVAR è una "variabile intelligente", per così dire, che è possibile modificare durante il runtime tramite una console, un terminale o un'interfaccia utente. Le CVAR sono generalmente implementate in termini di un oggetto che avvolge un valore sottostante. L'oggetto può quindi tenere traccia del valore e salvarlo / caricarlo nel / dal file. È possibile memorizzare gli oggetti CVAR in una mappa per accedervi con un nome o un altro identificatore univoco.

Per illustrare ulteriormente il concetto, il seguente pseudo-codice è un semplice esempio di un tipo CVAR che avvolge un intvalore:

// just some flags to exemplify:
enum CVarFlags {
    CVAR_PERSISTENT, // saved to file once app exits
    CVAR_VOLATILE    // never saved to file
};

class CVar {
public:
    // the constructor registers this variable with the global list of CVars
    CVar(string name, int value, int defaultValue, int flags);

    int getValue();
    void setValue(int v);
    void reset(); // reset to the default value

    // etcetera...

private:
    int flags; // flags like: save-to-file, etc.
    int value; // the actual value
    int defaultValue; // the default value to reset the variable to
};

// global list of all CVars:
map<string, CVar> g_cvars;

Accesso globale:
nell'esempio sopra, ho assunto che il costruttore di CVarregistri sempre la variabile con la cvarsmappa globale ; questo è abbastanza utile, poiché ti permette di dichiarare una variabile in questo modo:

CVar my_var = new CVar("my_var", 0, 42, CVAR_PERSISTENT);

Quella variabile viene automaticamente resa disponibile nella mappa globale e puoi accedervi da qualsiasi altra parte indicizzando la mappa con il nome della variabile:

CVar v = g_cvars.find("my_var");

Persistenza:
quando il gioco si sta chiudendo, itera la mappa e salva tutte le variabili contrassegnate come CVAR_PERSISTENTin un file. La prossima volta che il gioco inizia, ricaricalo.

Giurisprudenza:
per un esempio più specifico di un solido sistema CVAR, controlla l'implementazione descritta in Doom 3 .


4

Beh prima di tutto un definisce enum quali sono i valori possono essere , non quello che i valori sono . Quindi è ancora necessario dichiarare un'altra variabile dopo aver dichiarato l'enum. Per esempio:

public enum Sound
{
    ON,
    QUIET,
    OFF
}

public Sound soundValue;

In questo esempio, ora puoi impostare soundValuesu ON, QUIET o OFF.


Quindi è ancora necessario strutturare il codice in modo che altre parti del codice possano accedere a questo oggetto "Impostazioni". Non so se hai bisogno di aiuto anche con quella parte, ma i modelli comuni per affrontare questo problema includono i singleton (quelli sono corrugati in questi giorni) o i localizzatori di servizio o l'iniezione di dipendenza.


1

La soluzione glampert è molto completa, ma aggiungerò la mia esperienza personale.

Ho riscontrato questo stesso problema e la mia soluzione era quella di utilizzare una classe di variabili statiche.

La classe Variabili mantiene internamente una mappa da stringa a stringa (finora tutte le mie variabili sono solo stringhe) e vi si accede tramite getter e setter.

Il punto è che l'accesso alle variabili globali può introdurre tutti i tipi di errori sottili poiché parti del codice totalmente non correlate si stanno improvvisamente interferendo.

Per evitarlo, ho imposto la seguente semantica: l'uso del setmetodo genera un'eccezione se nel dizionario esiste già una variabile con quel nome ed getelimina la variabile dal dizionario prima di restituirla.

Due metodi aggiuntivi forniscono ciò che ti aspetteresti setAndOverwritee getAndKeep. Il punto della semantica degli altri metodi è che puoi facilmente individuare errori del tipo "questo metodo dovrebbe inizializzare questa variabile, ma altri metodi l'hanno fatto prima".

Per inizializzare il dizionario, le variabili iniziali sono memorizzate in un file json e quindi lette all'avvio del gioco.

Purtroppo non sono ancora troppo lontano dal mio gioco, quindi non posso testimoniare per la solidità di questo approccio. Tuttavia, forse può fornire qualcosa di interessante oltre ai CVAR.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.