2011-12-04 3 views
4

私は現在C++ゲームを作っています。 ロジックが計算されている間にメインループがあり、スプライトなどが描画されます。 NPCの前でタッチを押すとダイアログウィンドウが画面が表示され、キーを押すまでフリーズしますが、ゲームは実行され続けます(他の文字は動いているなど)ので、メインループはまだ実行されています。 私はうまくそれを行うために管理:今、問題が来るモードレスダイアログウィンドウに適したデザインは何ですか?

object::OnActivated() { 
GameManager::doWindow("some text"); 
//the game is not blocked here, the game continues to run normally and will display a window on the next frame 
} 

:オブジェクトがアクティブになったとき、それはゲームが稼働し続けながら、テキストウィンドウを表示するダイアログ・マネージャにメッセージを送信し、それは次のようになりますダイアログが終了した後に、または例えば質問に対して「はい」を選択した場合に、何らかの関連付けアクションが発生するようにする場合です。私はこのような仕事したいの実装を持っているしたいと思います:

object::OnActivated() { 
GameManager::doWindow("some text"); 
if(GameManager::Accepted()) addGold(100); 
} 

問題は、このチェック&行動は、すぐにウィンドウイベントが作成されるように実行、NOTウィンドウが閉じられたときに/ aceptedされるということです。 OnActivated()関数に関連付けられたアクションを維持しながら、これを行うための方法はありますか?関数ポインタを使用せずにこれを正しく行う方法は知られていないので、結果として使用できるすべてのメソッドに対して特定のシグネチャを持つ必要があります。 ありがとう

