多个弹跳球螺纹问题

我创建了一个程序,可以生成多个具有随机颜色,速度和半径的弹跳球。 当用户点击屏幕时,应出现一个新的随机球并在屏幕上移动。 但我有一个multithreading问题。 当我点击屏幕时,会出现一个球并且根本不会移动。 当另一次点击没有任何反应时。

BouncingBalls Class

public class BouncingBalls extends JPanel implements MouseListener{ private Ball ball; protected List balls = new ArrayList(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); } 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(){ ball.move(container); } class DrawCanvas extends JPanel{ public void paintComponent(Graphics g){ super.paintComponent(g); container.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(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 } } 

球类

 import java.awt.Color; import java.awt.Graphics; public class Ball{ public static int random(int maxRange) { return (int) Math.round((Math.random() * maxRange)); } private BouncingBalls balls; 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){ for(Ball ball : balls){ 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  500){ speedX = -speedX; x = 500 - radius; } if(y - radius  500){ speedY = -speedY; y = 500 - radius; } } } 

集装箱类

 import java.awt.Color; import java.awt.Graphics; public 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); } } 

你正在维护两个不同的球参考。

你可以参考一个名为ball和一个球List 。 您的updatepaint方法仅引用单个ball

Ball似乎没有start方法(我可以看到)所以这个balls.get(count-1).start(); 没有意义……

更新

  • 你不需要参考ball
  • 虽然测试时不是一个坏主意,但您应该在构造函数中调用start
  • BouncingBalls update方法应循环遍历balls列表,调用列表中每个球的move
  • DrawCanvaspaintComponent方法需要访问并应该使用balls列表。 通过模型界面可以更好地实现这一点
  • 不要使用参数构造一个新的Ball ,因为它为每个球赋予相同的属性,特别是当你以任何方式构造它时为它分配随机值…
  • Ball没有(或不需要) start方法

在此处输入图像描述

 public class BouncingBalls extends JPanel implements MouseListener { // private Ball ball; protected List balls = new ArrayList(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); } } } 

更新

正如评论员所指出的, ArrayList不是线程安全的,让多个线程同时尝试访问它并不是一个好主意。 虽然添加比删除更安全,但仍然是不好的做法。

您可以使用Vector替换ArrayList ,这可能是更简单的解决方案,也可以围绕公共监视器锁同步对列表的访问。 举个例子,我会使用java.util.Vector

您可以尝试使用此备用Java程序在单个“START”按钮上弹出10个多色球…..

 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); } } } 

我希望你会喜欢它....如果你无法理解代码......你可以随时质疑...... :)享受代码...... 🙂