1

I've written the following code

   import java.awt.BorderLayout;
import java.awt.Graphics;

import javax.swing.JFrame;
import javax.swing.JPanel;

final public class Test
{

    JFrame frame;
    DrawPanel drawPanel;
    boolean up = false;
    boolean down = true;
    boolean left = false;
    boolean right = true;
    private int timeStep = 0;
    private int ballYTravel = 100;
    private int BALL_NUM = 24;

    public static void main(String... args)
    {
        new Test().go();
    }

    private void go()
    {
        frame = new JFrame("Test");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        drawPanel = new DrawPanel();

        frame.getContentPane().add(BorderLayout.CENTER, drawPanel);

        frame.setResizable(false);
        frame.setSize(800, 600);
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
        moveIt();
    }

    class DrawPanel extends JPanel
    {
        private static final long serialVersionUID = 1L;
        public double getY(int i, int t) {
            return 200 + ballYTravel / 2 * (Math.sin(timeStep * (i / 200 + 0.08)));
        }

        public void paintComponent(Graphics g)
        {    
            for (int k = 0; k < BALL_NUM; k++ ) {
                g.fillRect(100  + 20 *k , (int) getY(k, timeStep), 6, 6);
            }
            timeStep++;

        }
    }



    private void moveIt()
    {
        while (true)
        {

            try
            {
                Thread.sleep(10);
            }
            catch (Exception e)
            {
                e.printStackTrace();
            }
            frame.repaint();
        }
    }
    }

It runs and animates, however it is not animating in the same fashion as the Javascript code I referenced it from which can be found here http://codepen.io/anon/pen/ZYQoQZ

any help in understanding why is appreciated

user3037561
  • 271
  • 2
  • 10
  • `"...however it is not animating in the same fashion..."` -- can you be a bit more descriptive? – Hovercraft Full Of Eels Dec 08 '14 at 22:34
  • Note -- you should use a Swing Timer to drive your animation, not a while-true loop with Thread.sleep. That way spells threading disaster. – Hovercraft Full Of Eels Dec 08 '14 at 22:35
  • The link can be found in the [swing info](http://stackoverflow.com/tags/swing/info) tab. – Hovercraft Full Of Eels Dec 08 '14 at 22:40
  • @HovercraftFullOfEels the aniamtion present in the Swing application simply moves up and down, while the Javascript version with almost identical code (look at the codepen) move about on both axis – user3037561 Dec 08 '14 at 22:53
  • 1
    You need to get all animation code out of paintComponent and into your [Swing Timer](http://docs.oracle.com/javase/tutorial/uiswing/misc/timer.html). The paintComponent method should just paint the ball once and that's it, without a for loop (unless you're drawing multiple balls simultaneously). Also see [this link](http://stackoverflow.com/questions/9849950). – Hovercraft Full Of Eels Dec 08 '14 at 22:56
  • Is your goal to draw 12 balls? If so, then keep your for loop. Note A) that there is no code present that would give your animation any x-axis translation, i.e., you have no `getX(...)` method, B) javascript animation is done completely differently and so you can't borrow code from JS and use it in Swing. Also, please clarify just what animation effect you're trying to achieve. – Hovercraft Full Of Eels Dec 08 '14 at 23:04
  • 1
    A working example and several variations are examined in this possible [duplicate](http://stackoverflow.com/q/9849950/230513). – trashgod Dec 08 '14 at 23:07
  • @HovercraftFullOfEels: D'oh, I should have looked under "Linked." :-) – trashgod Dec 08 '14 at 23:29
  • @HovercraftFullOfEels What do you mean clarify? I'm trying to achive the same animation effect as the codepen I linked. I put the code into a Swing Timer and the effects are still the same. Also I don't need a getX, which is visible in the code, the x axis is 100 + 20 * k, I convered that JS code from ActionScript, I also converted it to C# and it worked alright too. There isn't any reason simple math shouldn't work with Swing. – user3037561 Dec 08 '14 at 23:32
  • Kudos for a [complete example](http://stackoverflow.com/help/mcve). – trashgod Dec 09 '14 at 12:40

2 Answers2

5

Your transliteration reveals several problems:

Revised code, incorporating @Mad's fix and using drawOval():

import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;

final public class Test {

    JFrame frame;
    DrawPanel drawPanel;
    private int timeStep = 0;
    private int ballYTravel = 100;
    private int BALL_NUM = 24;

    public static void main(String... args) {
        new Test().go();
    }

    private void go() {
        EventQueue.invokeLater(new Runnable() {

            @Override
            public void run() {
                frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                drawPanel = new DrawPanel();
                frame.add(BorderLayout.CENTER, drawPanel);
                frame.setResizable(false);
                frame.pack();
                frame.setLocationByPlatform(true);
                frame.setVisible(true);
                Timer t = new Timer(10, new ActionListener() {

                    @Override
                    public void actionPerformed(ActionEvent e) {
                        drawPanel.repaint();
                    }
                });
                t.start();
            }
        });
    }

    private class DrawPanel extends JPanel {

        public double getY(int i, int t) {
            return 200 + ballYTravel / 2 * (Math.sin(t * (i / 200d + 0.08)));
        }

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            for (int k = 0; k < BALL_NUM; k++) {
                g.drawOval(100 + 20 * k, (int) getY(k, timeStep), 8, 8);
            }
            timeStep++;
        }

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

    }
}
Community
  • 1
  • 1
trashgod
  • 203,806
  • 29
  • 246
  • 1,045
5

There are (possibly) two basic problems...

  1. In getY, you are ignoring the parameter t and using timeStep instead, while, technically, this probably isn't going to make a MASSIVE difference, it is an area of concern
  2. You have an integer division issue. i/200 will result in int result, where you really want a double. Change it to i/200d

For example...

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

final public class Test {

    private int timeStep = 0;
    private final int ballYTravel = 100;
    private final int BALL_NUM = 24;

    public static void main(String... args) {
        new Test();
    }

    public Test() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    ex.printStackTrace();
                }

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

    class DrawPanel extends JPanel {

        private static final long serialVersionUID = 1L;

        public DrawPanel() {
            new Timer(10, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    timeStep++;
                    repaint();
                }
            }).start();
        }

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

        public double getY(int i, int t) {
            return 100 + ballYTravel / 2 * (Math.sin(t * (i / 200d + 0.08)));
        }

        @Override
        public void paintComponent(Graphics g) {
            super.paintComponent(g);
            for (int k = 0; k < BALL_NUM; k++) {
                g.fillRect(10 + 20 * k, (int) getY(k, timeStep), 6, 6);
            }

        }
    }
}

You're also breaking the paint chain, which is going to cause you issues in the long run, make sure you are calling super.paintComponent...

For more details see...

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366