-3

I'm trying to create a program that would have 2 balls drawn, with one at the North center and the other at the south center. I am required to move the balls in different directions with the first ball at the North moving randomly towards south and the other ball at the south center to move towards the North. I can make the North Center ball move downwards but the second ball at the South disappears right after it is drawn.

PS: I need to have 2 inner class which is Ball1 and Ball2. Please help. Many thanks.

Cole Tobin
  • 9,206
  • 15
  • 49
  • 74
poiuytrewq
  • 1
  • 1
  • 3
  • 2
    Why do you *need* to have two inner classes? – Nathaniel Waisbrot Mar 12 '13 at 03:52
  • 1
    Your code indentations are all over the place. Please understand that you're asking volunteers to put in effort and time help you. When doing this we greatly appreciate it if *you* first put the effort into posting well-formatted code. Why make it difficult for us to read and understand the code you've posted? – Hovercraft Full Of Eels Mar 12 '13 at 03:52
  • classes are not meant to be used in this way. You should pass the color to the constructor of the class, and merge `Ball1` and `Ball2` – Careal Manic Mar 12 '13 at 03:53
  • Also, `x` and `y` should be a member of `Ball` . – Careal Manic Mar 12 '13 at 03:54
  • I suggest that you delete the code above and start over as it is no where near what you want to do. For instance you are calling `Thread.sleep(...)` in a `paintComponent(...)` method, something that should never be done. Please search through this site for examples of Swing animation that uses a Swing Timer since that is what you want to do. Either that or a background thread, but *never* call `sleep(...)` on the Swing thread and never especially in a paint method. – Hovercraft Full Of Eels Mar 12 '13 at 03:56
  • Also I see that you've tagged your question as involving multi-threading, but no-where in your code do you actually do multi-threading. – Hovercraft Full Of Eels Mar 12 '13 at 04:12
  • The reason i have 2 inner class is the requirements of my program. Sorry for the mess of the codes. – poiuytrewq Mar 12 '13 at 04:31

1 Answers1

3

Problems...

  1. while-loop in the Event Dispatching Thread which adjusts the positions of graphics objects
  2. Thread.sleep in paint methods.
  3. Not calling super.paintComponent
  4. Updating the state of an object in the paintComponent method.

Swing uses a single thread model that is responsible for, amongst other things, dispatching repaint requests to all the components.

Performing any operation in the EDT that stops from processing these events, will prevent Swing from repainting the UI. This will make it look like your animation has suddenly gone from the start to the end in a single step.

Take a look at Concurrency in Swing for more details. In particular, take a look at Initial Threads and How to use Swing Timers

I should highlight point 4-

You do not control the repaint cycle. Repaint requests may be raised for a number of reasons, that you didn't ask for, these will cause your objects to be updated beyond your control or when you don't want them to be. You should never change the state of any part of your UI from within any paint method.

Simple Example

This is a very simple example, but it demonstrates the basic concepts you need to understand in order to do any animation in Swing

public class SimpleBouncyBall {

    public static void main(String[] args) {
        new SimpleBouncyBall();
    }

    public SimpleBouncyBall() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (Exception ex) {
                }

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.add(new CourtPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class CourtPane extends JPanel {

        private Ball ball;
        private int speed = 5;

        public CourtPane() {
            Timer timer = new Timer(40, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    Rectangle bounds = new Rectangle(new Point(0, 0), getSize());
                    if (ball == null) {
                        ball = new Ball(bounds);
                    }
                    speed = ball.move(speed, bounds);
                    repaint();
                }
            });
            timer.setRepeats(true);
            timer.setCoalesce(true);
            timer.start();
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(100, 100);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g); 
            if (ball != null) {
                Graphics2D g2d = (Graphics2D) g.create();
                g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
                Point p = ball.getPoint();
                g2d.translate(p.x, p.y);
                ball.paint(g2d);
                g2d.dispose();
            }
        }

    }

    public class Ball {

        private Point p;
        private int radius = 12;

        public Ball(Rectangle bounds) {

            p = new Point();
            p.x = 0;
            p.y = bounds.y + (bounds.height - radius) / 2;

        }

        public Point getPoint() {
            return p;
        }

        public int move(int speed, Rectangle bounds) {

            p.x += speed;
            if (p.x + radius >= (bounds.x + bounds.width)) {

                speed *= -1;
                p.x = ((bounds.x + bounds.width) - radius) + speed;

            } else if (p.x <= bounds.x) {

                speed *= -1;
                p.x = bounds.x + speed;

            }

            p.y = bounds.y + (bounds.height - radius) / 2;

            return speed;

        }

        public void paint(Graphics2D g) {
            g.setColor(Color.RED);
            g.fillOval(0, 0, radius, radius);
        }

    }

}
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366