再起動せずにオプション画面からディスプレイ設定を更新するにはどうすればよいですか?


9

私は現在、Allegro 5とboostを使用してC ++ 11で2D RPGを作成しています。

私の目標は、オプションメニューでオプションが変更されたときにゲームの設定を更新することです。ユーザーに強制的にゲームを再開させたくありません。他のゲームでは、解像度を変更したり、フルスクリーンからウィンドウ表示にしたりするときに再起動を必要としないため、私のゲームもそうではありません。以下のシステムの簡略図をご覧ください。

OptionsScreenからゲームオブジェクトを直接呼び出す必要がないことに注意してください。破線は、私が達成しようとしている効果を示すためのものです。システムの別の部分でオプションが変更されたときに、どういうわけかゲームを更新します。

詳細説明

ScreenManagerには、GameScreen現在存在するすべてのオブジェクトのリストが含まれています。これらは、ポップアップを含むゲーム内のさまざまな画面になります。この設計は、多かれ少なかれC#/ XNAゲーム状態管理サンプルに準拠しています。

ScreenManagerは、私のGameオブジェクトへの参照が含まれています。Gameオブジェクトは、ゲームの設定を初期化し、変更します。解像度を変更したい場合は、フルスクリーンにするか、Gameクラスで行うボリュームをミュートにします。

ただし、現在、OptionsScreenはGameクラスにアクセスできません。以下の図を参照してください。

GameScreenはonFinishedonTransitionStartおよびの3つのイベントを通知できonTransitionEndます。onOptionsChanged1つの画面だけがそれを行うため、ありません。ScreenManagerはすべての画面をGameScreens として処理するため、そのためのイベント処理を設定できません。

私の質問は、OptionsMenuの変更が再起動を必要とせずにすぐに変更されるように、どのようにデザインを変更できるかです。Game適用ボタンがクリックされたら、オブジェクトの更新をリクエストするのが望ましいでしょう。


この質問は、(それがゲーム関連しているにもかかわらず)のための完璧なフィットのように見えるprogrammers.stackexchange.comそれはより一般的なオブジェクト指向設計について実際のゲーム約だから
bughi

あなたはそのような素晴らしいグラフをどこで手に入れましたか?
joltmode 2013年

@psycketom:1つ目はVisio 2013から、2つ目はVS2012のコードから生成されます。お役に立てば幸いです。
IAE

回答:


1

私が見たことから、最も簡単な方法は、起動時にオプションファイルを読み取って現在のディスプレイ設定を決定することです。次に、オプション画面が表示されたら、現在のオプションをすべてファイルからロードします。

applyまたはokボタンを介して変更が確定されると、ファイルに保存されます。変更が表示に影響する場合は、変更を有効にするにはゲームを再起動する必要があることをユーザーに通知します。

ゲームを再起動すると、(今は新しい)ディスプレイ設定がファイルから再度読み取られます。

-編集-

最後に...私がその最後の文に気づいたら、助けになったでしょう。再起動する必要はありません。実装とバックエンドのグラフィックライブラリによっては、処理が少し難しくなります。

IIRC、Allegroには、オンザフライでディスプレイ設定を変更できる関数呼び出しがあります。私はまだAllegro 5に精通していませんが、4でできることは知っています。


この問題はAllegroとその機能に関連しているとは思いません。「私の質問は、OptionsMenuの変更で再起動が不要で、すぐに変更されるように設計を変更するにはどうすればよいですか?」再起動の理由は、「OptionsScreenは現在Gameクラスにアクセスできない」ためです。正しく理解した場合、設定ファイルからそれらをロードする必要があります。
ClassicThunder 2013年

@Casey:こんにちはケーシー!:)はい、関連する表示データを保存するために構成ファイルを使用していますが、再起動を回避できるようにしたいと考えています。これは小さなゲームであり、他のゲームは再起動せずに解像度を変更できるため、ユーザーに強制的に再起動する必要がある理由がわかりません。それはユーザビリティの問題です。allegroディスペイ関数を呼び出すことはできましたが、OOPを維持し、できる限りグラフィックスの呼び出しを混在させないようにしています。良いデザインだとは思いません。
IAE、2013年

他の人が同じ最後の文でつまずかないように、「再起動なし」のビットを強調表示しました。そのような重要な事実は最後に来るべきではなかったと私はお詫びします):
IAE 2013年

あなたが言う@SoulBeaver しなければならないあなたが再起動しないようにそれを作りますか?それを要求することは現実的なことであり、実際、今日ではより一般的になっています。大きな予算のゲームの最近のいくつかのリリース(XCOM:Enemy Unknown、Skyrimなど)は、再起動が必要です。(それらがSteam上にあるという事実は、サーバー側でのオプションの同期のために犯人かもしれませんが、そこに行かないでください...)
Casey

1
@Casey:確かに、特定のオプションではなぜそれが必要なのかがわかりますが、フルスクリーン/ウィンドウや画面解像度などの場合はどうでしょうか。これらの設定を再起動する必要があるゲームを見たことがありません。私の基本的な質問は、ゲームが設定を自動的に変更できるのに、なぜユーザーに再起動を強制する必要があるのですか?
IAE、2013年

