ANIMATIONS IN JAVA
| Previous |<Graphics in Java - example |
There are several ways to create animations in the Java programming language. In the following, it will be shown how to create an animation using a timer, ie. object of class Timer from package javax.swing. The animation is explained through two examples.
The first is a free fall animation, while the second is actually a continuation of the circular motion application.
The beginning of the example is on the Graphics in Java page - example
Timer
The previous examples show drawing shapes on a panel without any animation. In order to create an animation for a certain shape to move in the two-dimensional plane of the panel, it is necessary to import an object of class Timer, which is located in the javax.swing package. A Timer object produces an event that repeats at a given time interval. In response to this event, the actionListener method is called each time, similar to clicking a button, except that the event is repeated here.If the position of a certain geometric shape, e.g. moved the circle by a certain value of dx in the x direction with each call to the actionPerformed method. for a given time interval and that circle drawn again we would get the illusion of the movement of that circle.
The timer must first be declared, usually as an attribute for the class:
Timer time;
Then you need to create a timer: int interval = 100; // in milis
timer=new Timer(interval, listener)
The timer constructor requires two parameters: the time interval in milliseconds at which the timer event is repeated and the object that implements the ActionListener interface and which represents the timer event listener. One such object is similar to the listener at the button, and that was explained earlier.timer=new Timer(interval, listener)
In order for the timer to start, it is necessary to start it:
time.start();
The timer can also be stopped if necessary:time.stop();
VIDEO LESSONS
Video 1: Timer AnimationCreate an animation Sliding a physical body on a flat surface. Use a timer to repeat the screen every 5 milliseconds. |
Video 2: Free Fall AnimationAnimation of the free fall of a physical body to the ground using a timer. The application was made using NetbeansIDE in the java programming language |
NEW CONTENT
PROCESSING
Processing is an environment that is built as a plugin for programming animations as well as visual applications, with good and easy interaction with the user. It is written in Java and can be treated as a plugin that contains support ie. An API with functions for creating animations and visual applications. It is based on writing a sketch (skatch).
Read more: Processing JAVA
Animation not working? Please refresh the page
← scroll horizontal →
How to make an application for basic animation of a body sliding down an inclined plane, where the user can only observe and not influence the animation, the possibility has now been added that by moving the square at the top of the inclined plane, the height of the inclined plane can be increased or decreased, thereby also changing the angle of inclination .
Read more on web page:
Analysis of sliding of a body down an inclined plane example
EXAMPLE: Free fall:
Task text:Simulate the free fall of a circle-shaped body
Solution:An object that represents a body will be described by the class Body that inherits Ellipse2D.Double:
public classPhysicalObjectextends Ellipse2D.Double
{
Figure 1: Creating animations in Java using a timer. Body class.The constructor with parameters gets 4 parameters that define the rectangle in which the ellipse is inscribed, ie. circle in our case.{
/*
* Atributes
*/
doublem;//mass
doublev = 0;//velocity of free fall
Color color = Color.BLUE;
/*Constructor*/
public PhysicalObject() {
}
/*Constructor with parameters*/
public PhysicalObject(double x, double y, double w, double h) {
}* Atributes
*/
doublem;//mass
doublev = 0;//velocity of free fall
Color color = Color.BLUE;
/*Constructor*/
public PhysicalObject() {
/*Constructor with parameters*/
public PhysicalObject(double x, double y, double w, double h) {
super(x, y, w, h);
}The Environment class stores environmental data: free fall path distance x, initial position H0, body radius, and current body position along the y axis.
public classTheEnvironment
{
Figure 2: Creating animations in Java using a timer. Class Environment.The object on which the animation is drawn belongs to the Animation class that inherits JPanel:{
/*
* Atributes
*/
doublex = 10;//free fall path distance
doubleH0 = 20;//initial height of free fall
doubler = 50;//radius of physical body
doubleh = 0;//current height of free fall
/*Constructor*/
public TheEnvironment {
/*Constructor with parameters*/
public PhysicalObject(double x, double y, double w, double h) {
}* Atributes
*/
doublex = 10;//free fall path distance
doubleH0 = 20;//initial height of free fall
doubler = 50;//radius of physical body
doubleh = 0;//current height of free fall
/*Constructor*/
public TheEnvironment {
h=H0;
}/*Constructor with parameters*/
public PhysicalObject(double x, double y, double w, double h) {
super(x, y, w, h);
}package freefall;
import bussines.PhysicalObject;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JPanel;
public classAnimationextends JPanel
{
Figure 3: Creating animations in Java using a timer. Animation panel.In the drawing, two objects of the physical bodyclass PhysicalObject and soil of the class Rectangle2D.Double were created, and that is the class in the java.awt.geom package. Here the y coordinate of the rectangle depends on the height of the window obtained by the getHeight () method of the object of the current class this, and the width of the ground is identical to the width of the panel, where the current width value can be obtained by the getWidth () method.import bussines.PhysicalObject;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Rectangle2D;
import javax.swing.JPanel;
public classAnimationextends JPanel
{
/*
* Atributes
*/
Rectangle2D ground;//a body that free fall from some height
PhysicalObject physicalObject = 0;//the surface of the earth on which the body will fall
/*Constructor with parameters*/
public Animation() {
}
/*A method that plots the contents of the panel*/
@Override
public void paint(Graphics g) {
/*Method that creates a ground object*/
public void create() {
}* Atributes
*/
Rectangle2D ground;//a body that free fall from some height
PhysicalObject physicalObject = 0;//the surface of the earth on which the body will fall
/*Constructor with parameters*/
public Animation() {
/*A method that plots the contents of the panel*/
@Override
public void paint(Graphics g) {
Graphics2D g2=(Graphics2D) g;
super.paint(g);
g2.setColor(new Color(200, 200, 255));
g2.fillRect(0,0, getWidth(), getHeight());
g2.setColor(new Color(20, 200, 20));
if (ground != null) {
g2.setColor(Color.BLACK);
if (physicalObject != null) {
}super.paint(g);
g2.setColor(new Color(200, 200, 255));
g2.fillRect(0,0, getWidth(), getHeight());
g2.setColor(new Color(20, 200, 20));
if (ground != null) {
g2.fill(ground);
}g2.setColor(Color.BLACK);
if (physicalObject != null) {
g2.fill(physicalObject);
}/*Method that creates a ground object*/
public void create() {
ground = new Rectangle2D.Double(0, this.getHeight()-100,
this.getWidth(), 100);
}this.getWidth(), 100);
The "paint ()" method is called to a certain number of milliseconds as a result of firing a timer event, which is created and run in the main class within the constructor:
/**
* @param args the command line arguments
*/
public static void main(String[]args) {
public FreeFallFrame() throws HeadlessException {
* @param args the command line arguments
*/
public static void main(String[]args) {
FreeFallFrame app = new FreeFallFrame();
}public FreeFallFrame() throws HeadlessException {
//The main window of the application
fr = new JFrame("Free Fall");
fr.setSize(600, 500);
fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Creates and starts a timer
time = new Timer(dt, this);
time.start();
//Creates a panel container and connects to the main window
JPanel contentPane = new JPanel();
contentPane.setLayout(new BorderLayout(2, 2));
fr.setContentPane(contentPane);
/*creates an animation panel and places it in the central part
container*/
animationPanel = new Animation();
contentPane.add(animationPanel,BorderLayout.CENTER);
/*Creates a control panel and places it in the eastern (right) part
container*/
Panel controlPanel = new Panel(new BorderLayout(2, 2));
contentPane.add(controlPanel,BorderLayout.EAST);
theEnvironment = new TheEnvironment();
physicalObject = new PhysicalObject(theEnvironment.x, theEnvironment.H0, theEnvironment.r,
theEnvironment.r);
animationPanel.physicalObject = physicalObject;
animationPanel.setSize(600, 500);
animationPanel.create();
fr.setVisible(true);
}fr = new JFrame("Free Fall");
fr.setSize(600, 500);
fr.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
//Creates and starts a timer
time = new Timer(dt, this);
time.start();
//Creates a panel container and connects to the main window
JPanel contentPane = new JPanel();
contentPane.setLayout(new BorderLayout(2, 2));
fr.setContentPane(contentPane);
/*creates an animation panel and places it in the central part
container*/
animationPanel = new Animation();
contentPane.add(animationPanel,BorderLayout.CENTER);
/*Creates a control panel and places it in the eastern (right) part
container*/
Panel controlPanel = new Panel(new BorderLayout(2, 2));
contentPane.add(controlPanel,BorderLayout.EAST);
theEnvironment = new TheEnvironment();
physicalObject = new PhysicalObject(theEnvironment.x, theEnvironment.H0, theEnvironment.r,
theEnvironment.r);
animationPanel.physicalObject = physicalObject;
animationPanel.setSize(600, 500);
animationPanel.create();
fr.setVisible(true);
animationPan.physicalObject = physicalObject;
The attributes of this class are:public class FreeFallFrame implements ActionListener {
Figure 6: Creating animations in Java using a timer. FreeFallFrame class.As attributes of this class, in addition to those already mentioned, there are also g-gravitational acceleration, dt-time interval referred to by the timer event and plotting scales.
JFrame fr;
Timer time;
private final TheEnvironment theEnvironment;
private final PhysicalObject physicalObject;
private final Animation animationPanel;
private final doubleg = 9.81;//Acceleration due to gravity
intdt = 10;//change of time in one iteration in ms
intratio = 60;
/**
* @param args the command line arguments
*/
public static void main(String[]args) {
public FreeFallFrame() throws HeadlessException {
Timer time;
private final TheEnvironment theEnvironment;
private final PhysicalObject physicalObject;
private final Animation animationPanel;
private final doubleg = 9.81;//Acceleration due to gravity
intdt = 10;//change of time in one iteration in ms
intratio = 60;
/**
* @param args the command line arguments
*/
public static void main(String[]args) {
FreeFallFrame app = new FreeFallFrame();
}public FreeFallFrame() throws HeadlessException {
//The main window of the application
fr = new JFrame("Free Fall");
fr = new JFrame("Free Fall");
The FreeFallFrame class implements the ActionListener interface, so an object of that class is also used to listen for timer events and button clicks. This object was passed to the timer constructor (see previous figures). In this example, the control panel is not created, only the possibility of its creation is left, which is left to the reader for practice.
The actionPerformed method looks like this:
{
Figure 7: Creating animations in Java using a timer. Method actionPerformed.First, the changed value of the velocity in the interval dt is calculated, and for the gravitational acceleration g. Since time is in s, and dt in milliseconds, it is necessary to divide dt by 1000./*Reaction to the click of a button*/
@Override
public void actionPerformed(ActionEvent e) {
}@Override
public void actionPerformed(ActionEvent e) {
double y, dy;
physicalObject.v = physicalObject.v + ((g * dt) / 1000.0);
dy = physicalObject.v * dt * ratio / 1000.0;
y = physicalObject.y + dy;
if (y < animationPanel.getHeight()
- (physicalObject.getHeight() / 2) - 50) {
animationPanel.physicalObject.setFrame(physicalObject.x, y,
physicalObject.getWidth(), physicalObject.getHeight());
animationPanel.repaint();
}
}physicalObject.v = physicalObject.v + ((g * dt) / 1000.0);
dy = physicalObject.v * dt * ratio / 1000.0;
y = physicalObject.y + dy;
if (y < animationPanel.getHeight()
- (physicalObject.getHeight() / 2) - 50) {
animationPanel.physicalObject.setFrame(physicalObject.x, y,
physicalObject.getWidth(), physicalObject.getHeight());
animationPanel.repaint();
Then the change of the y coordinate in that interval dt is calculated. It should be noted that the lower the dt, the more accurate the result. In order to move the body to a new position, the setFrame method is used, where x, y, w and x of the rectangle (in this case the square) in which the ellipse (circle in this case) is inscribed are passed as arguments.
By calling the repaint method, the paint method is called, which redraws all objects, including the body, but now in a new position.
EXAMPLE: Circular motion animation:
Task:Make a simulation of circular motion in a plane. Enable entering the radius of the circular path as well as the angular velocity. Based on the entered values for r and W, calculate: V, ac and display the values in the report field
Solution:This is an example of a circular motion shown in the previous chapter where a graph of the circular motion was made, as well as the entry of data on the angular velocity and the radius of the path by clicking on the input button. The timer should be introduced below and, as a reaction to the timer event, first calculate the change in line velocity and particle position when the time dt changes equal to the interval between the two timer events. The particle should be moved to a new position using the setFrame method, and then all objects should be drawn again. To change the velocity vector (shown by line only), you should use an object of the affineTransform class that has methods for rotating and translating a shape. When you start the application, the initial graphic is displayed:
Figure 8: Circular motion animation.-The main window display.
On the left is the drawn path, particle and velocity vector for the default values of radius and angular velocity. On the right side is the input panel with fields for entering the radius r = 0.5m and the angular velocity W = 1, as well as the buttons for entering, for starting the animation and for stopping the animation. The code that performs this has already been shown and explained in the previous chapter.If values for r and W are entered in the input fields, for example r = 0.8m and W = 0.3s ^ -1 and the button for entering the values of r, W and speed v is clicked, the drawing will be updated, as well as the drawing in accordance with the changed values:
Figure 9: Circular motion animation. Display the main application window-complete.
An increase in radius can now be seen, as well as an increase in the intensity of the velocity. This part is also explained in the previous chapter.Clicking on any button, as well as when a timer event occurs, calls the ActionListener method:
@Override
public void actionPerformed(ActionEvent e) {
public void actionPerformed(ActionEvent e) {
/*Checks if the start enter is clicked*/
if (e.getSource().equals(inputBtn)) {
double rPrevious=drawing.r;
double vPrevious=drawing.particle.v;
double dr = drawing. r-rPrevious;
/*
* Loads the radius from the text field
* and places the parsed value in the attribute r
* drawing
*/
String rStr = rTF.getText();
if (!rStr.equals("")) {
//Loads the angular velocity from the text field
String wStr = WTF.getText();
if (!wStr.equals("")) {
drawing.changeTheEnvironmentParameters();
double dv = drawing.particle.v / vPrevious;
drawing.createThePath();
drawing.translateVectorVelocity(dr);
drawing.increaseTheIntensityOfVectorVelocity(dv);
//blank input fields r and W
rTF.setText("");
WTF.setText("");
reportTA.setText("");
reportTA.setText("Angular velocity: " + drawing.particle.W + "rad/s\n");
reportTA.append("ac = " + drawing.particle.ac + "m/s^2");
}
else if (e.getSource().equals(startBtn)) {
if (e.getSource().equals(inputBtn)) {
double rPrevious=drawing.r;
double vPrevious=drawing.particle.v;
double dr = drawing. r-rPrevious;
/*
* Loads the radius from the text field
* and places the parsed value in the attribute r
* drawing
*/
String rStr = rTF.getText();
if (!rStr.equals("")) {
drawing.r = Double.parseDouble(rStr);
}//Loads the angular velocity from the text field
String wStr = WTF.getText();
if (!wStr.equals("")) {
drawing.particle.W = Double.parseDouble(wStr);
}drawing.changeTheEnvironmentParameters();
double dv = drawing.particle.v / vPrevious;
drawing.createThePath();
drawing.translateVectorVelocity(dr);
drawing.increaseTheIntensityOfVectorVelocity(dv);
//blank input fields r and W
rTF.setText("");
WTF.setText("");
reportTA.setText("");
reportTA.setText("Angular velocity: " + drawing.particle.W + "rad/s\n");
reportTA.append("ac = " + drawing.particle.ac + "m/s^2");
else if (e.getSource().equals(startBtn)) {
Clicking the startBtn button starts the timer created in the createTimer() method, which is called in the constructor, while clicking the stopBtn timer button stops:
reportTA.append("ac=" + drawing.particle.ac + "m/s^2");
}else if (e.getSource().equals(startBtn)) {
time.start();
}else if (e.getSource().equals(stopBtn)) {
time.stop();
}double dt;
dt = interval / 1000.0;
drawing.promeniVreme(dt);
drawing.promeniUgaonuBrzinu(dt);
drawing.promeniUgao(dt);
drawing.changePosition();
drawing.rotateTheVelocityVector();
reportTA.setText("");
reportTA.setText("Angular velocity: " + drawing.particle.W + "rad/s\n");
reportTA.append("ac=" + drawing.particle.ac + "m/s^2");
repaint();
private void createTimer() {
time = new Timer(100, this);
}package circularmotion;
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Shape;
import java.awt.Stroke;
import java.awt.font.FontRenderContext;
import java.awt.font.TextLayout;
import java.awt.geom.AffineTransform;
import java.awt.geom.Ellipse2D;
import java.awt.geom.Line2D;
import javax.swing.JPanel;
/**
*
* @author xx
*/
public final class Drawing extends JPanel {
double r = 0.5;//radius of circular path
double ratio = 200;
double fi=0;//angle
double t = 0;
Ellipse2D.Double path;
Ellipse2D.Double center;
Stroke velocityView = new BasicStroke(3, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_MITER);
Shape velocityVector;
Particle particle;
private double particleX;
private final double ratioV = 1000;
private Shape textShape;
private TextLayout text;
private AffineTransform transf;
double dr=0;
double ds=1;
private double particleY;
//Constructor
public Drawing() {
creatingAnEnvironment();
}/*Creates objects in the drawing according to the initial or entered values
of the radius of the path and the angular velocity*/
public void creatingAnEnvironment() {
/*Creates a circular path of a particle*/
createThePath();
center = new Ellipse2D.Double(200 - 5, 200 - 5, 10, 10);
/*It re-calculates the speed of the particle and changes its position
in the plane of the drawing*/
changeTheEnvironmentParameters();
velocityVector = new Line2D.Double(particleX+5, center.y, particleX+5,
(center.y - particle.v * ratioV));
text = new TextLayout("V", new Font("Vedrana", Font.BOLD, 20),
new FontRenderContext(null, false, false));
public void createThePath() {
path = new Ellipse2D.Double(200 - r * ratio, 200 - r * ratio, 2 * r * ratio, 2 * r * ratio);
}public void changeTheEnvironmentParameters() {
particleX = center.x + r * ratio;
particleY=center.y;
if (particle == null) {
particle.velocity(r);
particle.centripetalAcceleration(r);
}particleY=center.y;
if (particle == null) {
particle = new Particle(particleX, particleY, 10, 10);
transf = new AffineTransform();
} else {transf = new AffineTransform();
particle.setFrame(particleX, center.y, 10, 10);
}particle.velocity(r);
particle.centripetalAcceleration(r);
@Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.black);
g2.setStroke(new BasicStroke(3));
g2.draw(path);
g2.fill(center);
g2.setColor(Color.blue);
g2.fill(particle);
g2.setStroke(velocityView);
g2.draw(velocityVector);
if (textShape != null) {
text.draw(g2, 5, 5);
}Graphics2D g2 = (Graphics2D) g;
g2.setColor(Color.black);
g2.setStroke(new BasicStroke(3));
g2.draw(path);
g2.fill(center);
g2.setColor(Color.blue);
g2.fill(particle);
g2.setStroke(velocityView);
g2.draw(velocityVector);
if (textShape != null) {
g2.fill(textShape);
g2.draw(textShape);
}g2.draw(textShape);
text.draw(g2, 5, 5);
/*changing the position of the particle*/
void changePosition() {
double newCenterParticleX = center.getCenterX() + r * ratio * Math.cos(fi);
double newCenterParticleY = center.getCenterY() + r * ratio * Math.sin(fi);
double newX = newCenterParticleX - (particle.width / 2);
double newY = newCenterParticleY - (particle.height / 2);
particle.setFrame(newX, newY, particle.width, particle.height);
}double newCenterParticleY = center.getCenterY() + r * ratio * Math.sin(fi);
double newX = newCenterParticleX - (particle.width / 2);
double newY = newCenterParticleY - (particle.height / 2);
particle.setFrame(newX, newY, particle.width, particle.height);
/*rotating velocity vector*/
void rotateTheVelocityVector() {
double x1 = particle.x+(particle.width/2);
double y1 = particle.y+(particle.height/2);
velocityVector = new Line2D.Double(x1, y1, x1, (y1 - particle.v * ratioV));
transf.setToRotation(fi, x1, y1);
velocityVector = transf.createTransformedShape(velocityVector);
}double y1 = particle.y+(particle.height/2);
velocityVector = new Line2D.Double(x1, y1, x1, (y1 - particle.v * ratioV));
transf.setToRotation(fi, x1, y1);
velocityVector = transf.createTransformedShape(velocityVector);
void translateVectorVelocity(double dr) {
AffineTransform aft=new AffineTransform();
double dx = ratio*dr*Math.cos(fi);
double dy = ratio*dr*Math.sin(fi);
aft.setToTranslation(dx, dy);
velocityVector=aft.createTransformedShape(velocityVector);
}double dx = ratio*dr*Math.cos(fi);
double dy = ratio*dr*Math.sin(fi);
aft.setToTranslation(dx, dy);
velocityVector=aft.createTransformedShape(velocityVector);
public void increaseTheIntensityOfVectorVelocity(double dv) {
AffineTransform aft=new AffineTransform();
aft.setToScale(dv, dv);
velocityVector=aft.createTransformedShape(velocityVector);
}aft.setToScale(dv, dv);
velocityVector=aft.createTransformedShape(velocityVector);
public void changeTime(double dt){
t = t + dt;
}public void changeAngularVelocity(double dt){
particle.W=particle.W+particle.angularAcceleration*dt;
}void changeAngle(double dt) {
double dfi = -particle.W * dt;
fi=fi+dfi;
| Previous |<Graphics in Java - example |
Next Applications in JAVA-examples>| |
