我正在创建一个程序来创建一个将使用箭头键移动的球,但是当我运行代码时,球开始在角落里,我只能在每个方向移动一次。 这是代码:
package squareMovingUsingArrowKeys;
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
@SuppressWarnings("serial")
public class squareMovingUsingArrowKeys extends JPanel implements ActionListener,KeyListener {
static int x;
static int y;
Timer timer;
squareMovingUsingArrowKeys() {
x = 0;
y = 0;
timer = new Timer(20, this);
}
@SuppressWarnings("deprecation")
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
x = -1;
}
else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
x = 1;
}
else if (e.getKeyCode() == KeyEvent.VK_UP) {
y = -1;
}
else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
y = 1;
}
//first call move to update x and y and later repaint that JPanel
move(x, y);
repaint();
}
public void paintComponent(Graphics g) {
super.paintComponent(g);
g.fillOval(x, y, 10, 10);
}
public void start() {
keyPressed(null);
paintComponent(null);
}
public static void main(String[] args) {
JFrame f = new JFrame("Moving");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
squareMovingUsingArrowKeys m = new squareMovingUsingArrowKeys();
f.add(m);
f.setSize(500, 500);
f.setVisible(true);
m.timer.start();
f.addKeyListener(m);
}
@Override
public void actionPerformed(ActionEvent e) {
// TODO Auto-generated method stub
}
@Override
public void keyReleased(KeyEvent arg0) {
// TODO Auto-generated method stub
}
@Override
public void keyTyped(KeyEvent arg0) {
// TODO Auto-generated method stub
}
}
这不是家庭作业或类似的东西,我只是在学习java并想尝试它。 还请记住,我只有9岁,还有一个菜鸟。
答案 0 :(得分:1)
它只移动一次的原因是,在您的主要听众中,您直接将x
和y
分配给±1而不是调整之前的值。要修改之前的值,您需要执行x = x + 1;
或x += 1;
或x++;
或同等值。 E.g:
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
x -= 1;
}
else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
x += 1;
}
else if (e.getKeyCode() == KeyEvent.VK_UP) {
y -= 1;
}
else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
y += 1;
}
我在您的代码中看到的其他一些问题:
squareMovingUsingArrowKeys
)应以大写字母开头命名。x
和y
不应该是static
,因为它会在类的多个实例之间共享变量,而不是让每个实例都有自己的位置。move
。这会移动整个JPanel
,但JPanel
已经将球相对于自身移动,所以这就是你所需要的。您也不需要@SuppressWarnings("deprecation")
。如果您确实希望在没有弃用警告的情况下移动JPanel
,请改为调用setLocation
(在Java 1.1中重命名move
方法,这就是警告的内容)。系统发送关键事件的方式导致一些问题。按住一个键时,球会立即移动一次,但在开始反复移动之前会有一个小的延迟。这是因为按住任何键时会出现按键重复延迟。键入是正确的,但游戏对象移动看起来不对。更糟糕的是,它的速率可能取决于系统,因此球不会在不同的系统上以一致的速度移动。此外,对角移动不起作用;当同时按下第二个键时,似乎不发送按键的按键事件。解决所有这些问题的方法是使用关键事件不直接调整球的位置,而是更新状态变量,说明当前按下哪些键。然后,在x
的{{1}} y
中实施Timer
和ActionListener
的实际更新:
private boolean movingLeft, movingRight, movingUp, movingDown;
@Override
public void keyPressed(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
movingLeft = true;
} else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
movingRight = true;
} else if (e.getKeyCode() == KeyEvent.VK_UP) {
movingUp = true;
} else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
movingDown = true;
}
}
@Override
public void keyReleased(KeyEvent e) {
if (e.getKeyCode() == KeyEvent.VK_LEFT) {
movingLeft = false;
} else if (e.getKeyCode() == KeyEvent.VK_RIGHT) {
movingRight = false;
} else if (e.getKeyCode() == KeyEvent.VK_UP) {
movingUp = false;
} else if (e.getKeyCode() == KeyEvent.VK_DOWN) {
movingDown = false;
}
}
@Override
public void actionPerformed(ActionEvent e) {
if (movingLeft) x -= 1;
if (movingRight) x += 1;
if (movingUp) y -= 1;
if (movingDown) y += 1;
repaint();
}
/* ... rest of the code the same ... */
所有与Swing的交互都应该发生在名为Event Dispatch Thread的专用线程上。 In main
you should call SwingUtilities.invokeLater
转到正确的主题:
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
JFrame f = new JFrame("Moving");
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
/* ... rest of code for setting up frame here ... */
});
}
使用错误的线程与Swing进行交互目前不会导致程序出现问题,但它在技术上仍然是不正确的,而且这种情况可能会导致细微的问题。程序的其余部分是事件驱动的,因此它已经在正确的线程上运行。