大規模ゲームの入力管理手法


16

大規模なゲームで入力を管理するための標準的な手法はありますか。現在、私のプロジェクトでは、すべての入力処理は次のようにゲームループで行われます。

while(SDL_PollEvent(&event)){
            switch(event.type){
                case SDL_QUIT:
                    exit = 1;
                    break;
                case SDL_KEYDOWN:
                    switch(event.key.keysym.sym){
                        case SDLK_c:
                            //do stuff
                            break;
                    }
                    break;
                case SDL_MOUSEBUTTONDOWN:
                    switch(event.button.button){
                        case SDL_BUTTON_MIDDLE:
                                //do stuff
                                break;
                            }
                    }
                    break;
            }

(私はSDLを使用していますが、メインプラクティスではライブラリとフレームワークも適用されると考えています)。大規模なプロジェクトでは、これは最善の解決策ではないようです。ユーザーが何を押したかを知りたいオブジェクトがいくつかある場合があるため、それらのオブジェクトが入力を処理する方が理にかなっています。ただし、イベントを取得すると、イベントバッファからプッシュされるため、別のオブジェクトがその入力を受け取らないため、すべてが入力を処理することはできません。これに対抗するために最も一般的に使用される方法は何ですか?


イベントマネージャーを使用すると、入力でイベントを発生させ、ゲームの他のすべての部分を登録できます。
ダニジャー

@danijarイベントマネージャーとは正確に何を意味しますか。スケルトンの擬似コードを提供して、どのようなことを話しているのかを示すことができれば可能ですか?
w4etwetewtwet


1
イベントマネージャーについて詳しく説明する回答を書きました。これは、入力処理を行う方法です。
ダニジャー

回答:


12

スレッドスターターからの質問を受けて、イベントマネージャーについて詳しく説明します。これはゲームの入力を処理する良い方法だと思います。

イベントマネージャは、キーにコールバック関数を登録し、それらのコールバックを起動することを可能にするグローバルクラスです。イベントマネージャは、登録された関数をキーでグループ化されたプライベートリストに保存します。キーが発生するたびに、登録されているすべてのコールバックが実行されます。

コールバックは、std::functionラムダを保持できるオブジェクトにすることができます。キーは文字列にすることができます。マネージャーはグローバルであるため、アプリケーションのコンポーネントは他のコンポーネントから起動されたキーに登録できます。

// in character controller
// at initialization time
Events->Register("Jump", [=]{
    // perform the movement
});

// in input controller
// inside the game loop
// note that I took the code structure from the question
case SDL_KEYDOWN:
    switch(event.key.keysym.sym) {
    case SDLK_c:
        Events->Fire("Jump");
        break;
    }
    break;

このイベントマネージャーを拡張して、追加の引数として値を渡すこともできます。これにはC ++テンプレートが最適です。このようなシステムを使用して、たとえば、"WindowResize"イベントが新しいウィンドウサイズを渡すため、リスニングコンポーネントがそれ自体をフェッチする必要はありません。これにより、コードの依存関係をかなり減らすことができます。

Events->Register<int>("LevelUp", [=](int NewLevel){ ... });

私は自分のゲームにそのようなイベントマネージャーを実装しました。興味がある場合は、コードへのリンクをここに投稿します。

イベントマネージャを使用すると、アプリケーション内で入力情報を簡単にブロードキャストできます。さらに、これにより、ユーザーがキーの割り当てをカスタマイズできるようになります。コンポーネントは、キーの"PlayerJump"代わりに(ではなく"KeyPressedSpace")セマンティックイベントをリッスンします。次に"KeyPressedSpace"、ユーザーがそのキーにバインドしたアクションをリッスンしてトリガーする入力マッピングコンポーネントを使用できます。


4
すばらしい回答、ありがとう。コードを見たいのですが、コピーしたくないので、自分で実装するまで投稿しないでください。詳細についてはこちらをご覧ください。
w4etwetewtwet

