ゲーム全体の変数を保存する最良の方法


23

難易度、解像度、フルスクリーンなどのオプション画面がありますが、実行時にこれらの変数を保存/取得する「最良の」方法を見つけるのに苦労しています。

現在、私Constantsはすべてを含むクラスを実装しましたGameOption列挙型が、これらのオプションすべてのデフォルトを選択するにはどうすればよいですか?また、現在選択されている列挙型を取得するにはどうすればよいですか?

解像度に関しては、具体的には、値を保存することにしましたが、デフォルト値または現在保存されている値を取得する方法がわかりません。どの方向も素晴らしいでしょう。ありがとう!:)

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:SOで尋ねると、彼らは私にこの場所を指し示しました。そこにコメントがありますが、私はそれを行うさまざまな方法/最もよく使われる方法を聞きたいです。


1
あなたは正しい場所で尋ねました。ここにあなたを送った人は誰でも間違っていました。とにかく質問に答えましたが、これはゲーム開発特有の質問ではなく、一般的なプログラミングの質問です。
ジョーク14

SOスレッドを読みました。スコット・チェンバリンの答えが好きです。
ジョーク14

@jhocking通常のアプリケーションとは異なるかもしれないゲーム開発に特有の側面がある場合に備えて、私は彼にこのように指摘しました。また、このトピックに関する一般的なQ&Aは非常に一般的であるため、皆さんも既にお持ちかもしれないと考えました。
クリスヘイズ

グローバルについての実際の質問に接して、決まった解像度のセットがそこにあると仮定しないでください。
ラースヴィクルンド

回答:


32

成長の計画:
ハードコードされた定数は小さなプロジェクトには適していますが、最終的には、ソフトウェアのサイズが大きくなるにつれて、すべてを再コンパイルせずにこれらの設定を変更できるようになります。ゲームの実行中に設定を変更したい場合が多くありますが、ハードコードされた定数では設定を変更できません。

CVars:
プロジェクトが成長したら、CVARを調べてみてください。CVARは、いわば「スマート変数」であり、実行時にコンソール、端末、またはUIを介して変更できます。CVARは通常、基礎となる値をラップするオブジェクトの観点から実装されます。オブジェクトは、値を追跡したり、ファイルに保存したりファイルからロードしたりできます。CVARオブジェクトをマップに保存して、名前または他の一意の識別子でそれらにアクセスできます。

概念をもう少し説明するために、次の擬似コードは、int値をラップするCVAR型の簡単な例です。

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

グローバルアクセス:
上記の例では、コンストラクタがCVar常に変数をグローバルcvarsマップに登録すると仮定しました。次のように変数を宣言できるため、これは非常に便利です。

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

その変数はグローバルマップで自動的に使用可能になり、変数の名前でマップにインデックスを付けることにより、どこからでもアクセスできます。

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

永続性:
ゲームがシャットダウンしているとき、マップを繰り返し、とマークされたすべての変数をCVAR_PERSISTENTファイルに保存します。次回のゲーム開始時に、それらをリロードします。

判例法:
堅牢なCVARシステムのより具体的な例については、Doom 3で紹介されている実装をご覧ください。


4

まず、列挙型は、値何であるかではなく、値何であるかを定義します。したがって、enumを宣言した後、別の変数を宣言する必要があります。例えば:

public enum Sound
{
    ON,
    QUIET,
    OFF
}

public Sound soundValue;

この例では、soundValueON、QUIET、またはOFFに設定できるようになりました。


その後、コードの他の部分がこの「設定」オブジェクトにアクセスできるように、コードを構造化する必要があります。その部分についても支援が必要かどうかはわかりませんが、この問題に対処する一般的なパターンには、シングルトン(最近では眉をひそめている)やサービスロケーター、依存関係注入などがあります。


1

glampertソリューションは非常に完全ですが、個人的な経験を追加します。

私はこの同じ問題に遭遇し、私の解決策は静的変数クラスを使用することでした。

Variablesクラスは、文字列から文字列へのマップを内部的に保持し(これまでのところ、すべての変数は文字列のみです)、ゲッターとセッターを介してアクセスされます。

ポイントは、グローバル変数にアクセスすると、コードのまったく無関係な部分が突然干渉するため、あらゆる種類の微妙なエラーが発生する可能性があるということです。

これを避けるために、次のセマンティクスを課しました。setその名前の変数が既に辞書に存在する場合、メソッドを使用すると例外がスローされます。get返される前にその変数が辞書から削除されます。

二つの追加の方法は、あなたが期待するものを提供する、setAndOverwritegetAndKeep。他のメソッドのセマンティックのポイントは、「このメソッドはこの変数を初期化するはずですが、他のメソッドは以前にそれを行った」という種類のエラーを簡単に見つけることができるということです。

辞書を初期化するために、初期変数はjsonファイルに保存され、ゲームの開始時に読み取られます。

悲しいことに、私はまだ自分のゲームとあまり離れていないので、このアプローチの堅牢性を証明することはできません。それでも、CVARの上に何か面白いものを提供できるかもしれません。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.