キーボード入力システムの取り扱い


13

注:API制限(SFML)のためにコールバックを行うのではなく、ポーリングする必要があります。「まともな」タイトルがないこともおizeび申し上げます。

ここで2つの質問があると思います。受け取った入力を登録する方法と、それをどうするか。

入力の処理

たとえば、「A」キーが押されたことを登録したという事実と、そこからそれを行う方法について話します。

私は次のようなキーボード全体の配列を見てきました:

bool keyboard[256]; //And each input loop check the state of every key on the keyboard

しかし、これは非効率的です。たとえば、「A」キーを「左に移動するプレーヤー」に結合するだけでなく、毎秒30〜60回すべてのキーをチェックします。

次に、必要なキーを探すだけの別のシステムを試しました。

std::map< unsigned char, Key> keyMap; //Key stores the keycode, and whether it's been pressed. Then, I declare a load of const unsigned char called 'Quit' or 'PlayerLeft'.
input->BindKey(Keys::PlayerLeft, KeyCode::A); //so now you can check if PlayerLeft, rather than if A.

ただし、これに関する問題は、たとえば、すべてのキーをバインドすることなく、名前を入力できないことです。

次に、2番目の問題がありますが、次の問題の良い解決策を考えることはできません。

入力を送信する

これで、Aキーが押されたか、playerLeftがtrueであることがわかりました。しかし、ここからどうやって行くのですか?

if(input->IsKeyDown(Key::PlayerLeft) { player.MoveLeft(); }
これをチェックすることで、入力がエンティティに大きく結合されることを考えました が、かなり面倒です。プレーヤーは、更新されたときに独自の動きを処理することを好みます。ある種のイベントシステムが機能すると思っていましたが、どうすればよいかわかりません。(信号とスロットはこの種の作業に適していると聞きましたが、明らかに非常に遅く、どのように適合するかわかりません)。

ありがとう。

回答:


7

オブザーバーパターンを使用し、コールバックまたは入力処理オブジェクトのリストを保持する入力クラスを作成します。他のオブジェクトは、特定のことが発生したときに通知されるように、入力システムに自分自身を登録できます。オブザーバーに通知する入力イベントのタイプに基づいて、登録できるコールバックにはさまざまなタイプがあります。これは、「キーxがダウン/アップ」と同じくらい低いレベルであるか、「ジャンプ/シューティング/移動イベントが発生した」などのゲーム固有のものです。

通常、ゲームオブジェクトには、入力クラスに自身を登録し、関心のあるイベントを処理するメソッドを提供する入力処理コンポーネントがあります。移動には、move(x、y)メソッドを持つ入力ムーバーコンポーネントがあります。入力システムに自身を登録し、移動イベント(xとyが-1と0で左に移動することを通知する)が通知されると、ムーバーコンポーネントは移動方向とオブジェクト速度に基づいて親ゲームオブジェクトの座標を変更します。

これが良い解決策かどうかはわかりませんが、今のところうまくいきます。特に、同じ論理的なゲームイベントにマップするさまざまな種類の入力システムを提供して、たとえばゲームパッドボタンxとキーボードスペースの両方がジャンプイベントを生成できるようにします(それよりも少し複雑で、ユーザーがキーを再割り当てできます)マッピング)。


これは間違いなく私に興味があります。入力コンポーネントは、特定のイベント(playerInputが「左」、「右」などを登録するようなもの)に対してそれ自体を登録しますか、または登録されているすべての入力コンポーネントがすべてのメッセージを受信しますか?
共産主義のカモ

それは本当にあなたの要件とそれをどのように実装したいかによって異なります。私の場合、リスナーは特定のイベントに自分自身を登録し、適切な入力ハンドラーインターフェイスを実装します。すべての入力コンポーネントがすべてのメッセージを受け取るようにする必要がありますが、メッセージ形式は私が持っているものよりも汎用的である必要があります。
フィラスアサアド

5

OPの議論は多くのことをひとまとめにしており、問題を少し分割することで大幅に簡素化できると思います。

私のおすすめ:

キーの配列を保持します。キーボード全体の状態を一度に取得するAPI呼び出しはありませんか?(私の作業のほとんどはコンソールで、接続されたコントローラーのWindowsでも、コントローラー全体の状態を一度に取得します。)キーの状態は、キーボードのキーの「ハード」マップです。未翻訳が最適ですが、APIから最も簡単に取得できます。

次に、キーがこのフレームを上回ったかどうかを示すいくつかの並列配列、キーが下がったことを示す別の配列、およびキーが「ダウン」したことを示す3つ目の配列を保持します。キーが現在の状態になっている時間を追跡できるように、タイマーをスローすることもできます。

