清水鼻涕泡 2018-01-21 08:49 采纳率: 100%
浏览 1048
已采纳

本应碰撞后产生一个小球 却好像生成了无数个 求改

public class BallPanel extends JPanel
{
private ArrayList balls = new ArrayList(); //小球列表
private BallComponent component = new BallComponent(); //小球画板
private JButton btnAdd = new JButton("Add"); //Add按钮
private JComboBox placeCombo = new JComboBox(); //小球出现方位
private BallThread thread = new BallThread(); //小球运动线程
private int delay = 5; //小球运动的延缓时间
private int flag=0;
private double newX;
private double newY;
/**
* 初始化小球面板
*/
public BallPanel()
{
setLayout(new BorderLayout()); //设置为BorderLayout的布局
add(component, BorderLayout.CENTER); //将小球画板加到面板中央
component.setOpaque(true); //设置画板不透明,以便能添加背景色
component.setBackground(Color.BLACK); //设置背景色

    JPanel panel = new JPanel();    //创建用来放各种按钮的面板
    panel.add(btnAdd);              //将Add按钮放入该面板
    panel.setBackground(Color.LIGHT_GRAY);
    add(panel, BorderLayout.SOUTH); //将按钮面板加到主面板南部
    //Add按钮加入监听器,当按下按钮时添加小球
    btnAdd.addActionListener(new ActionListener()
    {
        public void actionPerformed(ActionEvent event)
        {
            component.addBall();
        }
    });
    thread.start(); //画画板的线程开始
}

/**
 * 主函数,主要用于测试
 * @param args
 */
public static void main(String[] args)
{
    EventQueue.invokeLater(new Runnable()
    {
        public void run()
        {
            JFrame frame = new JFrame("Hit Balls"); //设置测试框架的标题
            frame.add(new BallPanel());     //将小球碰撞动画面板放上去
            frame.setSize(400, 300);        //设置框架大小
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);   //设置框架的默认关闭方式
            frame.setLocationByPlatform(true);  //将框架的定位交给系统实现
            frame.setVisible(true);         //设置框架可见
        }
    });
}

/**
 * 小球运动线程
 * @author zjf
 */
private class BallThread extends Thread
{
    private boolean isStop = false; //停止标记

    /**
     * 线程体
     */
    public void run()
    {
        while (true)    //让它一直执行
        {
            if (!isStop)    //当没有停止的时候
            {
                for (int i = 0; i < balls.size(); i++)
                {
                    balls.get(i).move(component.getBounds());//每个小球都移动一遍
                }
                     while(flag==1){
                        balls.add(new Ball(newX,newY));
                        flag=0;
                    }
                component.repaint();    //重画画板
            }
            try {
                Thread.sleep(delay);    //线程延缓delay毫秒
            } catch (InterruptedException e) {  //捕获异常
                e.printStackTrace();    //处理异常
            }
        }
    }
    /**
     * 设置stop标志
     * @param isStop    是否停止
     */
    public void setStop(boolean isStop)
    {
        this.isStop = isStop;
    }
}

/**
 * 小球的画板
 * @author zjf
 */
class BallComponent extends JComponent
{
    public BallComponent()
    {
        setUI(new ComponentUI()
        {
            public void installUI(JComponent c)
            {
                super.installUI(c);
                LookAndFeel.installColors(c, "Panel.background",
                        "Panel.foreground");
            }
        });
    }
    /**
     * 添加小球
     */
    public void addBall()
    {
        double x = 0;   //小球开始的x坐标
        double y = 0;   //小球开始的y坐标
        balls.add(new Ball(x, y));  //在小球的列表中加入新球,球的初始方位和颜色为前面的值
    }

    /**
     * 绘制画板
     */
    public void paintComponent(Graphics g)
    {
        super.paintComponent(g);
        Graphics2D g2 = (Graphics2D)g;
        for (int i = 0; i < balls.size(); i++)   //将小球列表中的小球都画到画板上
        {
            Ball ball = balls.get(i);
            g2.fill(ball.getShape());       //画出小球的形状
        }
    }
}

/**
 * 小球类
 * @author zjf
 */
private class Ball
{
    private static final double SIZE = 20;  //小球的直径
    private double x = 0;   //小球所在的x坐标
    private double y = 0;   //小球所在的y坐标
    private double vx = Math.sqrt(2) / 2;   //小球在x轴的速度
    private double vy = Math.sqrt(2) / 2;   //小球在y轴的速度
    private Color color = Color.BLACK;      //小球的颜色

