【问题标题】:Bouncing Balls in Java [closed]Java中的弹跳球[关闭]
【发布时间】:2021-08-12 08:10:11
【问题描述】:

我正在创建一个弹跳球项目,每次单击鼠标时都会以随机速度、随机大小和随机位置生成球,除了一件事之外,一切都运行良好,当球击中时让我们说从顶部和左侧的墙壁完全反弹回来但是当球击中窗口的底部和右侧部分时它们也会被反弹但并不完美,我的意思是球甚至在之前从窗口的右侧反弹回来当几乎一半的球超出窗口时,从底部击中墙壁。 有什么问题,为什么会这样?

这是代码:

import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
//To generate random colors
/*new Color((int) Math.floor((Math.random() * 256)),(int) Math.floor((Math.random() * 256)),(int) 
Math.floor((Math.random() * 256)))*/
public class bouncingBalls {
public static void main(String[] args) {
    Program program = new Program();
    program.run();
}
}

class Program {
protected JFrame mainFrame;
protected DrawPanel drawPanel;
protected java.util.List<Ball> balls;
void run() {

    balls = new ArrayList<>();
    mainFrame = new JFrame();
    drawPanel = new DrawPanel();
    mainFrame.getContentPane().add(drawPanel);
    mainFrame.setTitle("Bouncing Balls");
    mainFrame.setSize(640, 480);
    mainFrame.setVisible(true);
    mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    /* Generate balls */
    mainFrame.addMouseListener(new MouseAdapter() {
        public void mouseClicked(MouseEvent me) {
            System.out.println("Mouse clicked");
            Ball ball = new Ball(
                    /* Random positions from 0 to windowWidth or windowHeight */
                    (int) Math.floor(Math.random() * 640),
                    (int) Math.floor(Math.random() * 480),
                    /* Random size from 10 to 30 */
                    (int) Math.floor(Math.random() * 20) + 10,
                    /* Random RGB colors*/
                    new Color(0x851E3E),
                    /* Random velocities from -5 to 5 */
                    (int) Math.floor((Math.random() * 10) - 5),
                    (int) Math.floor((Math.random() * 10) - 5)
            );

            balls.add(ball);
        }
    });
    while (true) {
        for (Ball b: balls) {
            b.update();
        }

        /* Give Swing 10 milliseconds to see the update! */
        try {
            Thread.sleep(30);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        mainFrame.repaint();
    }
}

class DrawPanel extends JPanel {
    @Override
    public void paintComponent(Graphics graphics) {
        super.paintComponent(graphics);

        for (Ball b: balls) {
            b.draw(graphics);
        }

    }
}

class Ball {
    private int posX, posY, size;
    private Color color;

    private int vx;
    private int vy;

    public Ball(int posX, int posY, int size, Color color, int vx, int vy) {
        this.posX = posX;
        this.posY = posY;
        this.size = size;
        this.color = color;
        this.vx = vx;
        this.vy = vy;
    }

    void update() {

        if (posX > mainFrame.getWidth()-size*2 || posX < 0) {
            vx *= -1;
        }

        if (posY > mainFrame.getHeight()-size-32 || posY < 0) {
            vy *= -1;
        }

        if (posX > mainFrame.getWidth()-size*2) {
            posX = mainFrame.getWidth()-size*2;
        }

        if (posX < 0) {
            posX = 0;
        }

        if (posY > mainFrame.getHeight()-size-32) {
            posY = mainFrame.getHeight()-size-32;
        }

        if (posY < 0) {
            posY = 0;
        }

        this.posX += vx;
        this.posY += vy;

    }

    void draw(Graphics g) {
        g.setColor(color);
        g.fillOval(posX, posY, size, size);
        g.getClipBounds();
        g.getClipBounds();
    }
}
}

【问题讨论】:

