Multiple bouncing balls thread issue

后端 未结 2 2205
梦谈多话
梦谈多话 2020-11-27 22:59

I created a program that makes multiple bouncing balls with random color, speed and radius. When user clicks on the screen a new random ball should appear and move around sc

相关标签:
2条回答
  • 2020-11-27 23:18

    You Can try this alternate Java Programm for bouncing 10 multi-colored balls on a single "START" button.....

    import java.awt.*;
    import java.awt.event.*;
    import java.io.*;
    import javax.swing.*;
    import javaimage.io.*;
    
    class Thr extends Thread
    {
        boolean up=false;
        Ballbounce parent;
        int top,left;
        Color c;
    
        Thr(int t,int l,Color cr,ex5 p)
        {
            top=l;
            if(top > 170)
            top=170-t/8;
            left=t;
            c=cr;
            parent=p;
        }
    
        public void run()
        {
        try
        {
            while(true)
            {
                Thread.sleep(37);
                if(top >= 188)
                up=true;
                if(top <= 0)
                up=false;
                if(!up)
                top=top+2;
                else
                top=top-2;
                parent.p.repaint();
            }
        }catch(Exception e){}
    }
    }
    
        class Ballbounce extends JFrame implements ActionListener
    {
    int top=0,left=0,n=0,radius=50;
    Color C[]={Color.black,Color.cyan,Color.orange,Color.red,Color.yellow,Color.pink,Color.gray,Color.blue,Color.green,Color.magenta};
    Thr t[]=new Thr[10];
    GPanel p;
    JButton b;
    Panel  p1;
    
    Ballbounce()
    {
    setSize(700,300);
    setVisible(true);
    setLayout( new BorderLayout());
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    add(p=new GPanel(this),BorderLayout.CENTER);
    
    b= new JButton("Start");
    b.addActionListener(this);
    
    
    add(p1=new Panel(),BorderLayout.SOUTH);
    p1.setBackground(Color.lightGray);
    p1.add(b);
    }
    
    public static void main(String args[])
    {
    new Ballbounce();
    }
    
    public void actionPerformed(ActionEvent e)
    {
    t[n]=new Thr(left+(radius+13)*n+29,top+n*25,C[n],this);
    t[n].start();
    n++;
    p.repaint();
    if(n >9)
    b.setEnabled(false);
    }
    }
    
    class GPanel extends JPanel
    {
    Ballbounce parent;
    
    GPanel(Ballbounce p)
    {
     parent=p;
    }
    
    public void paintComponent(Graphics g)
    {
    super.paintComponent(g);
    setBackground(Color.white);
    
    for(int i=0;i< parent.n;i++)
    {
    g.setColor(parent.t[i].c);
    g.fillOval(parent.t[i].left,parent.t[i].top,parent.radius,parent.radius);
    }
    }
    }
    

    I hope you will like it.... If u are unable to understand the code... You can question it anytime...... :) Enjoy the code... :)

    0 讨论(0)
  • 2020-11-27 23:22

    You're maintaing two different references to your ball.

    You have a reference to a single Ball called ball and a List of balls. Your update and paint methods only reference the single ball

    Ball doesn't seem to have a start method (that I can see) so this balls.get(count-1).start(); doesn't make sense...

    Updated

    • You don't need the reference to ball
    • While not a bad idea, while testing, you should probably call start in the constructor
    • Your update method in BouncingBalls should looping through the balls list, calling move on each ball in the list...
    • The paintComponent method of DrawCanvas needs access to and should make use of the balls list. This might be better achievable through a model interface
    • Do not construct a new Ball with parameters, as it's giving each ball the same properties, especially when you assign random values to it when you construct it any way...
    • Ball doesn't have (or need) a start method

    enter image description here

    public class BouncingBalls extends JPanel implements MouseListener {
    
    //    private Ball ball;
        protected List<Ball> balls = new ArrayList<Ball>(20);
        private Container container;
        private DrawCanvas canvas;
        private int canvasWidth;
        private int canvasHeight;
        public static final int UPDATE_RATE = 30;
        int x = random(480);
        int y = random(480);
        int speedX = random(30);
        int speedY = random(30);
        int radius = random(20);
        int red = random(255);
        int green = random(255);
        int blue = random(255);
        int count = 0;
    
        public static int random(int maxRange) {
            return (int) Math.round((Math.random() * maxRange));
        }
    
        public BouncingBalls(int width, int height) {
    
            canvasWidth = width;
            canvasHeight = height;
    
    //        ball = new Ball(x, y, speedX, speedY, radius, red, green, blue);
            container = new Container();
    
            canvas = new DrawCanvas();
            this.setLayout(new BorderLayout());
            this.add(canvas, BorderLayout.CENTER);
            this.addMouseListener(this);
    
            start();
    
        }
    
        public void start() {
    
            Thread t = new Thread() {
                public void run() {
    
                    while (true) {
    
                        update();
                        repaint();
                        try {
                            Thread.sleep(1000 / UPDATE_RATE);
                        } catch (InterruptedException e) {
                        }
                    }
                }
            };
            t.start();
        }
    
        public void update() {
            for (Ball ball : balls) {
                ball.move(container);
            }
        }
    
        class DrawCanvas extends JPanel {
    
            public void paintComponent(Graphics g) {
    
                super.paintComponent(g);
                container.draw(g);
                for (Ball ball : balls) {
                    ball.draw(g);
                }
    //            ball.draw(g);
            }
    
            public Dimension getPreferredSize() {
    
                return (new Dimension(canvasWidth, canvasHeight));
            }
        }
    
        public static void main(String[] args) {
    
            javax.swing.SwingUtilities.invokeLater(new Runnable() {
                public void run() {
                    JFrame f = new JFrame("Bouncing Balls");
                    f.setDefaultCloseOperation(f.EXIT_ON_CLOSE);
                    f.setContentPane(new BouncingBalls(500, 500));
                    f.pack();
                    f.setVisible(true);
                }
            });
        }
    
        @Override
        public void mouseClicked(MouseEvent e) {
            // TODO Auto-generated method stub
        }
    
        @Override
        public void mouseEntered(MouseEvent e) {
            // TODO Auto-generated method stub
        }
    
        @Override
        public void mouseExited(MouseEvent e) {
            // TODO Auto-generated method stub
        }
    
        @Override
        public void mousePressed(MouseEvent e) {
    
            count++;
            balls.add(new Ball());
    //        balls.add(new Ball(x, y, speedX, speedY, radius, red, green, blue));
    //        balls.get(count - 1).start();
    //        start();
        }
    
        @Override
        public void mouseReleased(MouseEvent e) {
            // TODO Auto-generated method stub
        }
    
        public static class Ball {
    
            public int random(int maxRange) {
                return (int) Math.round(Math.random() * maxRange);
            }
            int x = random(480);
            int y = random(480);
            int speedX = random(30);
            int speedY = random(30);
            int radius = random(20);
            int red = random(255);
            int green = random(255);
            int blue = random(255);
            int i = 0;
    
            public Ball() { //int x, int y, int speedX, int speedY, int radius, int red, int green, int blue) {
    
    //            this.x = x;
    //            this.y = y;
    //            this.speedX = speedX;
    //            this.speedY = speedY;
    //            this.radius = radius;
    //            this.red = red;
    //            this.green = green;
    //            this.blue = blue;
            }
    
            public void draw(Graphics g) {
    
                g.setColor(new Color(red, green, blue));
                g.fillOval((int) (x - radius), (int) (y - radius), (int) (2 * radius), (int) (2 * radius));
    
            }
    
            public void move(Container container) {
    
                x += speedX;
                y += speedY;
    
                if (x - radius < 0) {
    
                    speedX = -speedX;
                    x = radius;
                } else if (x + radius > 500) {
    
                    speedX = -speedX;
                    x = 500 - radius;
                }
    
                if (y - radius < 0) {
    
                    speedY = -speedY;
                    y = radius;
                } else if (y + radius > 500) {
    
                    speedY = -speedY;
                    y = 500 - radius;
                }
            }
        }
    
        public static class Container {
    
            private static final int HEIGHT = 500;
            private static final int WIDTH = 500;
            private static final Color COLOR = Color.WHITE;
    
            public void draw(Graphics g) {
    
                g.setColor(COLOR);
                g.fillRect(0, 0, WIDTH, HEIGHT);
            }
        }
    }
    

    Updated

    As pointed out by the commentators, ArrayList is not thread safe, it's not a good idea to have multiple threads trying to access it simultaneously. While adding is slightly safer then removing, it is still bad practice.

    You can either replace ArrayList with Vector, which would be the simpler solution, or synchronize the access to the list around a common monitor lock. Given your example, I'd use a java.util.Vector

    0 讨论(0)
提交回复
热议问题