私はちょうど私がこのような任意のメンバ関数を渡すことができ、何かを考え、またはレジスタの機能は、1クラスのメンバ関数にそれを制限し、AClassは:: FUNCを取る必要はありません
w4etwetewtwet

これはC ++のラムダ式の素晴らしいところです。キャプチャ句[=]を指定すると、ラムダからアクセスされるすべてのローカル変数への参照がコピーされます。したがって、thisポインターまたはこのようなものを渡す必要はありません。ただし、古いC関数ポインタには、キャプチャ句を使用してラムダを格納できないことに注意してください。ただし、C ++ std::functionは正常に動作します。
ダニジャー

std :: functionは非常に遅い
TheStatehz

22

これをいくつかのレイヤーに分割します。

最下層には、OSからの生の入力イベントがあります。SDLキーボード入力、マウス入力、ジョイスティック入力など。複数のプラットフォームがある場合があります(SDLは、たとえば、後で気になるかもしれないいくつかの入力フォームを持たない最小公分母です)。

これらを「キーボードボタンダウン」などの非常に低レベルのカスタムイベントタイプで抽象化できます。プラットフォームレイヤー(SDLゲームループ)が入力を受け取ると、これらの低レベルイベントを作成し、入力マネージャーに転送する必要があります。シンプルなメソッド呼び出し、コールバック関数、複雑なイベントシステムなど、好きなものを使用してこれらを実行できます。

入力システムには、低レベルの入力を高レベルの論理イベントに変換する仕事があります。ゲームのロジックは、スペースが押されたことをまったく気にしません。JUMPが押されたことを気にします。入力マネージャーの仕事は、これらの低レベルの入力イベントを収集し、高レベルの入力イベントを生成することです。スペースバーと「A」ゲームパッドボタンの両方が論理コマンドJumpにマップされていることを認識する必要があります。ゲームパッドとマウスの外観のコントロールなどを扱います。低レベルのコントロールから可能な限り抽象的な高レベルの論理イベントを発行します(ここにはいくつかの制限がありますが、一般的な場合は完全に抽象化できます)。

キャラクターコントローラーはこれらのイベントを受け取り、これらの高レベル入力イベントを処理して実際に応答します。プラットフォームレイヤーは、イベント「キーダウンスペースバー」を送信しました。入力システムはそれを受信し、そのマッピングテーブル/ロジックを確認し、イベント「Pressed jump。」を送信します。ゲームロジック/キャラクターコントローラーはそのイベントを受信し、プレーヤーが実際にジャンプを許可されていることを確認してから、「プレーヤージャンプ」イベントを発行します(または直接ジャンプを発生させます)。 。

ゲームロジックに依存するものはすべてプレーヤーコントローラーに送られます。OSに依存するものはすべてプラットフォーム層に入ります。残りはすべて入力管理層に送られます。

これを説明するアマチュア風のASCIIアートを次に示します。

-----------------------------------------------------------------------
Platform Abstraction | Collect and forward OS input events
-----------------------------------------------------------------------
                          | |
                          | |
                         \   /
                          \_/
-----------------------------------------------------------------------
    Input Manager    | Translate OS input events into logical events
-----------------------------------------------------------------------
                          | |
                          | |
                         \   /
                          \_/
-----------------------------------------------------------------------
Character Controller | React to logical events and affect game play
-----------------------------------------------------------------------
                          | |
                          | |
                         \   /
                          \_/
-----------------------------------------------------------------------
      Game Logic     | React to player actions and provides feedback
-----------------------------------------------------------------------

クールなASCIIアートですが、それほど必要ではありません。すみません。代わりに番号付きリストを使用することをお勧めします。とにかく良い答えです!
ダニジャー

1
@danijar:ええ、私は実験していましたが、これまでに答えを出そうとしていませんでした。それは価値があったよりも多くの仕事ですが、ペイントプログラムを扱うよりもはるかに少ない仕事。:)
ショーン・ミドルディッチ

わかりました、わかりやすい:
danijar

8
個人的には、退屈な番号付きリストよりもASCIIアートの方が好きです。
ジェシーエモンド

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