Back to Java
2026-03-128 min read

Explicit Animations (Java)

Learn Explicit Animations (Java) step by step with clear examples and exercises.

Why This Matters

Explicit animations are a crucial aspect of creating dynamic and engaging user interfaces in Java applications. They allow developers to have complete control over the animation's behavior, enabling the creation of complex visual effects that significantly enhance the user experience. Understanding explicit animations is essential for both beginners and experienced developers who want to build visually appealing and interactive applications.

In this lesson, we will delve deeper into the core concepts of creating explicit animations in Java, providing you with a solid foundation for creating various types of animations using Swing or JavaFX libraries.

Prerequisites

To follow this lesson, you should have a basic understanding of:

  • Java programming language
  • Object-oriented programming (OOP) concepts
  • Swing or JavaFX libraries (for creating graphical user interfaces)
  • Threads and the Runnable interface (for animation loops)
  • Familiarity with classes such as JFrame, Graphics, and Shape will also be helpful.

Before diving into the core concepts, it's essential to have a solid understanding of Java fundamentals, including classes, objects, methods, and control structures. Additionally, having experience with Swing or JavaFX libraries is beneficial for creating graphical user interfaces that can host animations.

Core Concept

Explicit animations in Java are typically achieved using a loop that repeatedly updates the state of an object, causing it to appear as if it is moving or changing over time. This loop is usually run on a separate thread to ensure that the user interface remains responsive while the animation is running.

The core concept involves creating a custom Shape, setting its initial position and dimensions, and then updating its position in each iteration of the animation loop. To make the animation more responsive, it's essential to run the animation on a separate thread and use double buffering techniques to minimize flickering.

Let's explore these concepts in more detail:

Creating a Custom Shape

To create a custom shape for an animation, you can extend Shape or one of its subclasses (such as Ellipse2D, Rectangle2D, or Path2D) and define its outline using methods like moveTo(), lineTo(), and curveTo().

import java.awt.*;
import java.awt.geom.Path2D;

public class CustomShape extends Path2D {
public CustomShape(int x, int y, int width, int height) {
super();
moveTo(x, y);
lineTo(x + width, y);
lineTo(x + width, y + height);
lineTo(x, y + height);
closePath();
}
}

In the example above, we create a custom shape called CustomShape that represents a simple rectangle. The constructor takes four parameters (x, y, width, and height) and uses them to define the outline of the rectangle using the moveTo(), lineTo(), and closePath() methods.

Updating Shape Position

To update the position of your custom shape during an animation, you will need to create a variable for the current position (x and y) and increment them in each iteration of the animation loop. Additionally, you should store the initial position of the shape so that you can reset it when needed.

import java.awt.*;
import javax.swing.*;
import java.awt.event.ActionEvent;
import java.awt.geom.Path2D;

public class ExplicitAnimation extends JFrame {
private static final int WIDTH = 640;
private static final int HEIGHT = 480;
private static final int DELAY = 17; // milliseconds

private CustomShape shape;
private int x, y, dx, dy;

public ExplicitAnimation() {
// Set up the window and its contents
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(WIDTH, HEIGHT);
setLocationRelativeTo(null);
setResizable(false);

shape = new CustomShape(WIDTH / 4, HEIGHT / 4, 50, 50);
x = (int) shape.getPathIterator(null).getCurrentPoint().x;
y = (int) shape.getPathIterator(null).getCurrentPoint().y;
dx = 1;
dy = 1;

Timer timer = new Timer(DELAY, e -> {
if ((x + shape.getBounds2D().getWidth()) >= WIDTH || x <= 0) {
dx = -dx;
}
if ((y + shape.getBounds2D().getHeight()) >= HEIGHT || y <= 0) {
dy = -dy;
}
x += dx;
y += dy;
repaint();
});
timer.start();
}

@Override
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.translate(WIDTH / 2, HEIGHT / 2);
g2d.setComposite(AlphaComposite.SrcOver);
g2d.fill(shape);
}

public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new ExplicitAnimation().setVisible(true));
}
}

In the example above, we create an ExplicitAnimation class that extends JFrame. Inside the constructor, we set up a custom shape (a rectangle) and its initial position. We also create a timer with a delay of 17 milliseconds, which will call an action listener every time it ticks.

The action listener moves the shape by adding the dx and dy values to the current x and y coordinates, redrawing the shape in the paint() method, and flipping the direction of motion when the shape reaches the edge of the window. Additionally, we use double buffering to minimize flickering during the animation.

Worked Example

Let's create a more complex example that animates a bouncing ball:

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.geom.Ellipse2D;

