球移动只有一次

时间:2015-10-31 21:22:23

标签: java swing animation graphics keylistener

我正在创建一个程序来创建一个将使用箭头键移动的球,但是当我运行代码时,球开始在角落里,我只能在每个方向移动一次。 这是代码:

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岁,还有一个菜鸟。

1 个答案:

答案 0 :(得分:1)

它只移动一次的原因是,在您的主要听众中,您直接将xy分配给±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)应以大写字母开头命名。
  • xy不应该是static,因为它会在类的多个实例之间共享变量,而不是让每个实例都有自己的位置。
  • 你不应该致电move。这会移动整个JPanel,但JPanel已经将球相对于自身移动,所以这就是你所需要的。您也不需要@SuppressWarnings("deprecation")。如果您确实希望在没有弃用警告的情况下移动JPanel,请改为调用setLocation(在Java 1.1中重命名move方法,这就是警告的内容)。
  • 系统发送关键事件的方式导致一些问题。按住一个键时,球会立即移动一次,但在开始反复移动之前会有一个小的延迟。这是因为按住任何键时会出现按键重复延迟。键入是正确的,但游戏对象移动看起来不对。更糟糕的是,它的速率可能取决于系统,因此球不会在不同的系统上以一致的速度移动。此外,对角移动不起作用;当同时按下第二个键时,似乎不发送按键的按键事件。解决所有这些问题的方法是使用关键事件不直接调整球的位置,而是更新状态变量,说明当前按下哪些键。然后,在x的{​​{1}} y中实施TimerActionListener的实际更新:

    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进行交互目前不会导致程序出现问题,但它在技术上仍然是不正确的,而且这种情况可能会导致细微的问题。程序的其余部分是事件驱动的,因此它已经在正确的线程上运行。

祝你好运!