Home arrow Java arrow Page 7 - Swing Animation
JAVA

Swing Animation


Have you ever been interested in creating a game using the Swing-based animation library? This article covers some important information to help you understand the backbone of this library. It is excerpted from the book Advanced Java Game Programming, written by David Wallace Croft (Apress, 2004; ISBN 1590591232).

Author Info:
By: Apress Publishing
Rating: 5 stars5 stars5 stars5 stars5 stars / 19
March 29, 2005
TABLE OF CONTENTS:
  1. · Swing Animation
  2. · RepaintCollector
  3. · SimpleRepaintCollector
  4. · CoalescingRepaintCollector
  5. · LoopGovernor
  6. · WindowedLoopGovernor
  7. · AnimatedComponent
  8. · Static method check()

print this article
SEARCH DEVARTICLES

Swing Animation - AnimatedComponent
(Page 7 of 8 )

Class AnimatedComponent from package com.croftsoft.core.animation is the Swing component that brings it all together by providing the surface on which the painting occurs, the animation loop that calls the other classes, and the lifecycle methods that allow Swing components to be integrated into a framework.

package com.croftsoft.core.animation;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.lang.reflect.InvocationTargetException;
import javax.swing.JComponent;
import com.croftsoft.core.animation.factory.DefaultAnimationFactory; import com.croftsoft.core.lang.NullArgumentException;
import com.croftsoft.core.lang.lifecycle.Lifecycle;
import com.croftsoft.core.util.loop.LoopGovernor;
public class  AnimatedComponent
  extends JComponent
  implements Lifecycle
///////////////////////////////////////////////////
//////////////////////////////////////////////////
{

AnimatedComponent is a Swing JComponent subclass implementation. It implements interface Lifecycle so that its animation can be stopped and restarted as necessary.

public static final String      ANIMATION_THREAD_NAME =  
                                "Animation";
//
protected final Runnable        animationRunner;
//
protected ComponentAnimator     componentAnimator;
protected RepaintCollector      repaintCollector;
protected LoopGovernor          loopGovernor;
protected Thread                animationThread;
protected boolean               stopRequested;

Runnable instance animationRunner is used to call the update() and paint() methods within a separate thread. ComponentAnimator is used to animate the AnimatedComponent. RepaintCollector is used to aggregate repaint requests. LoopGovernor regulates the animation speed. The animationThread variable refers to the current Thread instance that drives the animation loop. The boolean flag stopRequested is used to indicate that animation should stop.

The references to the instances of the interfaces ComponentAnimator, Repaint-Collector, and LoopGovernor are not final, as they may be replaced during runtime if desired. This is used in the demonstration Sprite program to compare the performance of different implementations.

public AnimatedComponent (
  ComponentAnimator   componentAnimator,
  RepaintCollector    repaintCollector,
  LoopGovernor        loopGovernor )
/////////////////////////////////////////////////////
 {
  setComponentAnimator ( componentAnimator );
  setRepaintCollector ( repaintCollector );
  setLoopGovernor ( loopGovernor );
  setOpaque ( true );
  animationRunner =
    new Runnable ( )
    {
     public void run ( )
     {
      animate ( );
     }
   };
 }

Methods setComponentAnimator(), setRepaintCollector(), and setLoop-Governor() simply save references to the constructor arguments and are described below.

JComponent method setOpaque() is used to indicate whether a subclass implementation has any transparent areas. For reasons of efficiency, the Animated-Component subclass marks itself as opaque, i.e., it has no transparent regions, so that any components behind and completely obscured by this object will not be drawn unnecessarily. If AnimatedComponent were to be displayed as an odd shape such as a circle, it would be necessary to set opaque to false so that components behind the transparent regions would be repainted as necessary. For this implementation, however, a simple rectangular display is assumed and the default JComponent property value of false is overridden.

The constructor method initializes the final variable animationRunner to an anonymous inner class implementation of Runnable that simply redirects to the protected method animate(). The animationRunner is created only once during the constructor method, as the animation loop will use it over and over again instead of creating a new instance with each iteration.

public AnimatedComponent (
  ComponentAnimator  componentAnimator,
  AnimationFactory   animationFactory,
  double             frequency )
/////////////////////////////////////////////////////
{
  this (
   componentAnimator,
   animationFactory.createRepaintCollector ( ), 
   animationFactory.createLoopGovernor ( frequency ) );
}
public AnimatedComponent (
  ComponentAnimator  componentAnimator,
  AnimationFactory   animationFactory )
///////////////////////////////////////////////////
{

  this (
    componentAnimator,
    animationFactory.createRepaintCollector ( ),  
    animationFactory.createLoopGovernor ( ) );
}

These convenience constructors use an instance of the interface AnimationFactory from package com.croftsoft.core.animation to create the RepaintCollector and LoopGovernor objects required by the main constructor. The choice of RepaintCollector and LoopGovernor implementations will significantly impact the animation performance. Providing an AnimationFactory implementation as an argument allows you to choose a preferred strategy.

The constructor argument frequency is used to determine the animation speed. Film provides the eye with the illusion of smooth motion by displaying sampled snapshots of the world at the rate of 24 fps. By repainting itself at periodic intervals of 1/24th of a second per frame, AnimatedComponent can achieve a similar result.

The second convenience constructor does not take a frequency argument. In this case, a LoopGovernor will be created that runs the animation at the default frame rate as determined by the AnimationFactory.

 public AnimatedComponent (
   ComponentAnimator componentAnimator,
   double            frequency )
////////////////////////////////////////////////////////
 {
   this (
     componentAnimator,
     DefaultAnimationFactory.INSTANCE,
     frequency );
 }
 public AnimatedComponent ( ComponentAnimator
        componentAnimator )
//////////////////////////////////////////////////////////   {
  this (
    componentAnimator,
    DefaultAnimationFactory.INSTANCE );
}