public class BouncingBall extends JFrame {
private static final int WIDTH = 640;
private static final int HEIGHT = 480;
private static final int DELAY = 10; // milliseconds

private Ellipse2D ball;
private int x, y, dx, dy;

public BouncingBall() {
setDefaultCloseOperation(EXIT_ON_CLOSE);
setSize(WIDTH, HEIGHT);
setLocationRelativeTo(null);
setResizable(false);

ball = new Ellipse2D.Double(WIDTH / 4, HEIGHT / 2, 50, 50);
x = (int) ball.getX();
y = (int) ball.getY();
dx = 3;
dy = 3;

Timer timer = new Timer(DELAY, e -> {
if ((x + ball.getWidth()) >= WIDTH || x <= 0) {
dx = -dx;
}
if ((y + ball.getHeight()) >= HEIGHT || y <= 0) {
dy = -dy;
}
x += dx;
y += dy;
ball.setFrame(x, y, ball.getWidth(), ball.getHeight());
repaint();
});
timer.start();
}

@Override
public void paint(Graphics g) {
Graphics2D g2d = (Graphics2D) g;
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
g2d.translate(WIDTH / 2, HEIGHT / 2);
g2d.setComposite(AlphaComposite.SrcOver);
g2d.fill(ball);
}

public static void main(String[] args) {
SwingUtilities.invokeLater(() -> new BouncingBall().setVisible(true));
}
}

In this example, we create a BouncingBall class that animates an ellipse (representing a ball) bouncing around the window. The ball's direction is reversed when it hits either the left or right edge of the window, and the same happens for the top and bottom edges.

Common Mistakes

  1. Not updating the shape's position correctly: Make sure to update both the x and y coordinates of your shape in each iteration of the animation loop.
  2. Ignoring edge collisions: When animating objects that can hit the edges of the window, make sure to check for collisions and reverse their direction accordingly.
  3. Not making the animation threaded: Running the animation on a separate thread is essential to prevent the user interface from freezing during long or complex animations.
  4. Forgetting to repaint(): After updating the position of your shape, don't forget to call repaint() to redraw it on the screen.
  5. Not setting a reasonable delay: A delay that is too short can cause the animation to run too fast and become unresponsive, while a delay that is too long can make the animation appear jerky or slow.
  6. Not using double buffering: Double buffering helps minimize flickering during animations by drawing the updated frame off-screen before displaying it on the screen.
  7. Not handling exceptions properly: Make sure to handle exceptions that might occur during the execution of your animation, such as NullPointerException or ArrayIndexOutOfBoundsException.
  8. Not optimizing performance: Optimize your code by reducing the number of shapes in your animation, using more efficient rendering techniques (such as double buffering), and minimizing unnecessary calculations.

Practice Questions

  1. Create an animation of a moving square in Java, using Swing or JavaFX. The square should move diagonally from the top-left corner to the bottom-right corner of the window.
  2. Modify the bouncing ball example to make the ball change color every time it hits an edge. Use different colors for each edge (red for left/right, green for top, and blue for bottom).
  3. Create an animation of a spinning star in Java, using Swing or JavaFX. The star should rotate around its center point at a constant speed.
  4. Modify the bouncing ball example to make the ball grow larger every time it hits an edge. When the ball reaches the maximum size, reverse its direction and make it shrink back to its original size before continuing to bounce.
  5. Create an animation of a simple pong game in Java, using Swing or JavaFX. The game should consist of a paddle at the bottom of the window and a moving ball that bounces off both the paddle and the edges of the window.

FAQ

  1. Why is it important to run animations on a separate thread? Running animations on a separate thread prevents the user interface from freezing during long or complex animations, ensuring that the application remains responsive.
  2. How do I create a custom shape for an animation in Java? You can create a custom shape by extending Shape or one of its subclasses (such as Ellipse2D, Rectangle2D, or Path2D) and defining its outline using methods like moveTo(), lineTo(), and curveTo().
  3. What is the best way to handle edge collisions in an animation? To handle edge collisions, check for collisions by comparing the position of your shape with the edges of the window. If a collision occurs, reverse the direction of motion or apply any desired behavior (such as bouncing off the edge).
  4. What is the optimal delay for an animation in Java? The optimal delay depends on the complexity and speed of the animation. A good starting point is 10-20 milliseconds, but you may need to adjust this value based on your specific requirements.
  5. How can I make my animations more responsive in Java? To make animations more responsive, consider using a more efficient rendering technique (such as double buffering), reducing the number of shapes in your animation, or optimizing the code for better performance.
  6. What is double buffering and how does it help with animations in Java? Double buffering is a technique that helps minimize flickering during animations by drawing the updated frame off-screen before displaying it on the screen. This reduces the number of times the screen needs to be refreshed, making the animation appear smoother.
  7. How can I handle exceptions in my Java animations? To handle exceptions in your animations, wrap the code that might throw an exception inside a try-catch block. Inside the catch block
Explicit Animations (Java) | Java | XQA Learn