多个弹跳球螺纹问题 [英] Multiple bouncing balls thread issue

查看:111
本文介绍了多个弹跳球螺纹问题的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

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 screen. But i have a multi-thread issue. When i click on the screen a ball appears and doesn't moving at all. When another click comes nothing happens.

BouncingBalls Class

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

}
}

Ball Class

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


推荐答案

你'维护对你的球的两个不同的引用。

You're maintaing two different references to your ball.

你有一个名为<$ c的单个的引用$ c> ball 和一个 List 的球。您的更新 paint 方法仅引用单个

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 似乎没有 start 方法(我可以看到)所以这个 balls.get(count-1).start(); 没有意义......

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

已更新


  • 您不需要对

  • 虽然不是一个坏主意,但在测试时,你应该在构造函数中调用 start

  • BouncingBalls 中的更新方法应循环遍历列表,在列表中的每个球上调用移动 ...

  • paintComponent DrawCanvas 的方法需要访问并且应该使用列表。这可能通过模型​​界面更好地实现

  • 不要使用参数构造新的 Ball ,因为它为每个球提供相同的属性,尤其是当你以任何方式构造它时给它分配随机值...

  • Ball 没有(或需要) )a 开始方法

  • 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

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 不是线程安全的,所以不是一个好主意多个线程试图同时访问它。虽然添加比删除更安全,但仍然是不好的做法。

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.

你可以用<$替换 ArrayList c $ c> Vector ,这将是更简单的解决方案,或者围绕公共监视器锁同步对列表的访问。举个例子,我使用 java.util.Vector

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

这篇关于多个弹跳球螺纹问题的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