2 qq 38813780 qq_38813780 于 2018.01.21 16:49 提问

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

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
xiaoqiang_826   2018.01.21 22:33
已采纳

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

xiaoqiang_826
xiaoqiang_826 回复清水鼻涕泡: if (x > ball.x) //如果自己的x坐标大于发生碰撞的小球的x坐标,由数学知识可知自己应该往正向运动。这里只改变了当前小球的速度方向,被撞小球也要改变,要不然检测另一个小球还好碰撞。
大约一个月之前 回复
xiaoqiang_826
xiaoqiang_826 回复清水鼻涕泡: if (x > ball.x) //如果自己的x坐标大于发生碰撞的小球的x坐标,由数学知识可知自己应该往正向运动;
大约一个月之前 回复
qq_38813780
qq_38813780 if(flag==1){ //balls.add(new Ball(newx1,newy1)); component.addBall(); count++; System.out.println("发送碰撞 count数量"+count); flag=0; } component.repaint();
大约一个月之前 回复
qq_38813780
qq_38813780 即使是从左上角生成小球之后也生成了无数个啊 求您再解答下
大约一个月之前 回复
u014487136
u014487136   2018.01.21 18:18

自己打个Log看看,这个代码有点多啊

qq_26560315
qq_26560315   2018.01.21 18:43

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(); //处理异常
}
}
setStop()没有被调用,死循环将一直运行

qq_38813780
qq_38813780 死循环没事 检测碰撞后才会生成小球啊 问题是为啥生成了无数个小球
大约一个月之前 回复
qq_38813780
qq_38813780   2018.01.22 08:56

图片说明

xiaoqiang_826
xiaoqiang_826 回复清水鼻涕泡: 你的算法1球和2球碰撞后还会检测到2球和1球碰撞,所以至少会生成两个小球而这两个小球又相互碰撞生成无数个,所以检测到碰撞后必需改变发生碰撞的两个小球速度方向,使它们迅速脱离碰撞关系。
大约一个月之前 回复
qq_38813780
qq_38813780 即使改成从左上角生成小球依然生成了无数个
大约一个月之前 回复
Csdn user default icon
上传中...
上传图片
插入图片
准确详细的回答,更有利于被提问者采纳,从而获得C币。复制、灌水、广告等回答会被删除,是时候展现真正的技术了!