DefaultAnimationFactory from package com.croftsoft.core.animation.factory is a recommended AnimationFactory implementation. The concrete implementations produced by this factory may change over time as new research suggests better algorithms.

public synchronized ComponentAnimator setComponentAnimator  (
ComponentAnimator  componentAnimator )
//////////////////////////////////////////////////////
{
 NullArgumentException.check ( componentAnimator );
 ComponentAnimator  oldComponentAnimator = 
 this.componentAnimator;
 this.componentAnimator = componentAnimator;
 return oldComponentAnimator;
}
public synchronized RepaintCollector setRepaintCollector (
  RepaintCollector  repaintCollector )
//////////////////////////////////////////////////////
{
  NullArgumentException.check ( repaintCollector );
  RepaintCollector oldRepaintCollector = 
  this.repaintCollector;
  this.repaintCollector = repaintCollector;
  return oldRepaintCollector;
}
  public synchronized LoopGovernor setLoopGovernor (
  LoopGovernor loopGovernor )
//////////////////////////////////////////////////////
{
  NullArgumentException.check ( loopGovernor );
  LoopGovernor  oldLoopGovernor = this.loopGovernor;
  this.loopGovernor = loopGovernor;
  return oldLoopGovernor;
}

These mutator methods permit the ComponentAnimator, RepaintCollector, and LoopGovernor instances to be replaced as necessary during animation. The methods return the replaced instances for future use. These methods are synchronized to prevent them from being called simultaneously by multiple threads. It is assumed that the methods are called infrequently, much less than once per animation loop on average, so the performance hit from synchronizing these methods should be negligible.

Multiple ComponentAnimator, RepaintCollector, and LoopGovernor instances can be pre-constructed in memory and then instantly swapped in and out of the AnimatedComponent as required. For example, alternating the ComponentAnimator can cause the scene to suddenly switch to a different view, such as an animated pause screen, and just as suddenly, back again.

This article is excerpted from Advanced Java Game Programming by David Wallace Croft (Apress, 2004; ISBN 1590591232). Check it out at your favorite bookstore today. Buy this book now.


blog comments powered by Disqus
JAVA ARTICLES

- Java Too Insecure, Says Microsoft Researcher
- Google Beats Oracle in Java Ruling
- Deploying Multiple Java Applets as One
- Deploying Java Applets
- Understanding Deployment Frameworks
- Database Programming in Java Using JDBC
- Extension Interfaces and SAX
- Entities, Handlers and SAX
- Advanced SAX
- Conversions and Java Print Streams
- Formatters and Java Print Streams
- Java Print Streams
- Wildcards, Arrays, and Generics in Java
- Wildcards and Generic Methods in Java
- Finishing the Project: Java Web Development ...

Watch our Tech Videos 
Dev Articles Forums 
 RSS  Articles
 RSS  Forums
 RSS  All Feeds
Write For Us 
Weekly Newsletter
 
Developer Updates  
Free Website Content 
Contact Us 
Site Map 
Privacy Policy 
Support 

Developer Shed Affiliates

 




© 2003-2017 by Developer Shed. All rights reserved. DS Cluster - Follow our Sitemap
Popular Web Development Topics
All Web Development Tutorials