  • 听起来您没有正确考虑球的厚度。为什么你的更新方法中有size-32size*232 是什么?另外,为什么大小乘以2?这会让球离边缘太远,听起来就像你正在经历的行为。
  • 为什么是-size-32?不应该是posY + size &gt; height吗?另外,请注意,Swing 不是线程安全的。使用Thread 的方式可能会导致线程之间的脏读/写。 Swing Timer 可能是更好的解决方案
  • 请参阅:stackoverflow.com/questions/54028090/…,了解使用摇摆计时器的球动画示例。

标签: java swing


【解决方案1】:

好的,所以你有一些关键问题。

JFrame 包含 contentPane 和装饰。装饰出现在框架的边界内,这使得contentPanes 的大小等于框架大小减去装饰插图的大小。这是您主要遇到问题的地方,因为您使用帧大小而不是 DrawPanel 大小来确定碰撞检测。

相反,您应该使用DrawPanels 大小(已添加到contentPane)。

更多详情请见How can I set in the midst?

这是您代码的重建示例,它使用 Swing Timer 而不是 Thread,因此它是线程安全的,并将主要工作负载放置在 DrawPanel 中,而不是将其分散在各处。

详情请见How to Use Swing Timers

import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.ArrayList;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

public class Test {

    public static void main(String[] args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                Program program = new Program();
                program.run();
            }
        });
    }

    class Program {

        protected JFrame mainFrame;
        protected DrawPanel drawPanel;

        void run() {

            mainFrame = new JFrame();
            drawPanel = new DrawPanel();
            mainFrame.getContentPane().add(drawPanel);
            mainFrame.setTitle("Bouncing Balls");
            mainFrame.pack();
            mainFrame.setVisible(true);
            mainFrame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        }

        class DrawPanel extends JPanel {

            private java.util.List<Ball> balls;
            private Timer timer;

            public DrawPanel() {
                balls = new ArrayList<>(25);
                addMouseListener(new MouseAdapter() {
                    public void mouseClicked(MouseEvent me) {
                        System.out.println("Mouse clicked");
                        Ball ball = new Ball(
                                /* Random positions from 0 to windowWidth or windowHeight */
                                (int) Math.floor(Math.random() * 640),
                                (int) Math.floor(Math.random() * 480),
                                /* Random size from 10 to 30 */
                                (int) Math.floor(Math.random() * 20) + 10,
                                /* Random RGB colors*/
                                Color.RED,
                                /* Random velocities from -5 to 5 */
                                (int) Math.floor((Math.random() * 10) - 5),
                                (int) Math.floor((Math.random() * 10) - 5)
                        );

                        balls.add(ball);
                    }
                });
            }

            @Override
            public void addNotify() {
                super.addNotify();
                if (timer != null) {
                    timer.stop();
                }

                timer = new Timer(30, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent arg0) {
                        for (Ball b : balls) {
                            b.update(getSize());
                        }
                        repaint();
                    }
                });
                timer.start();
            }

            @Override
            public void removeNotify() {
                super.removeNotify();
                if (timer == null) {
                    return;
                }
                timer.stop();
            }

            @Override
            public Dimension getPreferredSize() {
                return new Dimension(640, 480);
            }

            @Override
            public void paintComponent(Graphics graphics) {
                super.paintComponent(graphics);

                for (Ball b : balls) {
                    b.draw(graphics);
                }

            }
        }

        class Ball {

            private int posX, posY, size;
            private Color color;

            private int vx;
            private int vy;

            public Ball(int posX, int posY, int size, Color color, int vx, int vy) {
                this.posX = posX;
                this.posY = posY;
                this.size = size;
                this.color = color;
                this.vx = vx;
                this.vy = vy;
            }

            void update(Dimension bounds) {

                if (posX + size > bounds.width || posX < 0) {
                    vx *= -1;
                }

                if (posY + size > bounds.height || posY < 0) {
                    vy *= -1;
                }

                if (posX + size > bounds.width) {
                    posX = bounds.width - size;
                }

                if (posX < 0) {
                    posX = 0;
                }

                if (posY + size > bounds.height) {
                    posY = bounds.height - size;
                }

                if (posY < 0) {
                    posY = 0;
                }

                this.posX += vx;
                this.posY += vy;

            }

            void draw(Graphics g) {
                g.setColor(color);
                g.fillOval(posX, posY, size, size);
            }
        }
    }
}

【讨论】:

    猜你喜欢
    • 2023-03-13
    • 2012-10-12
    • 2021-06-20
    • 1970-01-01
    • 2013-05-23
    • 1970-01-01
    • 1970-01-01
    • 2017-01-16
    • 1970-01-01
    相关资源
    最近更新 更多