1

これが私のゲームで行うことです。ものを初期化するための2つの別々の関数、「init」と「reset」があります。Initは起動時に1回だけ呼び出され、メインアセットの読み込みなど、設定に依存しない処理を実行します。リセットは、画面解像度に基づいてUIをレイアウトするなどの処理を行うため、設定が変更されるたびに呼び出されます。

init();
bool quit = false;
while( !quit )
{
    createWindow();
    reset();

    bool settings_changed = false;
    while( !quit && !settings_changed )
    {
        ... main loop
        // set quit=true if user clicks 'quit' in main menu
        // set settings_changed=true if user clicks 'apply' in options
    }

    destroyCurrentWindow();
}

私はAllegroに精通していませんが、私の答えは非常に一般的であるため、同様の問題を抱えているあなたや他の人に役立つことを願っています。


それは興味深い解決策です。リセットが呼び出されたときはいつでも厳密に制御するようにしましたが、変更に関係なくそれを行います。それは間違いなく私が実装できるものであり、私はそれを調査します、ありがとう!
IAE 2013年

1

現在のアーキテクチャを混乱させることなく、私は2つの方法を考えています。まず、GameインスタンスへのポインタをOptionsScreenクラスに格納できます。次に、Gameクラスが現在の設定を指定された間隔で、たとえば毎秒フェッチできるようにします。

新しい設定に実際に適応するには、Gameクラスは、現在の設定をフェッチし、それらに基づいて再初期化する何らかのリセット関数を実装する必要があります。

クリーンなソリューションを実現するには、何らかのグローバルマネージャーが必要です。そのため、実装するのはより困難です。たとえば、イベントシステムやメッセージングシステム。集約や合成などの強力なバインディングなしでクラスが通信できるようにすることは非常に便利です。

グローバルイベントマネージャーを使用すると、OptionsScreenGame以前にリッスンするように登録された再描画イベントをグローバルに起動できます。

一般に、イベントを格納するマネージャークラスと、それらをリッスンするコールバックをハッシュマップに実装できます。次に、そのマネージャーの単一のインスタンスを作成し、そのインスタンスへのポインターをコンポーネントに渡すことができます。新しいC ++を使用するとstd::unordered_map、ハッシュマップとして使用したりstd::function、コールバックを格納したりできるため、非常に簡単です。キーとして使用できる方法はいくつかあります。たとえば、イベントマネージャーを文字列ベースにして、コンポーネントをさらに独立させることができます。その場合std::stringは、ハッシュマップのキーとして使用します。私は個人的にこれが好きで、それは明らかにパフォーマンスの問題ではありませんが、ほとんどの従来のイベントシステムはイベントをクラスとして扱います。


ダニジャーこんにちは。すでにboost :: signalsを使用して、基本的なイベント処理スキームを設定しています。GameScreenからScreenManagerへの強力な線は、実際にはそのイベント処理です。グローバルイベントマネージャーのアーキテクチャを詳しく説明しているリソースはありますか?作業が増えるかどうかにかかわらず、これはクリーンな実装につながる可能性があるようです。
IAE、2013年

これに関する調査はまだ読んでいませんが、自分の小さなエンジンにグローバルイベントイベントマネージャーを実装しました。実装に興味があれば、リンクをお送りします。回答を更新して詳細を説明しました。
danijar 2013年

1

これは、Observerパターンの特定のケースです。

コールバックを含むソリューションがあります。これは、疎結合が必要な場合に最適な方法であり、最もクリーンな方法だと思います。これには、グローバルマネージャーやシングルトンは含まれません。

基本的には、ある種のが必要になりますSettingsStore。そこで設定を保存します。新しい画面を作成するときは、ストアへのポインターが必要です。の場合OptionsScreen、設定値自体の一部が変更されます。の場合はGameScreenそれを読むだけです。そのため、ゲームではインスタンスを1つだけ作成し、それを必要とするすべての画面に渡されます。

これで、そのSettingsStoreクラスにはのリストが含まれnotifiablesます。これらは、特定のISettingChangedインターフェースを実装するクラスです。インターフェースは、次のメソッドを含む単純なインターフェースになります。

void settingChanged(std::string setting);

次に、画面に、気になる各設定のロジックを実装します。次に、通知を受けるために自分をストアに追加しますstore->notifyOnChange(this);。設定が変更されると、コールバックは設定名で呼び出されます。その後、新しい設定値をから取得できますSettingsStore

これは、次のアイデアでさらに拡張できます。

  • 設定文字列を格納するクラスを使用しますSettingsStore。文字列のコピーアンドペーストを防ぐために、(const文字列)にすることもできます。
  • さらに良いのは、文字列の代わりに、列挙型を使用して、設定を指定することです
  • コールバックの引数として古い値と新しい値を指定することもできますが、文字列やintの値などを含めることができるため、より複雑になります。それはあなた次第です。

0

設定をファイルから変数に読み込みます。元の画面がオプション画面だったかどうかをスクリーンマネージャーに追跡させ、そうであった場合は変数から設定を再読み込みします。ユーザーがゲームを終了したら、変数の設定をファイルに書き戻します。

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