Java弹跳小球碰撞异常求助:图标触碰后无法正常反弹
Java Swing弹跳小球交叉碰撞异常修复方案
问题背景
基于Java Swing开发弹跳小球程序,使用JLabel承载小球图标。仅开启X轴速度反转时小球可正常反弹,但启用Y轴速度反转后,小球交叉碰撞时图标出现异常,需实现碰撞后正常反弹。
问题根源
- 逻辑顺序错位:原代码先更新小球位置,再检测边界与碰撞,导致碰撞检测使用的是更新前的位置,逻辑混乱。
- 碰撞后未分离小球:小球碰撞后重叠,会持续触发碰撞检测,导致速度反复反转,引发卡顿或图标异常。
- 速度反转逻辑不合理:直接同时反转X/Y速度,未根据实际碰撞方向(X轴或Y轴方向重叠)选择对应速度分量反转,不符合物理碰撞逻辑。
修复后代码
启动类(无需修改)
package odev5_m_metin; import javax.swing.*; public class giris { public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { odev_intersect o1 = new odev_intersect(); o1.setVisible(true); } }); } }
主类(修复后)
package odev5_m_metin; import javax.swing.*; import java.util.Timer; import java.util.TimerTask; import java.awt.Rectangle; public class odev_intersect extends JFrame { private JPanel panel1; private JLabel label1; private JLabel label2; private JLabel label3; static int x, y, x2, y2, x3, y3; static int hizx = 5, hizy = 4, hizx2 = 5, hizy2 = 7, hizx3 = 5, hizy3 = 5; static Timer time1; static Rectangle r1, r2, r3; public odev_intersect() { add(panel1); setSize(500, 500); setTitle("Intersect Ödev"); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); // 初始化小球位置 x = 100; y = 200; x2 = 200; y2 = 200; x3 = 300; y3 = 300; label1.setBounds(x, y, 50, 50); label2.setBounds(x2, y2, 50, 50); label3.setBounds(x3, y3, 50, 50); time1 = new Timer(); time1.schedule(new TimerTask() { @Override public void run() { // 先更新碰撞检测用的矩形(当前位置) r1 = new Rectangle(x, y, 50, 50); r2 = new Rectangle(x2, y2, 50, 50); r3 = new Rectangle(x3, y3, 50, 50); // 1. 检测边界碰撞并反转速度 checkBoundaryCollision(); // 2. 检测小球间碰撞并处理 checkBallCollision(r1, r2, 1, 2); checkBallCollision(r1, r3, 1, 3); checkBallCollision(r2, r3, 2, 3); // 3. 更新小球位置 x += hizx; y += hizy; x2 += hizx2; y2 += hizy2; x3 += hizx3; y3 += hizy3; // 更新UI label1.setBounds(x, y, 50, 50); label2.setBounds(x2, y2, 50, 50); label3.setBounds(x3, y3, 50, 50); } }, 0, 10); } // 检测边界碰撞 private void checkBoundaryCollision() { if (x <= 0 || x >= 450) hizx *= -1; if (y <= 0 || y >= 450) hizy *= -1; if (x2 <= 0 || x2 >= 450) hizx2 *= -1; if (y2 <= 0 || y2 >= 450) hizy2 *= -1; if (x3 <= 0 || x3 >= 450) hizx3 *= -1; if (y3 <= 0 || y3 >= 450) hizy3 *= -1; } // 处理小球间碰撞 private void checkBallCollision(Rectangle a, Rectangle b, int ballA, int ballB) { if (a.intersects(b)) { // 计算重叠量 int overlapX = Math.min(a.x + a.width, b.x + b.width) - Math.max(a.x, b.x); int overlapY = Math.min(a.y + a.height, b.y + b.height) - Math.max(a.y, b.y); // 判断碰撞方向:重叠量小的方向为碰撞主方向 if (overlapX < overlapY) { // X轴方向碰撞,反转X速度 if (ballA == 1) hizx *= -1; if (ballA == 2) hizx2 *= -1; if (ballA == 3) hizx3 *= -1; if (ballB == 1) hizx *= -1; if (ballB == 2) hizx2 *= -1; if (ballB == 3) hizx3 *= -1; // 分离小球:沿X轴推开 if (a.x < b.x) { a.x -= overlapX / 2; b.x += overlapX / 2; } else { a.x += overlapX / 2; b.x -= overlapX / 2; } } else { // Y轴方向碰撞,反转Y速度 if (ballA == 1) hizy *= -1; if (ballA == 2) hizy2 *= -1; if (ballA == 3) hizy3 *= -1; if (ballB == 1) hizy *= -1; if (ballB == 2) hizy2 *= -1; if (ballB == 3) hizy3 *= -1; // 分离小球:沿Y轴推开 if (a.y < b.y) { a.y -= overlapY / 2; b.y += overlapY / 2; } else { a.y += overlapY / 2; b.y -= overlapY / 2; } } // 更新对应小球的坐标 updateBallPosition(ballA, a); updateBallPosition(ballB, b); } } // 更新小球坐标 private void updateBallPosition(int ball, Rectangle rect) { switch (ball) { case 1: x = rect.x; y = rect.y; break; case 2: x2 = rect.x; y2 = rect.y; break; case 3: x3 = rect.x; y3 = rect.y; break; } } }
关键修复说明
- 调整逻辑顺序:先基于当前位置检测碰撞,再更新位置,确保碰撞检测的准确性。
- 碰撞分离处理:计算小球碰撞后的重叠量,沿碰撞方向将小球推开,避免持续触发碰撞检测。
- 方向化速度反转:根据X/Y轴的重叠量判断碰撞主方向,仅反转对应轴的速度,符合物理碰撞逻辑。
内容的提问来源于stack exchange,提问作者fantazsizt
相关产品推荐
相关产品推荐

