KeyListener 事件的短暂延迟
Short delay for KeyListener events
我正在编写一个小游戏。到目前为止,我有一个玩家,他可以跟随玩家在 2D 打印的瓷砖世界中移动。这里有个小的preview.
现在我的玩家移动代码如下所示:
KeyListener class
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
for(int i = 0; i < handler.object.size(); i++){
GameObject tempObject = handler.object.get(i);
if(tempObject.getId() == ID.Player){
if(key == KeyEvent.VK_D) tempObject.setVelX(5);
if(key == KeyEvent.VK_A) tempObject.setVelX(-5);
if(key == KeyEvent.VK_SPACE && Var.jump == true) {
tempObject.setVelY(-10);
Var.jump = false;
}
}
}
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
for(int i = 0; i < handler.object.size(); i++){
GameObject tempObject = handler.object.get(i);
if(tempObject.getId() == ID.Player){
if(key == KeyEvent.VK_D) tempObject.setVelX(0);
if(key == KeyEvent.VK_A) tempObject.setVelX(0);
}
}
玩家class
public void tick() {
if (Var.falling == true) {
velY += Var.gravity;
if (velY > 10) {
velY = 10;
}
}
x += velX;
y += velY;
这些代码只是 classes 的一部分。
问题
当我用 A 或 D 向右或向左移动,然后以某种方式点击另一个键(从 a 到 d/从 d 到 a)时,我的角色会静止一小会儿然后在短暂的延迟后移动。参见 here。
- 用户按下 D,触发对
keyPressed
的调用,后者调用 tempObject.setVelX(5)
.
- 用户释放 A,这会触发对
keyReleased
的调用,后者会调用 tempObject.setVelX(0)
。这会停止你角色的动作。
- 用户仍在按住 D,因此在短暂的延迟后,该键的自动重复触发了对
keyPressed
的另一次调用,这导致 tempObject.setVelX(5)
再次调用,导致角色再次开始移动。
除非没有按下移动键,否则你不应该调用tempObject.setVelX(0)
。
你怎么确定的?您需要定义跟踪它们的实例字段。例如:
private boolean leftPressed;
private boolean rightPressed;
// ...
public void keyPressed(KeyEvent e) {
//...
if (key == KeyEvent.VK_D) {
rightPressed = true;
tempObject.setVelX(5);
}
if (key == KeyEvent.VK_A) {
leftPressed = true;
tempObject.setVelX(-5);
}
//...
}
public void keyReleased(KeyEvent e) {
//...
if (key == KeyEvent.VK_D) {
rightPressed = false;
if (!leftPressed) {
tempObject.setVelX(0);
}
}
if (key == KeyEvent.VK_A) {
leftPressed = false;
if (!rightPressed) {
tempObject.setVelX(0);
}
}
//...
}
一些旁注:
gameObject
是比 tempObject
. 更好的变量名
- 你永远不应该写“booleanVariable == true”。相反,只需编写 booleanVariable。通过写一个“=”而不是两个来避免意外赋值的任何可能性。例如:
if (Var.falling) {
更简单地说:从您的代码中删除所有出现的 == true
。
如果不知道 keyups 和 keydowns 的确切顺序,很难说出确切的问题是什么,但看起来您的程序容易受到重叠 keyup/keydown 序列的影响 - 例如:
A down -> velocity = -5
D down -> velocity = +5
A up -> velocity = 0 // but you want it to still be +5
将日志记录添加到您的游戏代码以帮助调试这些情况。
有多种方法可以解决这个问题,但一种方法是保持 运行 当前按下键的计数:
public void keyPressed(KeyEvent e) {
heldKeys++;
... other code ...
}
public void keyReleased(KeyEvent e) {
heldKeys--;
... other code ...
if(heldKeys == 0) {
velocity = 0;
}
}
这是轻巧但生硬的。更精确的方法可能是记录每个键的状态:
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
heldKeys.set(key, true);
}
...根据 keyStates
.
中的内容更新您的游戏状态
根据您对效率的狂热程度,keyStates
可能是 HashSet(Integer, Boolean)
或您自己创造的更专业的东西。
但是!有关从键盘自动重复的讨论,请参阅 How to know when a user has really released a key in Java?。
我正在编写一个小游戏。到目前为止,我有一个玩家,他可以跟随玩家在 2D 打印的瓷砖世界中移动。这里有个小的preview.
现在我的玩家移动代码如下所示:
KeyListener class
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
for(int i = 0; i < handler.object.size(); i++){
GameObject tempObject = handler.object.get(i);
if(tempObject.getId() == ID.Player){
if(key == KeyEvent.VK_D) tempObject.setVelX(5);
if(key == KeyEvent.VK_A) tempObject.setVelX(-5);
if(key == KeyEvent.VK_SPACE && Var.jump == true) {
tempObject.setVelY(-10);
Var.jump = false;
}
}
}
public void keyReleased(KeyEvent e) {
int key = e.getKeyCode();
for(int i = 0; i < handler.object.size(); i++){
GameObject tempObject = handler.object.get(i);
if(tempObject.getId() == ID.Player){
if(key == KeyEvent.VK_D) tempObject.setVelX(0);
if(key == KeyEvent.VK_A) tempObject.setVelX(0);
}
}
玩家class
public void tick() {
if (Var.falling == true) {
velY += Var.gravity;
if (velY > 10) {
velY = 10;
}
}
x += velX;
y += velY;
这些代码只是 classes 的一部分。
问题
当我用 A 或 D 向右或向左移动,然后以某种方式点击另一个键(从 a 到 d/从 d 到 a)时,我的角色会静止一小会儿然后在短暂的延迟后移动。参见 here。
- 用户按下 D,触发对
keyPressed
的调用,后者调用tempObject.setVelX(5)
. - 用户释放 A,这会触发对
keyReleased
的调用,后者会调用tempObject.setVelX(0)
。这会停止你角色的动作。 - 用户仍在按住 D,因此在短暂的延迟后,该键的自动重复触发了对
keyPressed
的另一次调用,这导致tempObject.setVelX(5)
再次调用,导致角色再次开始移动。
除非没有按下移动键,否则你不应该调用tempObject.setVelX(0)
。
你怎么确定的?您需要定义跟踪它们的实例字段。例如:
private boolean leftPressed;
private boolean rightPressed;
// ...
public void keyPressed(KeyEvent e) {
//...
if (key == KeyEvent.VK_D) {
rightPressed = true;
tempObject.setVelX(5);
}
if (key == KeyEvent.VK_A) {
leftPressed = true;
tempObject.setVelX(-5);
}
//...
}
public void keyReleased(KeyEvent e) {
//...
if (key == KeyEvent.VK_D) {
rightPressed = false;
if (!leftPressed) {
tempObject.setVelX(0);
}
}
if (key == KeyEvent.VK_A) {
leftPressed = false;
if (!rightPressed) {
tempObject.setVelX(0);
}
}
//...
}
一些旁注:
gameObject
是比tempObject
. 更好的变量名
- 你永远不应该写“booleanVariable == true”。相反,只需编写 booleanVariable。通过写一个“=”而不是两个来避免意外赋值的任何可能性。例如:
if (Var.falling) {
更简单地说:从您的代码中删除所有出现的 == true
。
如果不知道 keyups 和 keydowns 的确切顺序,很难说出确切的问题是什么,但看起来您的程序容易受到重叠 keyup/keydown 序列的影响 - 例如:
A down -> velocity = -5
D down -> velocity = +5
A up -> velocity = 0 // but you want it to still be +5
将日志记录添加到您的游戏代码以帮助调试这些情况。
有多种方法可以解决这个问题,但一种方法是保持 运行 当前按下键的计数:
public void keyPressed(KeyEvent e) {
heldKeys++;
... other code ...
}
public void keyReleased(KeyEvent e) {
heldKeys--;
... other code ...
if(heldKeys == 0) {
velocity = 0;
}
}
这是轻巧但生硬的。更精确的方法可能是记录每个键的状态:
public void keyPressed(KeyEvent e) {
int key = e.getKeyCode();
heldKeys.set(key, true);
}
...根据 keyStates
.
根据您对效率的狂热程度,keyStates
可能是 HashSet(Integer, Boolean)
或您自己创造的更专业的东西。
但是!有关从键盘自动重复的讨论,请参阅 How to know when a user has really released a key in Java?。