如何防止我的 KeyEvent 重新绘制两个对象?

How to prevent my KeyEvent from repainting both objects?

我正在开发一个简单的游戏,它需要 1 个玩家(正方形)和一些在游戏区域内随机生成的敌人。我现在 运行 遇到了一个问题,因为当我 运行 我的程序时,按任意箭头键不仅会重绘玩家的新位置,还会将所有敌人重新生成到新位置地点。

我已经检查了我的代码几次,但我仍然不明白为什么会这样。任何帮助将不胜感激。

P.S.我不是一个非常有经验的程序员,所以这段代码中的一些可能不是尽可能高效,有些地方可能不正确;除了手头的问题,请随时指出任何错误。谢谢!

主要Class

    public class Eat {

    public static void main(String[] args) {

        // Creating the main frame
        JFrame main = new JFrame("Eat 'Em All - Version 1.0.2");
        main.setSize(497, 599);
        main.setLocationRelativeTo(null);
        main.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        main.setResizable(false);

        // Colours and borders
        Border areaBorder = new LineBorder(Color.LIGHT_GRAY, 3);

        // Creating main JPanel
        JPanel area = new JPanel();
        area.setLayout(new BoxLayout(area, BoxLayout.PAGE_AXIS));
        area.setBackground(Color.WHITE);
        main.setContentPane(area);

        // Creating the drawing/image/player
        DrawPlayer player = new DrawPlayer();
        player.setPreferredSize(new Dimension(497, 539));
        player.setOpaque(false);

        // Enemies
        DrawEnemy enemy = new DrawEnemy();
        enemy.setPreferredSize(new Dimension(497, 539));
        enemy.setBackground(Color.WHITE);

        // Creating the control panel for buttons, etc
        JPanel control = new JPanel();
        control.setPreferredSize(new Dimension(497, 60));
        control.setLayout(new GridLayout(1, 2, 0, 0));
        control.setBorder(areaBorder);

        JLabel welcome = new JLabel("  Welcome to Eat 'Em All   |--|   Press 'Start'");
        JButton start = new JButton("Start");

        // Adding it all to the frame
        main.add(enemy);
        enemy.add(player);
        control.add(welcome);
        control.add(start);
        area.add(control);

        // Adding keylistener and making button false
        player.addKeyListener(player);
        player.setFocusable(true);
        start.setFocusable(false);
        enemy.setFocusable(false);

        // Bring frame to front and visible
        main.toFront();
        main.setVisible(true);

        System.out.println(player.getWidth() / 2);
        System.out.println(player.getHeight() / 2);

    }

}

绘图玩家Class

    public class DrawPlayer extends JPanel implements KeyListener {

    long xPosition = 0;
    long yPosition = 0;

    public void paintComponent(Graphics g) {
        super.paintComponent(g);

        // Making loop to get points and move it
        // Center of area is x: 245 y: 255
        int xPoints[] = {235, 255, 255, 235, 235, 255};
        int yPoints[] = {265, 265, 245, 245, 265, 245};
        for (int i = 0; i < xPoints.length; i++) {
            xPoints[i] += xPosition;
            yPoints[i] += yPosition;
        }

        g.setColor(Color.BLUE);
        g.drawPolygon(xPoints, yPoints, xPoints.length);
    }

    public void keyPressed(KeyEvent e) {
        switch (e.getKeyCode()) {
            case KeyEvent.VK_DOWN:
                if (yPosition == 245) {
                    yPosition -= 5;
                } else {
                    yPosition += 5;
                }
                break;
            case KeyEvent.VK_UP:
                if (yPosition == -245) {
                    yPosition += 5;
                } else {
                    yPosition -= 5;
                }
                break;
            case KeyEvent.VK_LEFT:
                if (xPosition == -235) {
                    xPosition += 5;
                } else {
                    xPosition -= 5;
                }
                break;
            case KeyEvent.VK_RIGHT:
                if (xPosition == 235) {
                    xPosition -= 5;
                } else {
                    xPosition += 5;
                }
                break;
        }
        repaint();
    }

    public void keyReleased(KeyEvent e) {

    }

    public void keyTyped(KeyEvent e) {

    }
}

引敌Class

public class DrawEnemy extends JPanel {

    public void paintComponent(Graphics f) {
        super.paintComponent(f);

        for (int i = 0; i < 10; i++ ){
            f.setColor(Color.RED);
            f.drawOval((int)(Math.random() * ((440 - 0) + 0) + 0), (int)(Math.random() * ((500 - 0) + 0) + 0), 50, 50);
        }
    }
}

你这里有问题:

public void paintComponent(Graphics f) {
    super.paintComponent(f);

    for (int i = 0; i < 10; i++ ){
        f.setColor(Color.RED);
        f.drawOval((int)(Math.random() * ((440 - 0) + 0) + 0), (int)(Math.random() * ((500 - 0) + 0) + 0), 50, 50);
    }
}

您的程序逻辑在绘制方法中,这是您永远不应该做的事情,因为您永远无法完全控制何时甚至是否调用绘制方法.解决方案,获取 paintComponent 方法的随机化 out 并进入其自己的单独方法,当且仅当您想要随机化敌人时才调用该方法,而不是每次重新绘制时调用。

其他问题:

  • 将程序逻辑与 GUI 分开。
  • 例如,你应该有一个非 GUI Enemy class,它有自己的位置、大小、移动的字段,也许是 move() 方法,也许是 collision(Player p)方法。
  • 您应该只有 一个 绘图的 JPanel,这应该是它唯一的工作。
  • 同样,您不会将任何东西的移动与绘画方法联系起来。
  • 您可能需要某种游戏循环,也许是摇摆计时器。这将生成规则间隔的滴答声,促使敌人和玩家移动。
  • 摆脱 KeyListener 代码并支持键绑定。当涉及到组件焦点时,后者就不那么笨拙了。请检查教程。