1

アプレットウィンドウ内でそれぞれが独自のスレッドを持つ複数のボールをバウンスするJavaアプレットを作成しようとしています。以下のコードでは、すべてのボールが描画されますが、最初のボールだけが移動します。私は何が間違っているのですか?

import java.applet.Applet;
import java.awt.Color;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;

import static java.awt.Color.*;

public class BouncingBalls extends Applet implements Runnable {

    List<Ball> ballList = new ArrayList(); // holds Ball objects

    Color[] colors = new Color[]{BLACK, GRAY, WHITE, PINK, RED, ORANGE, YELLOW,
            GREEN, BLUE, CYAN}; // array holding available colors

    static int width, height; // variables for applet dimensions

    int ballCount; // number of balls to be created, set by html parameter

    Random random = new Random(); // random number generator


    public void init() {

        // get window dimensions
        width = getSize().width;
        height = getSize().height;

        //get number of balls from html
        String ballCountString = this.getParameter("ballCount");

        try {
            ballCount = Integer.parseInt(ballCountString);
        } catch (NumberFormatException e) {
            ballCount = 10; // set to 10 by default
        }

        for (int i = 0; i < ballCount; i++) {

            // randomly assign ballDiameter between 1 and 20
            int ballDiameter = random.nextInt(20) + 1;

            // create and add balls to ballList
            ballList.add(new Ball(
                    random.nextInt(width - ballDiameter), // set x coordinate
                    random.nextInt(height - ballDiameter), // set y coordinate
                    ballDiameter, // set ballDiameter
                    random.nextInt(ballDiameter) + 1, // deltaX <= ballDiameter
                    random.nextInt(ballDiameter) + 1, // deltaY <= ballDiameter
                    colors[i % 10] // use remainder to choose colors[] element
                    )
            );

        } // end for

    } // end init


    public void start() {

        for (Ball ball: ballList) {

            Thread t;
            t = new Thread(this);
            t.start();

        } // end for

    } // end start


    public void run() {

        for (Ball ball : ballList) {

            // infinite loop: ball moves until applet is closed
            while (true) {

                ball.move();

                repaint(); // call paint method to draw circle in new location

                // set ball repaint delay using Thread sleep method
                try {
                    Thread.sleep(20); // wait 20 msec before continuing
                } catch (InterruptedException e) {
                    return;
                }

            } // end while

        } // end for

    } // end run

    public void paint(Graphics g) {

        super.paint(g);

        for (Ball ball : ballList) {

            // set current color
            g.setColor(ball.ballColor);

            // draw filled oval using current x and y coordinates and diameter
            g.fillOval(ball.x, ball.y, ball.diameter, ball.diameter);

        } // end for

    } // end paint
}

class Ball {

    int x, y, // coordinates of upper-left corner of circle
        diameter, // circle diameter
        deltaX, deltaY; // number of pixels ball moves each time it's repainted
    Color ballColor;


    public Ball(int x, int y, int diameter, int deltaX, int deltaY,
                Color ballColor) {

        this.x = x;
        this.y = y;
        this.diameter = diameter;
        this.deltaX = deltaX;
        this.deltaY = deltaY;
        this.ballColor = ballColor;

    } // end Ball constructor


    public void move() {

        // update x and y coordinates using delta values
        x += deltaX;
        y += deltaY;

        // reverse x direction when ball reaches boundary
        if (x >= BouncingBalls.width - diameter || x <= 0){
            deltaX = -deltaX;
        } // end if

        // reverse y direction when ball reaches boundary
        if (y >= BouncingBalls.height - diameter || y <= 0) {
            deltaY = -deltaY;
        } // end if

    } // end move

} // end BouncingBalls
4

1 に答える 1

6

forwhile(true)ループの外側にいる必要があります。イテレータから返された最初のボールの上にあります。

そうは言っても、スレッドごとに1つのボールのロジックを確認することをお勧めします。実際には、N個のスレッド(Nはボールの数)を作成し、各スレッドが1つではなくすべてのボールを移動するように見えます。

私の2番目のポイントに対処するために編集します:

あなたが10個のボールを持っているとしましょう。10個のスレッドを開始し、各スレッドがすべてのボールを繰り返します。

例えば:

Thread 1:
public void run(){
   for(Ball b : ballList){
      b.move();
      b.repaint();
   }
}

Thread 2:
public void run(){
   for(Ball b : ballList){
      b.move();
      b.repaint();
   }
}

Thread N:
public void run(){
   for(Ball b : ballList){
      b.move();
      b.repaint();
   }
}

これはthis、各ボールを反復処理するランナブルの同じインスタンスでスレッドを作成するために行われます。

 public void start() {

        for (Ball ball: ballList) {

            Thread t;
            t = new Thread(this);
            t.start();

        } // end for

    } // end start

ですから、各ボールが20ミリ秒ごとに1ユニット移動するとしたら、私は思います。20ミリ秒ごとにN*1ユニットが移動するのを確認する必要があります。この場合、20ミリ秒ごとに10ユニット移動します。

編集-提案に関して。

Runnableとして設定する代わりにthis、Runnableの実装をthisクラスから削除し、単一のBallをパラメーターとして受け取る新しいRunnableを作成する必要があります。

private static class MovingRunnable implements Runnable{
   private final Ball b;
   private MovingRunnable(Ball b){this.b=b;}
   public void run(){
      for(;;){
         b.move(); 
         b.repaint();
         Thread.sleep(20);
      }
   }
}

startメソッドの後半

public void start() {
        for (Ball ball: ballList) {
            Thread t;
            t = new Thread(new MovingRunnable(ball));
            t.start();
        } // end for

    } // end start

したがって、ここでは、各ボールに独自のスレッドがあり、独自のランナブルがあります。各ボールはmove、20ミリ秒ごとにスレッドごとに1回だけ呼び出すようになりました。

repaintただし、UIスレッドによってのみ呼び出される必要があるため、まだ完全ではありません。各スレッドによって呼び出されると、さまざまな問題が発生する可能性があります(気付かないかもしれませんが、言うだけの価値があります)。

于 2013-02-25T17:18:06.493 に答える