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

Java 2D游戏repaint异常:mouseClicked方法触发次数与圆形数量一致

解决Java 2D游戏中mouseClicked多次触发的问题

这个问题我太熟了——你肯定是给每个生成的圆形对象都单独注册了MouseListener!每创建一个新圆形就绑定一次点击监听,导致点击屏幕时,所有现存圆形的mouseClicked方法都会被调用一遍,自然输出次数和当前圆形数量完全一致。

解决方案:给游戏面板统一加监听器,而非单个圆形

正确的做法是只给承载所有游戏元素的面板(比如你的JPanel子类)注册一次鼠标监听器,然后在监听器里判断点击坐标命中了哪个圆形。这样不管有多少个圆形,点击事件只会触发一次。

代码示例

假设你的圆形类为Circle,包含getX()、getY()、getRadius()方法,游戏面板维护一个圆形列表:

public class GamePanel extends JPanel {
    private List<Circle> circles = new ArrayList<>();
    private int score = 0;

    public GamePanel() {
        // 只给面板加一次鼠标监听器
        addMouseListener(new MouseAdapter() {
            @Override
            public void mouseClicked(MouseEvent e) {
                int clickX = e.getX();
                int clickY = e.getY();
                
                // 遍历圆形列表,查找被点击的圆形
                Iterator<Circle> circleIterator = circles.iterator();
                while (circleIterator.hasNext()) {
                    Circle target = circleIterator.next();
                    // 计算点击点到圆心的距离
                    double distance = Math.sqrt(
                        Math.pow(clickX - target.getX(), 2) +
                        Math.pow(clickY - target.getY(), 2)
                    );
                    
                    if (distance <= target.getRadius()) {
                        // 命中目标:移除圆形、加分、生成新圆形
                        circleIterator.remove();
                        score++;
                        System.out.println("得分+1,当前分数:" + score);
                        spawnNewCircle();
                        // 终止遍历,避免重叠圆形重复触发
                        break;
                    }
                }
                // 刷新面板显示
                repaint();
            }
        });
        // 初始化第一个圆形
        spawnNewCircle();
    }

    // 随机生成新圆形的方法
    private void spawnNewCircle() {
        int maxX = getWidth() - 50;
        int maxY = getHeight() - 50;
        int x = (int)(Math.random() * maxX) + 25;
        int y = (int)(Math.random() * maxY) + 25;
        circles.add(new Circle(x, y, 25));
    }

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        // 绘制所有圆形
        for (Circle circle : circles) {
            g.fillOval(
                circle.getX() - circle.getRadius(),
                circle.getY() - circle.getRadius(),
                circle.getRadius() * 2,
                circle.getRadius() * 2
            );
        }
    }
}

关键说明

  1. 统一监听器:仅在面板初始化时注册一次鼠标监听器,避免重复绑定导致的多次触发。
  2. 命中判断:通过计算点击点与圆心的距离,判断是否命中圆形(距离≤半径即命中)。
  3. 迭代器移除:使用Iterator移除圆形,避免遍历列表时修改结构引发异常。
  4. 终止遍历:命中后立即break,防止多个重叠圆形被同时处理。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 03:25:52