Melhor maneira de armazenar variáveis ​​em todo o jogo

23

Eu tenho uma tela de opções para coisas como dificuldade, resolução, tela cheia, etc., mas estou lutando para encontrar a "melhor" maneira de armazenar / obter essas variáveis ​​em tempo de execução.

Atualmente, implementei uma Constantsclasse que contém todas as GameOptionenumerações, mas como escolho um padrão para todas essas opções? Além disso, como obtenho a enumeração atualmente selecionada?

Em relação à resolução, especificamente, decidi armazenar os valores, mas não tenho certeza de como obter os valores padrão ou atualmente armazenados. Qualquer direção seria ótima; obrigado! :)

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: perguntei na SO e eles me indicaram esse lugar. Há um comentário lá, mas eu gostaria de ouvir maneiras diferentes de fazê-lo / as formas mais usadas.

R-nold
fonte
1
Você perguntou no lugar certo; quem mandou você aqui estava enganado. De qualquer maneira, respondi à pergunta para ajudá-lo, mas essa não é uma questão específica de desenvolvimento de jogos, é uma questão de programação geral.
jhocking
Acabei de ler o tópico SO; Eu gosto da resposta de Scott Chamberlin.
Jhocking
@jhocking Apontei para ele dessa maneira, caso haja aspectos específicos do desenvolvimento de jogos que possam diferir de um aplicativo comum. Eu também imaginei que vocês já podem ter uma sessão de perguntas e respostas canônicas sobre esse tópico, pois é muito comum.
21814 Chris Hayes
Tangencial à pergunta real sobre os globais, não assuma que há um conjunto fixo de resoluções por aí.
Lars Viklund #

Respostas:

32

Planejando crescer:
constantes constantes codificadas são adequadas para pequenos projetos, mas, eventualmente, à medida que seu software cresce, você deseja alterar essas configurações sem precisar recompilar tudo. Há muitas vezes que você deseja alterar as configurações enquanto o jogo está rodando e não é possível fazer isso com constantes codificadas.

CVars:
Depois que seu projeto cresce, você pode dar uma olhada nos CVARs . Um CVAR é uma "variável inteligente", por assim dizer, que você pode modificar durante o tempo de execução por meio de um console, terminal ou interface do usuário. Os CVARs geralmente são implementados em termos de um objeto que envolve um valor subjacente. O objeto pode, então, acompanhar o valor e salvá-lo / carregá-lo no / do arquivo. Você pode armazenar os objetos CVAR em um mapa para acessá-los com um nome ou outro identificador exclusivo.

Para ilustrar um pouco mais o conceito, o pseudocódigo a seguir é um exemplo simples de um tipo CVAR que envolve um intvalor:

// 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;

Acesso global:
no exemplo acima, assumi que o construtor de CVarsempre registra a variável no cvarsmapa global ; isso é bastante útil, pois permite que você declare uma variável assim:

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

Essa variável é disponibilizada automaticamente no mapa global e você pode acessá-la de qualquer outro lugar indexando o mapa com o nome da variável:

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

Persistência:
Quando o jogo está sendo encerrado, itere o mapa e salve todas as variáveis ​​marcadas como CVAR_PERSISTENT, em um arquivo. Na próxima vez que o jogo começar, recarregue-os.

Jurisprudência:
Para obter um exemplo mais específico de um sistema CVAR robusto, confira a implementação apresentada no Doom 3 .

glampert
fonte
4

Bem, primeiro, uma enumeração define quais podem ser os valores , não quais são . Portanto, você ainda precisa declarar outra variável depois de declarar o enum. Por exemplo:

public enum Sound
{
    ON,
    QUIET,
    OFF
}

public Sound soundValue;

Neste exemplo, agora você pode definir soundValueON, QUIET ou OFF.


Em seguida, você ainda precisará estruturar seu código para que outras partes do código possam acessar esse objeto "configurações". Não sei se você também precisa de ajuda com essa parte, mas os padrões comuns para resolver esse problema incluem singletons (aqueles que são mal vistos hoje em dia) ou localizadores de serviço ou injeção de dependência.

jhocking
fonte
1

A solução glampert é muito completa, mas adicionarei minha experiência pessoal.

Encontrei esse mesmo problema e minha solução foi usar uma classe estática de variáveis.

A classe Variables internamente mantém um mapa de string para string (até agora todas as minhas variáveis ​​são apenas strings) e é acessada por meio de getters e setters.

O ponto é que o acesso a variáveis ​​globais pode introduzir todo tipo de erros sutis, pois partes totalmente não relacionadas do código interferem repentinamente.

Para evitar isso, impus a seguinte semântica: o uso do setmétodo lança uma exceção se uma variável com esse nome já existir no dicionário e getexclui a variável do dicionário antes de devolvê-lo.

Dois métodos adicionais fornecem o que você esperaria, setAndOverwritee getAndKeep. O objetivo da semântica dos outros métodos é que você pode identificar facilmente erros do tipo "esse método deve inicializar essa variável, mas outro método já o fez antes".

Para inicializar o dicionário, as variáveis ​​iniciais são armazenadas em um arquivo json e lidas quando o jogo é iniciado.

Infelizmente, ainda não me afastei muito do jogo, portanto não posso testemunhar a robustez dessa abordagem. Ainda assim, talvez possa fornecer algo interessante sobre os CVARs.

angarg12
fonte