【问题标题】:How to move pong paddle with java.Swing?如何用 java.Swing 移动乒乓球拍?
【发布时间】:2020-06-13 18:13:51
【问题描述】:

我正在尝试使用 Java 和 Swing 制作 Pong。但是,我有两个问题 - 一,屏幕上的矩形根本不移动,二,即使代码仍在运行,也会发生 NullPointerException。这是我的两个文件:


import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowEvent;

import javax.swing.JFrame;
import javax.swing.JPanel;

public class Pong extends JFrame implements KeyListener {

    private static final long serialVersionUID = -5782301423436L;

    JPanel panel;

    Paddle paddle1;

    public Pong() {
        super("Pong");

        panel = new JPanel();
        this.add(panel);

        super.setPreferredSize(new Dimension(800, 600));
        super.setVisible(true);
        super.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        super.pack();
        addKeyListener(this);

        paddle1 = new Paddle(100, 300);
    }

    public static void main(String[] args) {
        @SuppressWarnings("unused")
        Pong game = new Pong();
    }

    @Override
    public void paint(Graphics g) {
        super.paint(g);

        g.setColor(Color.WHITE);
        g.fillRect(0, 0, 800, 600);

        g.setColor(Color.BLACK);
        this.paddle1.draw(g);
    }

    public void keyTyped(KeyEvent e) {}

    public void keyReleased(KeyEvent e) {}

    // I've tested this part and the w and s key presses
    // are still detected, but nothing happens. Why not?
    public void keyPressed(KeyEvent keyEvent) {
        int key = keyEvent.getKeyCode();
        if (key == KeyEvent.VK_ESCAPE) {
            this.dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING));
        } else if (key == KeyEvent.VK_W) {
            this.paddle1.up();
        } else if (key == KeyEvent.VK_S) {
            this.paddle1.down();
        }
    }

}

import java.awt.Graphics;

public class Paddle {

    // Position of the paddle's center
    int x;
    int y;

    public Paddle(int x, int y) {
        this.x = x;
        this.y = y;
    }

    public void draw(Graphics g) {
        g.fillRect(this.x - 10, this.y - 40, 20, 80);
    }

    // Up is negative because Java coordinates

    public void up() {
        this.y -= 30;
    }

    public void down() {
        this.y += 30;
    }

}

我已经测试了 Pong 文件中的 keyPressed 方法,当按下 w 和 s 键时,它确实会检测到它们(它会在控制台上打印一行)。我对 Java 中的图形非常陌生,这是我尝试创建的第一个不是从 YouTube 上的教程复制粘贴的东西。我一直在查看我的代码大约一个小时,但找不到错误可能出在哪里。任何和所有的帮助将不胜感激。

【问题讨论】:

  • 正在发生 NullPointerException - 一次一个问题。首先修复NPE。堆栈跟踪将告诉您导致问题的语句。因此,请查看语句并找出哪个变量为 null 并解决问题。话虽如此,您的代码存在几个问题:1)不要覆盖 JFrame 上的paint()。自定义绘画是通过覆盖 JPanel 上的 paintComponent() 来完成的,然后将面板添加到框架中。阅读Custom Painting 上的 Swing 教程以获取更多信息和工作示例。
  • 2) 不要使用 KeyListener 来监听 KeyEvent。有关更多信息和解决方案,请参阅:Motion Using the Keyboard
  • 当一切都设置好并准备好显示时,通常你想在构造函数的末尾setVisible(true);。你肯定不想在paddle1 = new Paddle(100, 300);之前setVisible(true);
  • 在动画中,没有任何东西“移动”。您每秒擦除并重绘图像 30 到 60 次以呈现动画效果。

标签: java swing graphics 2d-games


【解决方案1】:

我已经检查了代码,可以帮助您解决错误。

首先,您在这里展示了使用 JFrame Pong 的 paint() 方法的 Paddle。您正在检测“W”和“S”键,并根据您编写的代码更新 Paddle 类中的 y 坐标的键。

但是,这里的问题是,您只是在更新 y 坐标。您不会再次使用新坐标绘制桨。因此,在设置新的 y 值后,您应该再次绘制桨。 所以,在 keyPressed() 方法中,在

this.paddle1.up();

this.paddle1.down();

您应该再次调用 Paddle 类的 draw() 方法,该方法将在修改后的位置绘制 Paddle。

在这个 draw() 方法中,您将传递一个 Graphics 对象,该对象是当前 JFrame Pong 的图形配置。因此,这可以使用 JFrame 的 getGraphics() 方法获得。

因此,在 up() 或 down() 之后添加的行将是

this.paddle1.draw(getGraphics());

由于我们正在处理图形,因此一旦您更改了 JFrame 图形中的某些内容,重新绘制 JFrame 也是正确的做法。如果您在 keyPressed() 方法中的 up() 和 down() 方法之后仅添加了上述行,您将看到 Paddle 没有移动。它之前的绘图将保持原样,根据按下的键,新的 Paddle 将向上或向下绘制。因此,您将看到一个垂直条,而不是一个移动的桨。发生这种情况是因为我们正在修改图形但没有再次绘制 JFrame。因此,它只会在 JFrame 中添加新的矩形,保持原样。 因此,要摆脱这种情况,您应该使用 JFrame 的 repaint() 方法,以便它只绘制最新的屏幕。

所以,完整的 keyPressed() 方法应该是这样的:

@Override
public void keyPressed(KeyEvent keyEvent) {
    int key = keyEvent.getKeyCode();
    if (key == KeyEvent.VK_ESCAPE) {
        this.dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING));
    } else if (key == KeyEvent.VK_W) {
        this.paddle1.up();
        this.paddle1.draw(getGraphics());
        repaint();
    } else if (key == KeyEvent.VK_S) {
        this.paddle1.down();
        this.paddle1.draw(getGraphics());
        repaint();
    }
}

所以,现在在检测到正确的键之后,它会再次绘制桨并 之后也会丢弃之前的代码,这样当您运行此代码时,您将能够看到桨在按下的键时移动。

现在,关于 NullPointerException。我尝试运行此代码,但无法重现此类异常。因此,在尝试了建议的代码后,如果遇到 NPE,可以更新堆栈跟踪以解决问题。

我已经阅读了 cmets,它们非常有用。请务必查看解释如何更好地收听关键事件的链接。

谢谢。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2022-01-11
    • 1970-01-01
    • 1970-01-01
    • 2018-10-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多