repeating animation using java.swingTimer

2019-08-20 04:51发布

问题:

I am writing the code of Game bean machine (Galton box) using animated graphics. I am using swing.Timer to make the red ball move, by letting the Timer object take an ActionListener.

Here is the output: The red ball here is moving randomly : http://imgur.com/J9Xq0t5&HIv1udp And here it reaches the bottom: http://imgur.com/J9Xq0t5&HIv1udp#1

The problem is that I want to make several balls moving not only 1 but I actually cannot, I tried to put the Timer object in a loop but it only speeded up the ball motion.

Here is the code I wrote:

import java.awt.*;
import java.awt.event.*;
import java.util.Random;
import java.util.Scanner;
import javax.swing.*;


public class GameBean extends JFrame{
private int nSlots;
private int balls;

public GameBean (int nSlots, int balls){
    this.balls=balls;
    this.nSlots=nSlots;
    Timer timer=new Timer(500,new RandomListener());

    timer.start();

    JPanel panel = new JPanel();

    this.add(canvas); 
}

Ball canvas = new Ball();


 public static void main(String[] args) {

    Scanner input=new Scanner(System.in);

    System.out.println("Please enter number of slots: ");
    int nSlots=input.nextInt();

    JFrame frame = new GameBean (nSlots, 5);

    frame.setTitle("Bean Game Machine");
    frame.setLocationRelativeTo(null);
    frame.setDefaultCloseOperation(EXIT_ON_CLOSE);
    frame.setSize(300, 500);
    frame.setVisible(true);

   }
 class RandomListener implements ActionListener {
    public void actionPerformed(ActionEvent e) {
         canvas.moveRandom();
    }
}


class Ball extends JPanel{
    Random rand=new Random();
    private int n;
    private int raduis = 10;
    private int moveRaduis=12;
    private int L = 0;
    private int R = 0;
    private int D = 0;


    protected void paintComponent(Graphics g) {
        super.paintComponent(g);

        g.setColor(Color.RED);

        g.fillOval(getWidth()/2 -raduis/2  + R + L, 0 + D , moveRaduis, moveRaduis);

        repaint();
        int  i=0;
        int width=(getWidth()/8);
        int space=(getWidth()-nSlots*30)/2;
        g.setColor(Color.BLACK);
        for(i=0;i<=nSlots;i++){
            g.drawLine(space+(30*i),getHeight()-balls*(raduis) ,space+(30*i) ,getHeight() );
            if(i!=0 && i!=nSlots)
                g.fillOval(space+(30*i)-5, getHeight()-balls*(raduis)-5, 10, 10);
            if(i==0){
                g.drawLine(space,getHeight()-balls*(raduis) , space+((nSlots)*15)-(raduis/2)-15 , getHeight()-15-(balls*raduis)-(30*(nSlots-2))-raduis/2);
                g.drawLine(space+((nSlots)*15)-(raduis/2)-15 , getHeight()-15-(balls*raduis)-(30*(nSlots-2))-raduis/2 , space+((nSlots)*15)-(raduis/2)-15 , getHeight()/2-nSlots*nSlots);//vertical line

            }
            if(i==nSlots){
                g.drawLine(space+(30*i), getHeight()-balls*(raduis), space+((nSlots)*15)+(raduis/2)+15, getHeight()-15-(balls*raduis)-(30*(nSlots-2))-raduis/2);
                g.drawLine(space+((nSlots)*15)+(raduis/2)+15 , getHeight()-15-(balls*raduis)-(30*(nSlots-2))-raduis/2 , space+((nSlots)*15)+(raduis/2)+15 , getHeight()/2-nSlots*nSlots);//vertical line

            }

        }


        int o=1;
        for(i=1;i<=nSlots-2;i++){
            int k=2;
            for(int j=i;j<=nSlots-2;j++){
                g.fillOval(space+((i+k)*15)-raduis/2, getHeight()-(balls*raduis)-(30*o)-raduis/2, raduis, raduis); 
                k=k+2;   
             }o++;
        }

      }

    public void moveRandom(){

        n=1+rand.nextInt(100);
        if(n<=51){
            D+=15;

            if(D<=(getHeight()-15-(balls*raduis)-(30*(nSlots-2))-raduis/2))//if(D<=14*15)
                L=0;
            else if(D>getHeight()-15-(balls*raduis)-(30*(nSlots-2))-raduis/2 && D<getHeight()-balls*(raduis))
            {
                D+=15;
                L-=15;

            }
            else if(D>=getHeight()-balls*(raduis))
            {
                if(D==31*15)D-=15;
                D=D;

            }

        }
        else if (n>=51 && n<=100){
            D+=15;
            if(D<=getHeight()-15-(balls*raduis)-(30*(nSlots-2))-raduis/2)
                R=0;
            else if(D>getHeight()-15-(balls*raduis)-(30*(nSlots-2))-raduis/2 && D<getHeight()-balls*(raduis))
                {
                D+=15;
                R+=15;
            }
            else if(D>=getHeight()-balls*(raduis)){

                if(D==31*15)D-=15;
                D=D;

            }

        }

    }
    } 

    }

Any HELP please ! Thanks all..

回答1:

Here's a suggestion.

Don't make each ball extends JPanel. Just make it a class for holding/manipulating/drawing the state.

Ball.java (notice Java naming convention)

public class Ball {
    int x, y; // and whatever other state you need

    public Ball(int x, int y {}  // or however you want to construct the ball

    public void draw(Graphics g) {
        // draw ball here
    }
    public void move() {
        // do calculations to move here
    }
}

Then just have one BallPanel class that extends JPanel and do the painting there. Just hold a List<Ball> in the class and you can call each Ball's draw() method in the paintComponent and each Ball's move() method in the Timer. You could even dynamically add balls to be animated by just adding a new Ball to the list. Something like

public class BallPanel extends JPanel {
    private List<Ball> balls;  // create the list

    public BallPanel() {
        Timer timer = new Timer(40, new ActionListener(){
            public void actionPerformed(ActionEvent e) {
                for (Ball ball: balls) {
                    ball.move();
                }
                repaint();
            }
        });
    }

    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        for (Ball ball : balls) {
            ball.draw(g);
        }
    }
}

This way you don't have to worry above separate timers and layering panels.

See a bunch of complete example, using this technique, here and here and here and here and here and here.