基于Java Swing实现小球触同色网格反弹及反转网格颜色的问题
解决方案与代码示例
核心问题分析
- 索引越界原因:原代码在
Core构造方法中直接调用getHeight()/getWidth()时,JPanel尚未完成布局,返回值为0,导致网格状态数组初始化失败。 - 缺失逻辑:未实现小球与同色网格的碰撞检测、反弹及颜色反转逻辑。
修改后的完整代码
Interface.java(无需修改)
import javax.swing.*; import java.awt.*; public class Interface extends JFrame{ private int frameHeight = 637; private int frameWidth = 1214; public Interface() { setSize(frameWidth, frameHeight); setLocationRelativeTo(null); setDefaultCloseOperation(EXIT_ON_CLOSE); setLayout(new BorderLayout()); setTitle("Bouncing Ball"); add(new Core()); setVisible(true); } public static void main(String[] args){ new Interface(); } }
Core.java(修改后)
import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Core extends JPanel{ int xw = 10, yw = 10, xb = 1000, yb = 400; int bounds = 20, gridSize = 20; int vxw = 5, vyw = 5, vxb = 5, vyb = 5; int rows, columns; int[][] gridState; // 0=黑色网格,1=白色网格 public Core() { Timer timer = new Timer(10, new ActionListener() { @Override public void actionPerformed(ActionEvent e) { // 移动小球 xw += vxw; yw += vyw; xb -= vxb; yb -= vyb; // 窗口边界反弹 if (xw > getWidth() - bounds || xw < 0) vxw = -vxw; if (yw > getHeight() - bounds || yw < 0) vyw = -vyw; if (xb > getWidth() - bounds || xb < 0) vxb = -vxb; if (yb > getHeight() - bounds || yb < 0) vyb = -vyb; // 处理白球与网格的碰撞 handleBallCollision(xw + bounds/2, yw + bounds/2, true); // 处理黑球与网格的碰撞 handleBallCollision(xb + bounds/2, yb + bounds/2, false); repaint(); } }); timer.start(); } // 处理小球碰撞逻辑:isWhiteBall为true表示白球,false表示黑球 private void handleBallCollision(int centerX, int centerY, boolean isWhiteBall) { if (gridState == null) return; // 网格未初始化时跳过 // 计算小球中心所在的网格坐标 int gridX = centerX / gridSize; int gridY = centerY / gridSize; // 避免索引越界 if (gridX < 0 || gridX >= columns || gridY < 0 || gridY >= rows) return; // 判断网格颜色是否与小球颜色匹配 boolean isMatch = isWhiteBall ? (gridState[gridY][gridX] == 1) : (gridState[gridY][gridX] == 0); if (isMatch) { // 反弹:根据小球移动方向反转速度(这里简化为反转x和y方向,可根据碰撞面调整) if (isWhiteBall) { vxw = -vxw; vyw = -vyw; } else { vxb = -vxb; vyb = -vyb; } // 反转网格颜色 gridState[gridY][gridX] = gridState[gridY][gridX] == 0 ? 1 : 0; } } @Override public void paintComponent(Graphics g) { super.paintComponent(g); Graphics2D g2d = (Graphics2D) g; // 初始化网格状态数组(仅第一次绘制时执行) if (gridState == null) { rows = getHeight() / gridSize; columns = getWidth() / gridSize; gridState = new int[rows][columns]; // 初始半黑半白布局 for (int y = 0; y < rows; y++) { for (int x = 0; x < columns; x++) { gridState[y][x] = x < columns / 2 ? 0 : 1; } } } // 绘制网格 for (int y = 0; y < rows; y++) { for (int x = 0; x < columns; x++) { int posX = x * gridSize; int posY = y * gridSize; // 根据网格状态设置颜色 g2d.setColor(gridState[y][x] == 0 ? Color.BLACK : Color.WHITE); g2d.fillRect(posX, posY, gridSize, gridSize); // 绘制网格线 g2d.setColor(Color.GRAY); g2d.drawRect(posX, posY, gridSize, gridSize); } } // 绘制白球 g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); g2d.setColor(Color.WHITE); g2d.fillOval(xw, yw, bounds, bounds); // 绘制黑球 g2d.setColor(Color.BLACK); g2d.fillOval(xb, yb, bounds, bounds); } }
关键修改说明
- 网格状态数组初始化:移至
paintComponent方法中,确保组件布局完成后获取正确的宽高,避免索引越界。 - 碰撞检测逻辑:
- 以小球中心坐标计算所在网格,提升判断准确性。
- 先判断网格坐标是否在数组范围内,避免索引越界。
- 匹配小球颜色与网格颜色时,执行反弹(反转速度)和网格颜色反转操作。
- 网格绘制优化:根据
gridState数组动态绘制颜色,不再依赖固定的半屏判断,支持颜色反转后的状态更新。
内容的提问来源于stack exchange,提问作者garwy
相关产品推荐
相关产品推荐

