1

私は別の質問のコメントセクションでこれを尋ねました(> Javaで同時キー押下を処理するにはどうすればよいですか?)、まったく新しい質問をするように求められました。

私の問題は、キー押下のArrayListを作成するときに、ユーザーがキーを押したままにすると、keyReleasedイベントを介してそれらが十分に速く削除されないことです。「asdf」と北、東、南、西、北東などの動きをしたいです。

両方のイベントのコードは次のとおりです。

@Override
public void keyPressed(KeyEvent e) {
    if(chatTextField.isFocusOwner() == true){
        //do nothing - don't walk
    } else {
        logger.debug("Key Pressed: " + e.getKeyChar());
        lastKey = keysPressed.get(keysPressed.size()-1);

        for (String key : keysPressed){
            if (!key.contains(String.valueOf(e.getKeyChar())) && !lastKey.contains(String.valueOf(e.getKeyChar()))){
                keysPressed.add(String.valueOf(e.getKeyChar()));
                System.out.println("ADDED: " + keysPressed);
            }
        }

        String keysList = keysPressed.toString();
        if (keysList.contains("w")){
            if (keysList.contains("d")){
                requestCharacterMove("NorthEast");
            } else if(keysList.contains("a")){
                requestCharacterMove("NorthWest");
            } else{
                requestCharacterMove("North");
            }
        } else if (keysList.contains("s")){
            if (keysList.contains("d")){
                requestCharacterMove("SouthEast");
            } else if(keysList.contains("a")){
                requestCharacterMove("SouthWest");
            } else{
                requestCharacterMove("South");
            }
        } else if (keysList.contains("d")){
            requestCharacterMove("East");
        } else if (keysList.contains("a")){
            requestCharacterMove("West");
        }
    }
}

@Override
public void keyReleased(KeyEvent e) {
    if(chatTextField.isFocusOwner() == true){
        //do nothing - don't walk
    } else {
        logger.debug("Key Released: " + e.getKeyChar());
        for (String key : keysPressed){
            if (key.contains(String.valueOf(e.getKeyChar()))){
                keysPressed.remove(String.valueOf(e.getKeyChar()));
                System.out.println("REMOVED: " + keysPressed);
            }
        }
    }
}

@Override
public void keyTyped(KeyEvent arg0) {
    // TODO Auto-generated method stub

}

lastKey(String)変数を介して2番目のチェックを追加するまで、ピラミッドが作成したものは膨大でした。その2番目のチェックを行っても、リストは大きくなり、ほとんどの場合、2〜3個の重複があります。私のキャラクターがぎこちなく動いているので、これに関するどんな助けも素晴らしいでしょう。:(

また、char、string、arrayListへの重複した変換を削除する方法はどれも素晴らしいでしょう。私は緊張しているので、「単純な」ものにあまりにも多くの型を使用しました。

4

3 に答える 3

4

物事がゆっくりと処理される可能性が最も高いというあなたの観察は、多くのSystem.out.println()ステートメントだけが原因です。

斜めの動きが得られないという問題は、チェックロジックの誤りが原因です。たとえば、キーABが押されているかどうかを明示的にチェックするのではなく、個別にチェックします。キーAはキャラクターをある方向に動かし、Bは別の方向に動かします。 。合計(例)、WESTNORTHを移動すると、効果的にNORTHWESTを移動できます。

押されたキーのリストの代わりに、java.util.BitSetを使用して、現在押されている各キーのビットを設定することができます。これにより、記述する必要のあるコードの量も大幅に削減されます(keyPressedは、キーコードで示されるビットを設定するだけで、keyReleasedはそれをクリアします)。キーが押されているかどうかを確認するには、BitSetに問い合わせて、コードのビットが現在設定されているかどうかを確認します。

編集:リストの代わりにBitSetを使用する例

public class BitKeys implements KeyListener {

    private BitSet keyBits = new BitSet(256);

    @Override
    public void keyPressed(final KeyEvent event) {
        int keyCode = event.getKeyCode();
        keyBits.set(keyCode);
    }

    @Override
    public void keyReleased(final KeyEvent event) {
        int keyCode = event.getKeyCode();
        keyBits.clear(keyCode);
    }

    @Override
    public void keyTyped(final KeyEvent event) {
        // don't care
    }

    public boolean isKeyPressed(final int keyCode) {
        return keyBits.get(keyCode);
    }

}

サンプルにKeyListenerを実装させたので、そのまま使用することもできます。キーが押されているかどうかを知る必要がある場合は、isKeyPressed()を使用してください。生のキーコードを使用するか(私が行ったように)、キー文字を使用するか(現在のように)を決定する必要があります。いずれにせよ、BitSetクラスを使用すると、キーを記録するためのコードの量が数行にどのように減少するかがわかります:)

于 2012-08-07T17:54:32.777 に答える
1

別の方法として、このゲームはテンキーを使用して、1回のキーストロークで各(半)基本方位を実装します。デフォルトの配置は、「設計」セクションに示されています。キーを個別に再割り当てして、キーボードのどこにでも同様のロゼットをマッピングできます。

于 2012-08-07T21:21:03.577 に答える
0

Javaでスレッドを正しく処理していないようです。Javaプログラムには3つのスレッド(最小)があります。それらはメインプログラムスレッド、イベントディスパッチスレッド、そして私が今思い出せないもう1つのスレッドです。

イベントを取得するたびに、特別なスレッドによって配信されます(これはイベントディスパッチスレッドだと思いますが、それは重要ではありません)。このスレッドで(時間がかかる)何もすることは許可されていません。これにより、入力がフリーズし、イベントを見逃して、Javaが応答しなくなったように見えます。つまり、Javaのイベントシステムが壊れたということです。あなたがすべきことは、結果をある種のバッファに保存することです。これは、イベントで実行することが期待できる高速な処理であり、後で説明するように処理されます。

[余談ですが、面白いアプリケーションは単純なGUIを作成することで、ボタンを押すだけで5秒間スレッドを待ちます。遅延が終了するまで、GUI全体がフリーズします!]

側面で別のスレッドを実行する必要があります(おそらくメインスレッド)。プログラム内のフレームを制御するある種のループを実行し、ゲームサイクルごとに1回完了します。各サイクルで、このスレッドは入力バッファーに格納されている結果を読み取り、それらを処理します。この背後にある理論は単純ですが、入力イベントがドロップされたり、複数回読み取られたりしないようにする必要があるため、実行は少し厄介になる可能性があります。いずれにせよ、あなたのゲームで頑張ってください!

于 2012-11-12T18:16:14.263 に答える