    /**
     * 小球的构造函数
     * @param x 小球所在的x坐标
     * @param y 小球所在的y坐标
     */
    public Ball(double x, double y)
    {
        this.x = x;
        this.y = y;
    }

    /**
     * 小球在一个矩形边框中移动
     * @param bounds 矩形边框
     */
    public void move(Rectangle2D bounds)
    {
        x += vx;    //小球在x轴上的位移
        y += vy;    //小球在y轴上的位移
        double minX = bounds.getMinX(); //矩形边界的最小x坐标
        double minY = bounds.getMinY(); //矩形边界的最小y坐标
        double maxX = bounds.getMaxX(); //矩形边界的最大x坐标
        double maxY = bounds.getMaxY(); //矩形边界的最大y坐标
        if (x <= minX)   //如果小球越过左边界
        {
            x = minX;   //小球的x坐标变为矩形边界的最小x坐标
            vx = -vx;   //小球在x轴方向的速度反向
        }
        if (y <= minY)   //如果小球越过上边界
        {
            y = minY;   //小球的y坐标变为矩形边界的最小y坐标
            vy = -vy;   //小球在y轴方向的速度反向
        }
        if (x + SIZE >= maxX)    //如果小球越过右边界
        {
            x = maxX - SIZE;    //小球的x坐标变为矩形边界的最大x坐标减去小球的直径
            vx = -vx;           //小球在x轴方向的速度反向
        }
        if (y + SIZE >= maxY)    //如果小球越过下边界
        {
            y = maxY - SIZE;    //小球的y坐标变为矩形边界的最大y坐标减去小球的直径
            vy = -vy;           //小球在y轴方向的速度反向
        }
        for (int i = 0; i < balls.size(); i++)   //判断小球间是否发生碰撞
        {
            Ball ball = balls.get(i);
            if (this.equals(ball))
                continue;
            if ((ball.x - x) * (ball.x - x) + (ball.y - y) * (ball.y - y) <= SIZE * SIZE)    //当两球间的距离小于直径时,可认为两小球发生了碰撞
            {
                flag=1;
                double degree = Math.atan((y - ball.y) / (x - ball.x)); //获取自己与发生碰撞的小球之间所形成的夹角,因为夹角只能在-pi/2-pi/2之间,所以还需判断两球的x坐标之间的关系
                if (x > ball.x)      //如果自己的x坐标大于发生碰撞的小球的x坐标,由数学知识可知自己应该往正向运动
                {
                    vx = Math.cos(degree);
                    vy = Math.sin(degree);
                }
                else    //如果自己的x坐标小于发生碰撞的小球的x坐标,由数学知识可知应该朝负向运动
                {
                    vx = -Math.cos(degree);
                    vy = -Math.sin(degree);
                }
            }
            newX=x;
            newY=y;
        }
    }

    /**
     * 获取小球的形状
     * @return 形状
     */
    public Ellipse2D getShape()
    {
        return new Ellipse2D.Double(x, y, SIZE, SIZE);
    }
    /**
     * 判断两个小球是否相同
     */
    public boolean equals(Object object) {
        if (this == object) return true;    //如果所指的对象相同,即两小球的确相同
        if (object == null) return false;   //如果要比较的小球不存在,则两小球不同
        if (getClass() != object.getClass()) return false;  //如果自己的类名与另一个对象的类名不同,则两小球不同
        Ball ball = (Ball) object;           //将另一个对象强制转化为小球
        return x == ball.x && y == ball.y && color.equals(ball.color);  //通过方位,颜色判断是否相同
    }
}

}

  • 写回答

4条回答 默认 最新

  • xiaoqiang_826 2018-01-21 14:33
    关注

    两球碰撞后新产生的小球在碰撞点上,下一次新小球会和前两个小球碰撞,如此死循环会一直产生小球,简单点改进办法就是新小球位置距离前两稍微放远一点,不能产生碰撞判断。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论
查看更多回答(3条)

报告相同问题?

悬赏问题

  • ¥15 关于#python#的问题:求帮写python代码
  • ¥15 LiBeAs的带隙等于0.997eV,计算阴离子的N和P
  • ¥15 关于#windows#的问题:怎么用WIN 11系统的电脑 克隆WIN NT3.51-4.0系统的硬盘
  • ¥15 来真人,不要ai!matlab有关常微分方程的问题求解决,
  • ¥15 perl MISA分析p3_in脚本出错
  • ¥15 k8s部署jupyterlab,jupyterlab保存不了文件
  • ¥15 ubuntu虚拟机打包apk错误
  • ¥199 rust编程架构设计的方案 有偿
  • ¥15 回答4f系统的像差计算
  • ¥15 java如何提取出pdf里的文字?