我正在编写一个小游戏。到目前为止,我有一个玩家,他可以跟随玩家在2D打印的瓷砖世界中移动。这里有一个小预览。
现在我的播放器移动代码如下所示:
键侦听器类
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);
}
}
玩家类
public void tick() {
if (Var.falling == true) {
velY += Var.gravity;
if (velY > 10) {
velY = 10;
}
}
x += velX;
y += velY;
这些代码只是类的一部分。
问题
当我使用 A 或 D 向右或向左移动,然后以某种方式点击另一个键(从 a 到 d/从 d 到 a)时,我的角色会静止一小段时间,然后在短暂的延迟后移动。看这里。
- 用户按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"。 相反,只需编写布尔变量。 这避免了通过编写一个"="而不是两个来意外分配的任何可能性。 例如:
if (Var.falling) {
更简单地说:从代码中删除每个出现的== true
。
在不知道键控和键降的确切顺序的情况下,很难说出确切的问题是什么,但看起来您的程序容易受到重叠的键控/键下序列的影响 - 例如:
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)
或更专业的东西。
但!请参阅如何知道用户何时真正在 Java 中释放了密钥?讨论从键盘自动重复。