編集:私はこの問題に対する最も「正式な」答えが何であるか知りたいので奨励金を出しました。私はこれが非常に一般的な問題だと思っています(多くのアプリケーションとすべての現代ゲーム)、 と私は可能な限り柔軟な解決策を持っていきたいと思います。ダイアログが起動する可能性があります。 詳細: - 各ダイアログは、共通の「エンティティ」クラスから派生したオブジェクトによってトリガーされます - 同じクラスの異なるオブジェクトは、ほとんど常に、それらに関連付けられた異なるダイアログ/アクションを持ちます(たとえば、NPCのオブジェクトはすべて - "ダイアログロジック"をOnActivatedメソッドから外したり、Entityクラスの外に移動したりすることは気にしません。とにかく、NPCごとに「ランダム」なダイアログシナリオを追加したいので、ダイアログなどは別の場所に保存されます。 - しかし、ダイアログロジック自体を可能な限り近くに保ちたい単一のダイアログ。理想的には、私は "result = dialogWindow(" question? "); if(result){...}"のようにすることができるようにしたいと思います。私はそれが可能だとは確信していません

+0

これはGameDev.SEに属していますが、私は移動のためにそれをフラグしました。 – Xeo

+1

@ Xeo:そうですね。彼は単にモードレスのダイアログウィンドウに相当するものを作りたいと思っていますが、それはゲームのためのものではありません。 – Jon

答えて

1

Command Patternは、後で実行されるコードをカプセル化するために使用されます。

object::OnActivated()関数では、適切なコマンドオブジェクトが作成され、後で見つかるように格納されます。ユーザーが「はい/いいえ」を選択すると、特定のコマンドオブジェクトが何か起こっているかを知る必要のないコードを実行して、コマンドを実行することができます。

ここで「金を追加」コマンドオブジェクトの例です:

class DialogResponseCommand 
{ 
public: 
    virtual run() = 0; 
}; 

class AddGoldCommand : public DialogResponseCommand 
{ 
public: 
    AddGoldCommand(int amount) : amount(amount) {} 
    virtual run() 
    { 
    if(GameManager::Accepted()) 
     addGold(amount); 
    } 

private: 
    int amount; 
}; 

、今後のコマンドのためのいくつかのストレージ与えられた:あなたはあなたのOnActivated()コマンドを作成してもらうことができ

shared_ptr<DialogResponseCommand> dialog_command; 

を:

object::OnActivated() { 
    GameManager::doWindow("some text"); 
    dialog_command = make_shared<AddGoldCommand>(100); 
} 

ユーザーが最後に選択したとき:

dialog_command->run(); 
+0

(これは私が解決しようとしているかなり一般的な問題であるため)私は既存の実績のあるデザインパターンを探していたので、みんなありがとう – lezebulon

2

必要なものに基づいていくつかの事前定義されたアクションを行うイベントクラスを作成できます。これは、EVENT_ADD_GOLDのようなenum値を保持するインスタンス変数を持ちます。また、インスタンス変数をチェックして適切なアクションを実行するPerform関数もあります。必要に応じて他のアクションを追加することができます。

これについては、タイプごとに1つのインスタンス変数のみが必要です。例えば、valueは、金の量または損傷を意味する可能性があります。意味はイベントタイプによって決まります。

「これ以上ダイアログを表示する必要はありません!」というコードでは、 EventオブジェクトのPerformメソッドを呼び出すことができます。この目的のために一度に複数のイベントを持つのは意味がないので、参照を保持するために1つのインスタンス変数を作ることができます。

+0

これは私が実装する可能性が最も高い解決策ですが、これはダイアログでトリガーできる「アクション」ごとに別個のイベントタイプを作成する必要があることを意味し、「ジェネリック」で引数を渡すことはできないと思います"way(つまり、いくつかのイベントは2つのintを必要とし、いくつかはオブジェクトへの参照などが必要です) – lezebulon

+0

コンストラクタをオーバーロードする可能性があります。 ([このページの下半分はコンストラクタのオーバーロードのために)(http://www.cplusplus.com/doc/tutorial/classes/) – FakeRainBrigand

3

プラットフォームが指定されていない(またはタグ付けされていない)ので、具体的な答えを出すのは難しいので、一般的な答えを書きます。

あなたの質問への答え:

は「OnActivated()関数に関連付けられたアクションを維持しながら、これを行うにはどのような方法は、ありますか?」

おそらく"いいえ"です。

あなたが説明した問題を解決するために試して真のパターンのファミリーがあります。このパターンファミリは、さまざまなModel-View-XXXパターン(MVC、MVP、Document-Viewなど)です。 これらのパターンの基本的な前提は、現在の状態をカプセル化する構造体、通常はオブジェクトのグラフです(モデル)と、この状態をユーザに表示するユーザインタフェース要素(ビュー)のセットとを含む。 モデルが変更されるたびに、ビューは新しい状態に合わせて変更されます。モデルがどのように変化し、ビューが更新されるかの詳細は、ファミリの異なるパターンを設定し、どのパターンを使用するかは、特定のシステムで入力がどのように処理されるかによって異なります。 MVCは、インターネットアプリケーションや、ループに基づいた多くのゲームに適しています。ユーザー入力には、システムへの単一の入力ポイントがあるためです。 MVP、DV、MVVM(MVPと同じ)は、入力がGUIのアクティブなコントロールに移動するデスクトップアプリケーションに適しています。

これらのパターンを使用することの欠点は、ビューを作成するためのコードに関連するアクションのコードが続くことはめったにないことですが、利点はこの欠点をはるかに上回ります。

あなたのモデルには、ダイアログテキストのプロパティと現在の入力ハンドラ(状態パターン)を格納するプロパティが必要です。 あなたのメインループは、次の操作を行います:

  1. いかなる場合(例えば、ユーザのスプライトの位置を変更する)、ユーザの入力に基づいてモデルを更新するために、現在の入力ハンドラを取得します。
  2. 残りのモデルを更新して、ゲーム内の他の要素を反映させます。
  3. 更新現在のモデル

に基づくUIは、NPCの前に利用者プレスは、デフォルトの入力ハンドラの変更は特定ダイアログの入力を処理するときにトリガされ、ためジェネリックビューダイアログがテキストをユーザーに表示します。

ユーザがダイアログ内でアクションを選択すると、ハンドラはデフォルトの入力ハンドラに戻り、ダイアログのプロパティが空に戻ります。

手順1と2はMVCパターンのコントローラを構成し、手順3はイベントドリブンでないビュー更新です。逆にObservable-Observerパターンを使用し、それに応じて変化するビューによって観察されるモデルスローイベントを持たせることができます。

+0

MVCの説明に感謝しますが、 )ダイアログが閉じられると、私は "ジェネリック"イベントを引き起こすことができます – lezebulon

1

あなたがここで欠けているものはコールバックだと思います。問題の解決策は、onActivatedメソッドでコールバックを提供することです。ダイアログマネージャは、モードレスダイアログが受け入れられたときにこのコールバック関数またはメソッドを呼び出します。これは、必要な動作を実行できる場所です。

あなたはゲームについての詳細を提供していないので、これを解決するための決定的な方法は実際にはありません。任意のオブジェクトに対して常に同じアクションが必要な場合は、単にメソッドOnAcceptedを提供することができます。このような何か:

object::OnActivated() { 
    GameManager::doWindow(this, "some text"); // note I'm passing the object to the dialog manager 
} 

// the dialog manager calls this when the dialog box is accepted 
void object::OnAccepted() { 
    addGold(100); 
} 

以上がOnAccepted方法は、基本クラスの仮想関数として宣言することができるようにオブジェクトを表すすべてのクラスは、同じ階層に属していることを前提としています。

これはあまりにも単純化したアプローチですが、より精巧にすることができますが、適切な時間にコールバックをトリガーするためにダイアログマネージャが使用できるdoWindowメソッドに渡されるコールバックデータが常にあります。

非常に洗練されたものが必要で、ブーストにアクセスできるもの、またはstd::functionstd::bindを持つC++ 11の実装では、任意の引数でコールバックをサポートすることもできます。考えられるのは、doWindowに渡された引数がfunctionオブジェクトだということです。オブジェクトは通常の関数、またはあるオブジェクトの中のメソッドをラップすることができ、追加の引数がある場合は、std::bindを使用して関数オブジェクトにバインドすることができます。

0

窓やウィジェットを扱うときはいつも、the MVC,presenter firstなどの代替手段を使うのが良いでしょう。

特定の「イベント」に反応するには、コールバックを使用するか、より良い方法をthe observerboost's signal/slotを参照してください)することができます。

関連する問題