投票ベースの入力のキーの組み合わせ


9

したがって、ポーリングに基づく入力システムがあると仮定します

void update()
{
    if( Keyboard[ 'A' ] )
        // A is down
}

3〜8の長さのキーの組み合わせ(ダウン、ダウンフォワード、フォワード、ハドーケンのAなど)を認識できるようにしたいとします。

ポーリングされ入力に、一般的な(簡単に変更可能/プログラム可能な)キーの組み合わせの入力システムをどのように作成するのが最善でしょうか。

回答:


7

基本的にはできません。キーの組み合わせには順序が必要であり、順序にはイベントが必要です。

あなたができることは、各フレームのキーの状態を比較し、その違いから事後のキーアップ/キーダウンイベントを生成することで、ポーリングをイベントに変えることです。「ネイティブ」イベントシステムが提供するタイムスタンプやその他のフレーム内の順序付けを失うため、信頼性は低くなりますが、フレームごとに少なくとも1つのキーを検出して順序付けすることができます。

これらの順序付けられたイベントを取得したら、有限状態マシンまたはその他のツールを使用して、それらを移動リストと照合し、正しいものを実行できます。


イベントなしでこれを行うことはできないと言うのは少し誤解を招きます。技術的には、イベントは、何らかの条件が満たされたときにメソッドまたはメソッドのリストを呼び出す方法にすぎません。その意味では、イベントが必要です。ただし、その説明に当てはまる多くのプログラミングタスクに、イベントという単語を(不適切に)適用できます。私が通常行う方法で問題を解決する回答を追加しました。これは、ほとんどのプログラマーが「イベント」と考える傾向があるものを使用しません。
Olhovsky、

2
あなたのコードは、イベントなしで私が言ったこととまったく同じですが、警告を無視します。これは、フレーム内の順序を失うことです。Win32メッセージループなどからイベントを取得すると、フレームごとのグロブよりも細かい順序でイベントが取得されます。デルタを自分で計算すると、それは失われます。プレイヤーが1つのフレームにコンボのいくつかの部分を入力する可能性がある格闘ゲームの場合、それらが順不同であるかどうかを知る必要があります。

けっこうだ。60 Hzでポーリングしている場合、60 Hzのポーリングで提供される16ミリ秒未満のプレスを区別したいとは思いません(プレイヤーが人間であると想定)。
Olhovsky、

します。熟練した格闘ゲームプレーヤーは、3フレーム未満でハドウケン/昇龍拳のスティックコマンドを入力できます。つまり、それらを区別する必要があります。

次に、60Hzより頻繁にポーリングする必要があります。
Olhovsky、

3

1つの方法は、現在および以前の入力状態を保存し、入力をポーリングするたびにそれらを比較することです。

押すことができるキーごとに、キーが最後にダウン状態からアップ状態に切り替わったときのタイムスタンプを持つオブジェクトを保存します。

すべてのポーリングでこれを実行して、これらのオブジェクトを更新します。

void update(){
    some_key_has_been_pressed = false;
    foreach(key in keys){
        if(previous_input[key].Down && current_input[key].Up){
            keys[key].up_timestamp = current_time();
        }

        if(current_input[key].Down){
            keys[key].down_timestamp = current_time();
            some_key_has_been_pressed = true;
        }
    }
}

これで、コンボをのコンテンツに対してパターンマッチングできますkeys

各コンボのコンボオブジェクトを用意し、各ポーリングで各コンボオブジェクトのupdate()を呼び出します。

コンボオブジェクトのupdate()メソッドは、コンボにパターンマッチし、このポーリングでコンボに必要なすべての条件が満たされているかどうかを確認します。つまり、これまでのコンボのすべてのキーのタイムスタンプは順調であり、コンボを壊す他のキーはこのフレームで押されていません。一致する条件ごとに、コンボオブジェクトのカウンターをインクリメントして、チェックする次の条件に移動します。コンボですべての条件が満たされたら、コンボが実行するメソッドを呼び出します。場合some_key_has_been_pressed == trueしかし、コンボのために、次の条件であるキーが押されていない場合、0にコンボの満足条件カウンタをリセットします。

上記は、実装が簡単で、保守が容易で、効率的で、高度にモジュール化されているため、私が好む方法です。

ただし、別の優れた方法については、C#で記述されたXNA入力シーケンスサンプルを確認してください。ロジックは、使用している言語に転送できる可能性があります。


2番目のifステートメントでif(current_input[key].down){は、キーがprevious_input状態にあるかどうかも確認しませんか?書かれているように、私はそれが保持されたキーを継続的に更新すると思いますdown_timestamp
webdevkit 2012

ダウンタイムスタンプを継続的に更新することは、意図された動作です。これにより、任意のキーのup_timestampとdown_timestampを比較して、保持されていた時間を確認できます。キーを押し続けている場合、up_timestampは変更されないので、(down_timestamp-up_timestamp)は、キーが保持されていた期間を示します。
Olhovsky 2012

説明をありがとう。私は反対を考えていました。up_timestamp-down_timestampは保持されたキーの期間です。
webdevkit 2012

1

最後のXキーイベントのスタックを作成し、キーイベントごとにキーとプレス/リリースの時間でオブジェクトを追加し、スタックの最後のメンバーが特別なパターンに一致するかどうか、およびそれらのキーが十分に速く押されたかどうかを確認します組み合わせとして数えます。最後に、最も古いオブジェクトをスタックから削除します。


2
一番下のオブジェクトを削除できるスタックは、実際にはスタックではありません;)
Olhovsky

順序付けられたデータエンティティの集まり。リストが正しい用語である場合があります。
aaaaaaaaaaaa

deque;)O(1)enq / deq ftw。
michael.bartnett 2011

3
オブジェクトが一方の端に置かれ、もう一方の端から削除される順序付けられたシーケンスは、最も適切にキューと呼ばれます

1
リングバッファーを作成し(BufferLength> =最長のコマンド)、それにキーを書き込むことができます(Position = Number MOD BufferLength)。いいえ、全く必要とされる追加/削除しない
Kromster
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.