How to use the timer class in Java

advertisements

I am struggling in figuring out how the timer class works and I can use it. I looked online for answers though I couldent find an explanation that was easy enough for a beginner like me. I would very much appreciate if someone either sent a link for a great timer class tut , or maybe even explain to me what I should do in my code. Thanks!

    public class movement {
    private JComponent jt; // the JLabel (my game character)
    private InputMap ip;
    private ActionMap ap;
    private String comm; // the ActionMapKey
    private KeyStroke key;
    private int movement;
public movement(JComponent jt, InputMap ip,ActionMap ap, String comm,KeyStroke key,int movement){
    this.jt = jt;
    this.ip = ip;
    this.ap= ap;
    this.comm = comm;
    this.key = key;
    this.movement = movement;
}
public void newAction(){
    this.ip  = this.jt.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
    this.ip.put(key, comm);
    this.ap = this.jt.getActionMap();
    this.ap.put(this.comm, new AbstractAction() {

        @Override
        public void actionPerformed(ActionEvent arg0) {
            int originaly = jt.getY();
            if(key ==  KeyStroke.getKeyStroke(KeyEvent.VK_UP,0)){

                if(originaly==jt.getY()){
                    // how do i make this action animated? i want the JLabel to look like its moving up (like a jump)
                    // after the up key is pressed
                    // i dont really understand how to use the timer class to make it animated .. thanks!
                    jt.setBounds(jt.getX(),jt.getY()+movement , 50, 50);
                    //timer pause for 0.1 secs
                    jt.setBounds(jt.getX(),jt.getY()+movement , 50, 50);
                    //timer pause for 0.1 secs...
                    // can also be in a while loop until the y is 50 higher than original y.
                }

            }
            else{
            jt.setBounds(jt.getX()+movement,jt.getY() , 50, 50);
            }
        }
    });

}
}


Okay, so you problem isn't so much the timer, it's an understanding how an animation might be achieved.

  • Animation is a change of state over time
  • A Timer is a pseudo loop which has a specified delay between iterations

Okay, so how does this help? Well, basically, you need to craft a concept of an object moving from it's current position, to a new position and back again (jump up and down)

This is where your Timer come in. The Timer provides the delay between one state and the next, which should be long enough for the user to perceive

This is a really basic example, but it demonstrates the basic principle. The key binding Action isn't responsible for changing the position, it is responsible for changing a state which is then acted upon by the Timer. Why? Imagine now you have other key bindings (left and right), they shouldn't be changing the state of the objects, as those changes could conflict. Instead, they set a state flag, which is then used to determine what should occur as the state is updated.

The object has a yPos and can be acted upon by a change value (yDelta) which affects what change is actually applied to the object. While jump is true, the object is moved to it's top most height and moved back down again. Once it completes this cycle, the jump state is reset, this means that you can't keep pressing Space to perform multiple jumps in the air ... cause that's impossible ;)

import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.io.IOException;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.KeyStroke;
import javax.swing.Timer;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class Test {

    public static void main(String[] args) throws IOException {
        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 TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private int yPos = 200;
        private int yDelta = -1;

        private boolean jump = false;

        public TestPane() {
            InputMap im = getInputMap(WHEN_IN_FOCUSED_WINDOW);
            ActionMap am = getActionMap();

            im.put(KeyStroke.getKeyStroke(KeyEvent.VK_SPACE, 0), "space");
            am.put("space", new AbstractAction() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    jump = true;
                }
            });
            Timer timer = new Timer(5, new ActionListener() {
                @Override
                public void actionPerformed(ActionEvent e) {
                    if (jump) {
                        if (yPos > 200) {
                            yPos = 200;
                            yDelta *= -1;
                            jump = false;
                        } else if (yPos < 150) {
                            yPos = 150;
                            yDelta *= -1;
                        } else {
                            yPos += yDelta;
                        }
                        repaint();
                    }
                }
            });
            timer.start();
        }

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

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            int x = (getWidth() - 5) / 2;
            g2d.fillRect(x, yPos - 10, 10, 10);
            g2d.dispose();
        }

    }

}

Lots of boring theory

TL;DR

Now, this is an overly simplified example, it doesn't discuss things like framerates, easements or gravity to name a few things. You could have a look at this example which demonstrates the concept of a variable delta which degrades over a time, applying a (very basic) concept of gravity.

There are other ways to achieve similar results, depending on what you want to do, but they revolve around the same concept.

If you're really brave, you could have a look at How can I implement easing functions with a thread which discuess (rather poorly IMHO) the concept of easement - or variable speed animation. You could also have a look at Java image move along points in list and use linear interpolation which talks more about variable animation paths - where t (time) is variable, which allows you to calculate a value for you animation based on how long it's been playing and how long you would like it to play.

If you're wondering why I'd mention it - it's because you can do things like this which greatly expands what you can do.

But, at the heart of all these things, is a Timer