问题
Okay so I am sorry for this being a really weird question but it is driving me insane.
I handle my WASD movement for my game via:
Action ClassWASDKeyPressed = new ClassWASDKeyPressed();
Action ClassWASDKeyReleased = new ClassWASDKeyReleased();
BitKeys movementBitKeys = new BitKeys(); //for WASD movement key pressed/releases
//pressed
theDesktop.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("W"), "wButtonPress");
theDesktop.getActionMap().put("wButtonPress", ClassWASDKeyPressed);
theDesktop.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("A"), "aButtonPress");
theDesktop.getActionMap().put("aButtonPress", ClassWASDKeyPressed);
theDesktop.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("S"), "sButtonPress");
theDesktop.getActionMap().put("sButtonPress", ClassWASDKeyPressed);
theDesktop.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("D"), "dButtonPress");
theDesktop.getActionMap().put("dButtonPress", ClassWASDKeyPressed);
//released
theDesktop.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released W"), "wButtonRelease");
theDesktop.getActionMap().put("wButtonRelease", ClassWASDKeyReleased);
theDesktop.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released A"), "aButtonRelease");
theDesktop.getActionMap().put("aButtonRelease", ClassWASDKeyReleased);
theDesktop.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released S"), "sButtonRelease");
theDesktop.getActionMap().put("sButtonRelease", ClassWASDKeyReleased);
theDesktop.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke("released D"), "dButtonRelease");
theDesktop.getActionMap().put("dButtonRelease", ClassWASDKeyReleased);
Here are the two Action classes:
class ClassWASDKeyPressed extends AbstractAction {
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent e) {
if (chatTextField.isFocusOwner() == false){
if (e.getActionCommand().equals("w")){
keyPressed(87);
} else if(e.getActionCommand().equals("a")){
keyPressed(65);
} else if(e.getActionCommand().equals("s")){
keyPressed(83);
} else if(e.getActionCommand().equals("d")){
keyPressed(68);
}
}
}
}
class ClassWASDKeyReleased extends AbstractAction {
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent e) {
if (chatTextField.isFocusOwner() == false){
if (e.getActionCommand().equals("w")){
keyReleased(87);
} else if(e.getActionCommand().equals("a")){
keyReleased(65);
} else if(e.getActionCommand().equals("s")){
keyReleased(83);
} else if(e.getActionCommand().equals("d")){
keyReleased(68);
}
}
}
}
And here is the logic for this:
public void keyPressed(int e) {
long endTime = System.nanoTime();
long elapsedTime = endTime - startTime;
double elapsedTimeSeconds = (double)elapsedTime / 1000000000.0;
if (elapsedTimeSeconds < .125){ //let them move 8 times a second
logger.info("KeyPressed (QUICK): " + elapsedTimeSeconds);
} else {
logger.info("KeyPressed (VALID): " + elapsedTimeSeconds);
//logger.debug("Key Pressed: " + e.getKeyChar()); //FOR TROUBLESHOOTING
movementBitKeys.keyPressed(e);
//movementBitKeys.showKeyList(); //FOR TROUBLESHOOTING
if (movementBitKeys.isKeyPressed(87) && !movementBitKeys.isKeyPressed(68) && !movementBitKeys.isKeyPressed(83) && !movementBitKeys.isKeyPressed(65)){
requestCharacterMove("North");
}
if (movementBitKeys.isKeyPressed(87) && movementBitKeys.isKeyPressed(68) && !movementBitKeys.isKeyPressed(83) && !movementBitKeys.isKeyPressed(65)){
requestCharacterMove("NorthEast");
}
if (movementBitKeys.isKeyPressed(87) && !movementBitKeys.isKeyPressed(68) && !movementBitKeys.isKeyPressed(83) && movementBitKeys.isKeyPressed(65)){
requestCharacterMove("NorthWest");
}
if (!movementBitKeys.isKeyPressed(87) && movementBitKeys.isKeyPressed(68) && !movementBitKeys.isKeyPressed(83) && !movementBitKeys.isKeyPressed(65)){
requestCharacterMove("East");
}
if (!movementBitKeys.isKeyPressed(87) && !movementBitKeys.isKeyPressed(68) && movementBitKeys.isKeyPressed(83) && !movementBitKeys.isKeyPressed(65)){
requestCharacterMove("South");
}
if (!movementBitKeys.isKeyPressed(87) && movementBitKeys.isKeyPressed(68) && movementBitKeys.isKeyPressed(83) && !movementBitKeys.isKeyPressed(65)){
requestCharacterMove("SouthEast");
}
if (!movementBitKeys.isKeyPressed(87) && !movementBitKeys.isKeyPressed(68) && movementBitKeys.isKeyPressed(83) && movementBitKeys.isKeyPressed(65)){
requestCharacterMove("SouthWest");
}
if (!movementBitKeys.isKeyPressed(87) && !movementBitKeys.isKeyPressed(68) && !movementBitKeys.isKeyPressed(83) && movementBitKeys.isKeyPressed(65)){
requestCharacterMove("West");
}
startTime = endTime;
}
}
public void keyReleased(int e) {
//logger.debug("Key Released: " + e.getKeyChar()); //FOR TROUBLESHOOTING
movementBitKeys.keyReleased(e);
//movementBitKeys.showKeyList(); //FOR TROUBLESHOOTING
}
public void keyTyped(int e) {
// not used - but in case I ever want it
}
Also the BitSet class:
package com.jayavon.game.helper;
import java.util.BitSet;
public class BitKeys{
private BitSet keyBits = new BitSet(256);
public void keyPressed(final int keyCode) {
keyBits.set(keyCode);
}
public void keyReleased(final int keyCode) {
keyBits.clear(keyCode);
}
public void keyTyped(final int keyCode) {
// don't care
}
public boolean isKeyPressed(final int keyCode) {
return keyBits.get(keyCode);
}
public void showKeyList(){
System.out.println(keyBits.toString());
}
}
My problem is when you hold down one of the movement keys between the first and second 'movement' is much longer than the required .125 millisecond wait. Here is some sample data:
Set 1:
6059 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (VALID): 2.567790275
6620 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (VALID): 0.560479937
6670 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (QUICK): 0.0504469 6710 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (QUICK): 0.09360516 6750 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (VALID): 0.129943376
6791 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (QUICK): 0.04009505 6821 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (QUICK): 0.07098997 6851 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (QUICK): 0.102378686 6902 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (VALID): 0.152006677
Set 2:
9690 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (VALID): 2.03802468
10272 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (VALID): 0.582025645
10322 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (QUICK): 0.054749323 10342 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (QUICK): 0.069890042 10372 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (QUICK): 0.100790212 10412 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (VALID): 0.141337411
10462 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (QUICK): 0.049483458 10462 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (QUICK): 0.049720381 10512 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (QUICK): 0.098888524 10542 [AWT-EventQueue-0] INFO com.jayavon.game.client.MyClient - KeyPressed (VALID): 0.128729361
And now time for the question. Obviously the first time you move the elapsed time is huge depending on how long, so that makes sense. What I dont get is why the second 'movement' is around .5 instead of closer to .125. As you can see from the data the third and fourth steps are firing so fast while holding down the key that they are less than .125.
Can anyone help me out with this in any way? Any suggestions to improve my code in any way would be tremendous help indeed. Milliseconds count.
回答1:
Here is how I solved this due to the tremendous help of @aioobe.
Timer timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
checkKeyStrokes();
}
}, 0, 0135);
public void checkKeyStrokes(){
if (movementBitKeys.isKeyPressed(87)){ //w
keyPressed(87);
}
if (movementBitKeys.isKeyPressed(65)){ //a
keyPressed(65);
}
if (movementBitKeys.isKeyPressed(83)){ //s
keyPressed(83);
}
if (movementBitKeys.isKeyPressed(68)){ //d
keyPressed(68);
}
}
Hope this can be of help to others!!!
回答2:
After analyzing your code - a quick response from me
- When a key is pressed to quick its not regognized by your movementBitKeys (not valid) This could be a problem. When you press the keys quickly e.g "s" followed by an "w" than "a".
"s" is valid (move south) - move south
(release "s" - do nothing)s
"w" is invalid (to quick)
"a" is valid (move east) -> move east -> this is wrong - should be NorthEast
Another suggestion of me. Currently you use two timers. One for elapsedTimeInSeconds and one Timer to control keys which were pressed.
This can be done in one process
class ClassWASDKeyPressed extends AbstractAction {
private static final long serialVersionUID = 1L;
public void actionPerformed(ActionEvent e) {
if (chatTextField.isFocusOwner() == false){
if (e.getActionCommand().equals("w")){
movementBitKeys.keyPressed(87);
} else if(e.getActionCommand().equals("a")){
movementBitKeys.keyPressed(65);
} else if(e.getActionCommand().equals("s")){
movementBitKeys.keyPressed(83);
} else if(e.getActionCommand().equals("d")){
movementBitKeys.keyPressed(68);
}
}
}
}
And a change in TimerTask
Timer timer = new Timer();
timer.schedule(new TimerTask() {
public void run() {
move(movementBitKeys); // instead of keypressed - without elapsedTimeSeconds
}
}, 0, 0125);
回答3:
If you're holding a key down then there is a timer that waits before sending repeat events. This sounds very similar to the question posted here Eliminating Initial keypress delay and Fixing delay issue in java keypress action
Why not just take the approach of assuming that when you receive a keyPressed event that the key is down until you get a keyReleased. So simply don't rely on the system generating the event for you. Have your own timer that when you've received a keyPressed event and no keyRelease that it requests at your required interval that the character moves in the key pressed direction. When you receive a keyRelease simply stop the timer.
来源:https://stackoverflow.com/questions/13043229/keypressed-event-slow-on-first-repeat