Introduction:
In this tutorial, I will show you how to animate Images in terms of direction in Java using the Swing Timer. For those that are perhaps novice to what is animation, animation is the process whereby a Image seemingly moves across the screen. In the programming world, the Image is being updated to a new position so fast that it fakes regular movement.
What is a timer and what is its use?
A timer is generally used as a way of checking data at regular intervals. If we apply this to a game, it can be very useful. Certain elements of a game generally have to be constantly checked and certain tasks generally have to be constantly done such as collision detection and drawing the units to the screen.
A swing timer can be used to schedule tasks as described above at regular or arbitrary intervals with a single thread. It is a class part of the javax.swing libraries.. The Swing Timer schedules actions via actionPerformed @ specific intervals as will be shown soon. This is generally perfect for Animation and GUI Related tasks.
Timer Logic:
As it is with most that are new to a concept, some questions come to mind. Some of the most common are:
How Do I Implement a Swing Timer:
The simplified steps of this would be:
1) Create a new action or class that instantiates the Timer Class.
2) Code functionality into the action or class
3) Call the timer
Where do I call my Swing Timer:
It really depends on the situation, however if it used for something like updating an Image that is immediately drawn
to the screen upon start up of the Swing application. I would suggest calling it in the constructor of your Swing Application.
How many times per second should I call it?:
Again this depends on what you are doing, if you are checking collision detection or painting something to a screen. Generally you want the timer to update many times a second, something like 15 millisecond intervals should be okay and will equate to around 66 Frames Per Second (FPS).
Now lets get into the code. There are three parts to our Ball Animation Project:
Ball - used to create features of a ball on screen, namely X and Y Positions
MainFrame - JFrame used to display our MainPanel JPanel so we do not have to use an applet.
MainPanel - JPanel that is used for drawing and animating of the "ball", Swing Timer is in here.
Now here is our code, I have purposely left out explanatory comments here here so that I can dissect the program with you afterwards however some self-documenting comments are in the listings below and a fully commented version of this program will be available at the end of the tutorial
Ball.java:
public class Ball {
/*
* Simple Object class to store the ball's co-ordinates.
*/
private int x;
private int y;
Ball() {
;
} // default constructor
public int getX() { // accessor/GET method for data
return x;
}
public void setX(int x2) { // mutator/SET method for data
x = x2;
}
public int getY() {
return y;
}
public void setY(int y2) {
y = y2;
}
}
MainFrame.java:
import java.awt.Panel;
import javax.swing.*;
public class MainFrame extends JFrame {
// Simple Object class used to add our MainPanel to a JFrame so that it can
// be displayed without the use of an applet.
MainPanel mPanel;
MainFrame() {
setTitle("Ball animation");
mPanel = new MainPanel();
setSize(350, 250);
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
add(mPanel); // add MainPanel JPanel to JFrame
setVisible(true); // show class
}
public static void main(String[] args) {
new MainFrame();
}
}
MainPanel.java:
//required libraries:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import javax.swing.*;
public class MainPanel extends JPanel { // inherit JPanel
Image ballImage; // Reserve memory for Image ballImage;
Ball currentBall = new Ball(); // instantiate our ball class
// Constructor:-----------------------------------------------------
public MainPanel() {
ImageIcon ball_IMG_ICON = new ImageIcon("ball.png");
ballImage = ball_IMG_ICON.getImage(); // get ImageIcon ball_IMG_ICON and
// store it in Image ballImage
prepareImage(ballImage, this);
currentBall.setX(10);
currentBall.setY(10); // set currentBall's X and Y Position
setDoubleBuffered(true);
new Timer(15, paintTimer).start();
}
// ----------------------------------------------------------------
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2d = (Graphics2D) g;
g2d.drawImage(ballImage, currentBall.getX(), currentBall.getY(), this); //Draws the ball Image at the correct X and Y co-ordinates.
Toolkit.getDefaultToolkit().sync(); // necessary for linux users to draw and animate image correctly
g.dispose();
}
Action paintTimer = new AbstractAction() { // functionality of our timer:
public void actionPerformed(ActionEvent e) {
// set X and Y co-ordinates that will then be fetched when drawing
// the ball Image on the JPanel.
currentBall.setX(currentBall.getX() + 5);
currentBall.setY(currentBall.getY() + 5);
repaint();
}
};
}
Dissecting the code:
Lets first start with ball.java:
The class simply contains two private integers namely x and y that are used to store the ball's position on screen and that have accessors/mutators or GETTERS/SETTERS to access and change the information as this will be necessary when redrawing the ball Image.
Well that was simple enough... Now for MainFrame.java:
Our MainFrame.java class contains the main method and this is the class that is called first. We simply add our MainPanel (JPanel Component) to our JFrame container via:
MainPanel mPanel = new MainPanel();
and then set some mundane information about the JFrame namely (note the comments if you are unsure of what the methods do):
setTitle("Ball Animation"); //You guessed it, this sets the Title of our Swing Application to Ball Animation
setSize(350,250); //sets Size of JFrame, 350 pixels wide by 250 pixels high
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); //EXITS the program when you click the "X" button
add(mPanel); //adds our MainPanel object
setVisible(true); //shows the MainFrame
Now for the actual animation, lets look at our JPanel MainPanel.java:
We firstly create a Image data structure for the ball Image and instantiate our ball class with the handle of currentBall
Image ballImage; ball currentBall = new Ball();
We then proceed to load the image via the following:
ImageIcon ball_IMG_ICON = new ImageIcon("ball.png");
ballImage= ball_IMG_ICON.getImage(); //get ImageIcon ball_IMG_ICON and store it in Image ballImage
prepareImage(ballImage, this);
We then set the starting position of currentBall namely to 10,10 from the Top Left Corner:
currentBall.setX(10); currentBall.setY(10); //set currentBall's X and Y Position
The next statement is very important if you are drawing loads of things at once and I included this as it is necessary knowledge:
setDoubleBuffered(true);
Application will use buffers this is efficient as in this case the drawing is done in memory and then
copied to the screen which can speed up our program although once again due to today's hardware features most Computer Systems will not lag running a program like this however this method is essential when you are drawing and animating many things at once especially to avoid flickering. For more on buffers, see this Link.
Next we create a Swing Timer that will perform the action we describe later in the program and how often we call it:
new Timer(15, paintTimer).start();
Here is a breakdown of the parameters/methods used:
- new Timer(:
create Timer, call it in constructor of MainPanel(). - 15,:
15 = time between next call, measured in milliseconds. Decreasing this value can smooth
animation but means your application requires more memory and processing to constantly paint, generally not a big issue today however. A interval of 15 milliseconds equates to 66 or so fps when drawing the image(s) which is more than acceptable for most applications.
paintTimer):
paintTimer refers to the action method that we are going to call- .start();:
start() obviously starts our Timer
Hence the final statement is: create Timer(15, paintTimer).start();
Now onto the paint method, this is overridden from the java.awt.component and is called every time we use repaint(). The comments explain the relevant code:
public void paint(Graphics g) { super.paint(g); //we repaint the JPanel and clear old images otherwise the previous image and new image would overlap Graphics2D g2d = (Graphics2D)g; //creates a Graphics2D element which we use for drawing g2d.drawImage(ballImage, currentBall.getX(), currentBall.getY(), this);//paint ballImage @ currentBall's X and Y position Toolkit.getDefaultToolkit().sync(); //This if for linux systems, it synchronizes the painting otherwise it would not be smooth. g.dispose(); }
Now for the action method. This is the functionality of our Swing Timer, without this method. There would be no point to the timer. The method is actually really simplistic and simply increases the Ball's X and Y values and then repaints the JPanel whenever it is called:
Action paintTimer = new AbstractAction() { public void actionPerformed(ActionEvent e) {//functionality of our timer: //set X and Y co-ordinates that will then be fetched when drawing the ball Image on the JPanel. currentBall.setX(currentBall.getX() + 5); currentBall.setY(currentBall.getY() +5); repaint(); } };
Here is an example of what will be displayed on the screen:

I hope you have enjoyed this tutorial, It simply animates a image across a screen but can be extended to do much more such as move a player across a screen. The full commented code listing of MainPanel.java can be found below, this was the only class I removed essential comments out of for explanation.
MainPanel.java With comments:
//required libraries:
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import javax.swing.*;
public class MainPanel extends JPanel {
Image ballImage;
Ball currentBall = new Ball(); // instantiate our ball class
public MainPanel() {
ImageIcon ball_IMG_ICON = new ImageIcon("ball.png");
ballImage = ball_IMG_ICON.getImage(); // get ImageIcon ball_IMG_ICON and
// store it in Image ballImage
prepareImage(ballImage, this);
currentBall.setX(10);
currentBall.setY(10); // set currentBall's X and Y Position
setDoubleBuffered(true);
/*
* Application will use buffers this is efficient as in this case the
* drawing is done in memory and then copied to the screen which can
* speed up our program although once again due to today's hardware
* features most Computer Systems will not lag running a program like
* this however this method is essential when you are drawing and
* animating many things at once.
*/
new Timer(15, paintTimer).start();
/*
* create Timer, call it in constructor of MainPanel() 15 = time between
* next call, measured in milliseconds. Decreasing this value can smooth
* animation but means your application requires more memory and
* processing to constantly paint, generally not a big issue today
* however. 15 millisecond interval equates to around 66 fps. paintTimer
* refers to the action method that we are going to call start()
* obviously starts our Timer
*/
// call paintTimer's action every 15 milliseconds
}
public void paint(Graphics g) {
super.paint(g); // we repaint the JPanel and clear old images otherwise
// the previous image and new image would overlap
Graphics2D g2d = (Graphics2D) g; // creates a Graphics2D element which
// we use for drawing
g2d.drawImage(ballImage, currentBall.getX(), currentBall.getY(), this);// paint
// ballImage
// @
// currentBall's
// X
// and
// Y
// position
Toolkit.getDefaultToolkit().sync(); // This is for linux systems, it
// synchronizes the painting
// otherwise it would not be smooth.
g.dispose();
}
Action paintTimer = new AbstractAction() {
public void actionPerformed(ActionEvent e) {// functionality of our
// timer:
// set X and Y co-ordinates that will then be fetched when drawing
// the ball Image on the JPanel.
currentBall.setX(currentBall.getX() + 5);
currentBall.setY(currentBall.getY() + 5);
repaint();
}
};
}
I hope you have enjoyed this tutorial, thanks
v0rtex
This post has been edited by v0rtex: 19 June 2011 - 05:04 AM






MultiQuote





|