次に、アクションへのキーのマッピングを作成するメソッドを作成します。これを数回行うとよいでしょう。UIスタッフ用に1回(および「A」を押したときにスキャンコードがユーザーのコンピューターにAを与えると想定できないため、Windowsマッピングを照会するように注意してください)。ゲーム内の「モード」ごとにもう1つ。これらは、キーコードとアクションのマッピングです。これはいくつかの方法で行うことができます。1つは受信側システムで使用される列挙型を保持する方法、もう1つは状態変更時に呼び出される関数を示す関数ポインターです。目標とニーズに応じて、2つのハイブリッドを組み合わせることもできます。これらの「モード」を使用すると、それらをコントローラモードスタックにプッシュおよびポップすることができます。フラグを使用すると、無視された入力がスタックなどを下に移動し続けることができます。

最後に、これらの重要なアクションを何らかの方法で処理します。動きについては、「W」を「前進」を意味するように変換しますが、バイナリソリューションである必要はありません。「W is down」は「最大Yまで速度をX増加」、「W is up」は「ゼロに達するまでZ速度を減少」することを意味します。一般的に言えば、「ゲームシステムのコントローラー処理インターフェイス」をかなり狭くする必要があります。すべての主要な翻訳を1か所で行い、その結果を他のすべての場所で使用します。これは、スペースバーがコード内の任意の場所でランダムに押されているかどうかを直接確認するのとは対照的です。それに対処したい...

私はパターンに合わせた設計を本当に嫌っていますし、コンポーネントは良いものよりも開発コストをもたらすと思うので、私はどちらにも言及しませんでした。コンポーネントがそうであるように、それらが運命づけられている場合、パターンは現れますが、最初からどちらかを行うように設定することはあなたの人生を複雑にするだけです。


イベントをグラフィックフレームにバインドするのはちょっと汚いと思いませんか?それは分離すべきだと思います。
ジョーSo

つまり、ほとんどすべての場合、プレーヤーはグラフィックカードがフレームを出力するよりもボタンの入力が遅くなりますが、実際には独立している必要があります。実際、ネットワークから収集されたイベントなど、 。
ジョーSo

確かに; キーボード(または他の入力デバイス)のポーリングがディスプレイと異なるレートで実行できない理由はありません。実際、100Hzで入力をポーリングすると、ビデオハードウェアの更新頻度に関係なく、非常に一貫したユーザーコントロールエクスペリエンスを提供できます。データの処理方法(ラッチなど)についてもう少し賢くする必要がありますが、ジェスチャなどの方法で一貫性を簡単にすることができます。
ダッシュトムバン

3

SFMLでは、KeyPressedイベントタイプで押された順にキーがあります。各キーをwhile(getNextEvent())で処理します。

したがって、押されたキーがKey-> Actionマップにある場合、対応するアクションを実行し、そうでない場合、それを必要とする可能性のあるウィジェット/ものに転送します。

2番目の質問については、ゲームプレイを微調整しやすくなるため、このように保つことをお勧めします。シグナルなどを使用する場合は、「RunKeyDown」用のスロットと「JumpKeySlot」用のスロットを作成する必要があります。しかし、ゲーム内で両方が押されたときに特別なアクションが実行されるとどうなりますか?

入力とエンティティを無相関化する場合は、入力をState(RunKey = true、FireKey = false、...)にして、他のイベントをAIに送信するようにプレーヤーに送信できます。


それはリアルタイム検出IIRCであるため、sf :: Eventではなくsf :: Inputでキーボードイベントを処理していません。できるだけAPIに依存しないようにしました。:P(質問、つまり)
共産主義のダック

1
しかし、Calvin1602が指摘している点は、「APIの制限(SFML)のためにコールバックを行うのではなく、ポーリングする必要がある」という質問の元のステートメントは真実ではないということです。イベントがあるので、イベントを処理するときにコールバックを発行できます。
キロタン

3

多くの場合、正しい解決策は、次の2つの方法の組み合わせです。

事前定義されたキーのセットを使用したゲームプレイ機能では、すべてのフレームのポーリングが完全に適切であり、実際に何かにバインドされているキーのみをポーリングする必要があります。これは、実際にコンソールゲームでコントローラー入力を照会する方法に似ています。特にアナログ入力デバイスに関しては、完全にポーリングされます。一般的なゲームプレイ中は、おそらくキー押下イベントを無視して、ポーリングを使用するだけです。

名前などの入力を入力する場合は、ゲームを別の入力処理モードに切り替える必要があります。たとえば、「名前を入力してください」というプロンプトが表示されたら、入力コードの動作を変更できます。コールバックインターフェイスを介してキープレスイベントをリッスンするか、必要に応じて各キーのポーリングを開始できます。通常、イベントの入力中はパフォーマンスにあまり関心がないため、ポーリングはそれほど悪くないことがわかります。

そのため、ゲームプレイ入力には選択的ポーリングを使用し、名前入力入力にはイベント処理を使用します(イベント処理が利用できない場合はすべてのキーボードポーリング)。


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