2

我创建了一个程序,可以制作多个具有随机颜色、速度和半径的弹跳球。当用户点击屏幕时,应该会出现一个新的随机球并在屏幕上移动。但我有一个多线程问题。当我点击屏幕时,会出现一个球并且根本不动。当再次点击时,什么也没有发生。

弹跳球类

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

}

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

容器类

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

2 回答 2

1

你对你的球有两个不同的引用。

你有一个单一的Ball被叫ball和一个List球的参考。您的updateandpaint方法仅引用单个ball

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

更新

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

在此处输入图像描述

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

更新

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

您可以替换ArrayListVector,这将是更简单的解决方案,或者围绕公共监视器锁同步对列表的访问。鉴于您的示例,我将使用java.util.Vector

于 2013-01-29T23:07:49.950 回答
0

你可以试试这个替代的 Java 程序,在一个“开始”按钮上弹跳 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);
}
}
}

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

于 2014-12-03T14:27:59.460 回答