Java中调用自定义Swing迷你网球游戏类无法正常启动问题咨询
解决方案
一、修改Game2游戏代码
核心修改点
- 新增游戏运行状态控制变量,将游戏循环从静态
main方法中抽离为独立子线程,避免阻塞Swing事件调度线程 - 移除
gameOver方法中会终止整个虚拟机的System.exit调用,改为仅关闭当前游戏窗口 - 新增
start()/stop()方法控制游戏生命周期,支持外部手动启停 - 调整窗口默认关闭逻辑,避免关闭游戏时连带退出主程序
修改后完整代码
import javax.swing.*; import java.awt.*; import java.awt.event.*; @SuppressWarnings("serial") public class Game2 extends JPanel { Ball ball = new Ball(this); Racquet racquet = new Racquet(this); int speed = 1; // 新增:游戏运行状态标记 private volatile boolean isRunning; // 新增:游戏循环线程 private Thread gameThread; private int getScore() { return speed - 1; } public Game2() { addKeyListener(new KeyListener() { @Override public void keyTyped(KeyEvent e) { } @Override public void keyReleased(KeyEvent e) { racquet.keyReleased(e); } @Override public void keyPressed(KeyEvent e) { racquet.keyPressed(e); } }); setFocusable(true); Sound.BACK.loop(); } // 新增:启动游戏方法 public void start() { isRunning = true; gameThread = new Thread(() -> { while (isRunning) { move(); repaint(); try { Thread.sleep(10); } catch (InterruptedException e) { Thread.currentThread().interrupt(); break; } } }); gameThread.start(); } // 新增:停止游戏、释放资源方法 public void stop() { isRunning = false; if (gameThread != null) { gameThread.interrupt(); } Sound.BACK.stop(); } private void move() { ball.move(); racquet.move(); } @Override public void paint(Graphics g) { super.paint(g); Graphics2D g2d = (Graphics2D) g; g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); ball.paint(g2d); racquet.paint(g2d); g2d.setColor(Color.GREEN); g2d.setFont(new Font("Verdana", Font.BOLD, 30)); g2d.drawString(String.valueOf(getScore()), 10, 30); } // 修改:移除System.exit,仅关闭游戏窗口 public void gameOver() { stop(); Sound.GAMEOVER.play(); JOptionPane.showMessageDialog(this, "你接住了" + getScore() + "次", "游戏结束", JOptionPane.YES_NO_OPTION); Window gameWindow = SwingUtilities.windowForComponent(this); if (gameWindow != null) { gameWindow.dispose(); } } // 修改:优化单独运行逻辑,不影响外部调用 public static void main(String[] args) { SwingUtilities.invokeLater(() -> { JFrame frame = new JFrame("Catch the Snowball"); Game2 game = new Game2(); frame.add(game); frame.setSize(300, 400); frame.setVisible(true); // 改为DISPOSE_ON_CLOSE,仅关闭当前窗口不退出程序 frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); // 启动游戏 game.start(); // 窗口关闭时自动停止游戏线程 frame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { game.stop(); } }); }); } }
二、外部调用示例
在你的主程序按钮点击事件中添加如下代码即可调起游戏:
// 假设这是你主界面上的启动游戏按钮 JButton startGameBtn = new JButton("启动网球小游戏"); startGameBtn.addActionListener(e -> { JFrame gameFrame = new JFrame("迷你网球"); Game2 game = new Game2(); gameFrame.add(game); gameFrame.setSize(300, 400); // 窗口居中显示可选 gameFrame.setLocationRelativeTo(null); gameFrame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); gameFrame.setVisible(true); // 启动游戏循环 game.start(); // 窗口关闭时停止游戏释放资源 gameFrame.addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { game.stop(); } }); });
三、修改说明
- 原来的游戏循环直接写在
main方法的主线程中,调用时会阻塞当前线程导致界面无响应,抽离为独立子线程后不会影响主程序运行 - 移除
System.exit调用后,游戏结束只会关闭游戏窗口,不会终止整个主程序 - 提供显式的
start()/stop()方法,方便外部控制游戏生命周期,也避免了InterruptedException异常抛出到上层
内容的提问来源于stack exchange,提问作者myBad
相关产品推荐
相关产品推荐

