You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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();
        }
    });
});

三、修改说明

  1. 原来的游戏循环直接写在main方法的主线程中,调用时会阻塞当前线程导致界面无响应,抽离为独立子线程后不会影响主程序运行
  2. 移除System.exit调用后,游戏结束只会关闭游戏窗口,不会终止整个主程序
  3. 提供显式的start()/stop()方法,方便外部控制游戏生命周期,也避免了InterruptedException异常抛出到上层

内容的提问来源于stack exchange,提问作者myBad

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.23 14:15:07