1

I have my program running where I have a variable radius so that the balls can be of a size int, but I would like to know how to make this program more complex with adding random sizes of balls. small,medium,big etc. On line 148 I tried changing it to int radius = (int)(5*Math.random); but it did not work. Must I do something else to my code in order for this to work? And if there are any other hints you may have, they'd be much appreciated. Thanks

import javax.swing.Timer;
import java.util.ArrayList;
import java.awt.*;
import javax.swing.*;
import java.awt.event.*;

public class MultipleBallApp extends JApplet 
{
  public MultipleBallApp() 
  {
    add(new BallControl());
  }

  class BallControl extends JPanel {
    private BallPanel ballPanel = new BallPanel();
    private JButton jbtSuspend = new JButton("Suspend");
    private JButton jbtResume = new JButton("Resume");
    private JButton jbtAdd = new JButton("+1");
    private JButton jbtSubtract = new JButton("-1");
    private JScrollBar jsbDelay = new JScrollBar();

    public BallControl() {
      // Group buttons in a panel
      JPanel panel = new JPanel();
      panel.add(jbtSuspend);
      panel.add(jbtResume);
      panel.add(jbtAdd);
      panel.add(jbtSubtract);

      // Add ball and buttons to the panel
      ballPanel.setBorder(new javax.swing.border.LineBorder(Color.red));
      jsbDelay.setOrientation(JScrollBar.HORIZONTAL);
      ballPanel.setDelay(jsbDelay.getMaximum());
      setLayout(new BorderLayout());
      add(jsbDelay, BorderLayout.NORTH);
      add(ballPanel, BorderLayout.CENTER);
      add(panel, BorderLayout.SOUTH);

      // Register listeners
      jbtSuspend.addActionListener(new Listener());
      jbtResume.addActionListener(new Listener());
      jbtAdd.addActionListener(new Listener());
      jbtSubtract.addActionListener(new Listener());
      jsbDelay.addAdjustmentListener(new AdjustmentListener() 
      {
        @Override
        public void adjustmentValueChanged(AdjustmentEvent e) {
          ballPanel.setDelay(jsbDelay.getMaximum() - e.getValue());
        }
      });
    }

    class Listener implements ActionListener 
    {
      @Override
      public void actionPerformed(ActionEvent e) {
        if (e.getSource() == jbtSuspend) 
          ballPanel.suspend();
        else if (e.getSource() == jbtResume) 
          ballPanel.resume();
        else if (e.getSource() == jbtAdd) 
          ballPanel.add();
        else if (e.getSource() == jbtSubtract) 
          ballPanel.subtract();
      }
    }
  }

  class BallPanel extends JPanel 
  {
    private int delay = 10;
    private ArrayList<Ball> list = new ArrayList<Ball>();

    // Create a timer with the initial dalay
    protected Timer timer = new Timer(delay, new ActionListener() {
      @Override /** Handle the action event */
      public void actionPerformed(ActionEvent e) 
      {
        repaint();
      }
    });

    public BallPanel() 
    {
      timer.start();
    }

    public void add() 
    {
      list.add(new Ball());
    }

    public void subtract() 
    {
      if (list.size() > 0)
        list.remove(list.size() - 1); // Remove the last ball
    }

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

      for (int i = 0; i < list.size(); i++) 
      {
        Ball ball = (Ball)list.get(i); // Get a ball
        g.setColor(ball.color); // Set ball color

        // Check boundaries
        if (ball.x < 0 || ball.x > getWidth()) 
          ball.dx = -ball.dx;

        if (ball.y < 0 || ball.y > getHeight()) 
          ball.dy = -ball.dy;

        // Adjust ball position
        ball.x += ball.dx;
        ball.y += ball.dy;
        g.fillOval(ball.x - ball.radius, ball.y - ball.radius, 
          ball.radius * 2, ball.radius * 2);
      }
    }

    public void suspend() 
    {
      timer.stop(); 
    }

    public void resume() 
    {
      timer.start(); 
    }

    public void setDelay(int delay) 
    {
      this.delay = delay;
      timer.setDelay(delay);
    }
  }

  class Ball 
  {
    int x = 0;
    int y = 0; // Current ball position
    int dx = 10; // Increment on ball's x-coordinate
    int dy = 10; // Increment on ball's y-coordinate
    int radius = 5; // Ball radius
    Color color = new Color((int)(Math.random() * 256),
        (int)(Math.random() * 256), (int)(Math.random() * 256));
  }

  /** Main method */
  public static void main(String[] args) 
  {
    JFrame frame = new JFrame();
    JApplet applet = new MultipleBallApp();
    frame.add(applet);
    frame.setTitle("MultipleBallApp");
    frame.setLocationRelativeTo(null); // Center the frame
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setSize(400, 200);
    frame.setLocationRelativeTo(null); // Center the frame
    frame.setVisible(true);
  }
}
ttrigger10
  • 32
  • 5
  • 1
    What does "did not work" mean? Also, assuming you mean `Math.random() * 5`, that will return 0, 1, 2, 3, or 4. Is that what you want? – blm Nov 20 '15 at 18:38
  • 1
    Try `int radius = (int)(5*Math.random()+1);`, that way you never get a radius of 0. Or if you want the max size to be 5 `int radius = (int)(4*Math.random()+1);` – gonzo Nov 20 '15 at 18:38
  • @gonzo that worked! thank you very much! If I wanted the balls to go at different speeds(faster, slower) would I go about it the same way as I would with the radius? – ttrigger10 Nov 20 '15 at 18:41
  • @ttrigger10 yup, you should be able to randomize everything in your `Ball` class. Just keep in mind the fields that you do not want 0 and do something similar. – gonzo Nov 20 '15 at 18:43
  • 1
    `If I wanted the balls to go at different speeds(faster, slower) would I go about it the same way as I would with the radius?` - try it and see what happens. It worked for your color and the radius, why would you expect problems with another property? Try things first that is how you learn and then ask a question if it doesn't work the way you expect. – camickr Nov 20 '15 at 18:43
  • thank you again! now I've got a fun program @gonzo – ttrigger10 Nov 20 '15 at 18:47
  • thank you as well! @camickr – ttrigger10 Nov 20 '15 at 18:48
  • Also, not sure what other people think but this isn't really the best way to randomize. Getting a random decimal from 0-1 then multiplying that by an integer does not really give a uniform randomness. I would use the `Random` class instead. You can use something like `int radius = new Random().nextInt(4)+1;` to get a random number between 1-5. – gonzo Nov 20 '15 at 18:48
  • okay I will look into this! @gonzo – ttrigger10 Nov 20 '15 at 18:49
  • @gonzo It's just about the same, there really isn't much of a difference between creating one `Random` object and using it versus using `Math.random()` and using Math's Random object – phflack Nov 20 '15 at 19:26
  • @phflack Using the `Random` class is both more efficient and less biased according to [this](http://stackoverflow.com/questions/738629/math-random-versus-random-nextintint). But yeah if we are just trying to do something simple like this, probably does not matter. – gonzo Nov 20 '15 at 19:30
  • 1
    @gonzo In a case like this, twice the method calls * few method calls * almost instant time for each method call = still 0 time processing. It's just easier to use `Math.random()` for simple random numbers in a place like this. I do like how `Random.nextInt()` keeps trying until the buckets are of even size though – phflack Nov 20 '15 at 19:52

1 Answers1

1

Make sure you do not get 0 as a radius when trying to randomize the ball's radius.

int radius = (int)(4*Math.random()+1);
gonzo
  • 2,103
  • 1
  • 15
  • 27