Swing Animation - SimpleRepaintCollector
(Page 3 of 8 )
public class SimpleRepaintCollector
implements RepaintCollector
SimpleRepaintCollector is a very simple concrete implementation of interface RepaintCollector. It exists in package com.croftsoft.core.animation.collector. The subpackage collector contains other concrete RepaintCollector implementations such as BooleanRepaintCollector, CoalescingRepaintCollector, NullRepaintCollector, and SwingRepaintCollector. I have organized the animation classes by grouping concrete implementations of an interface within a subpackage with the same name as the interface.
private int count;
private Rectangle [ ] repaintRegions;
public SimpleRepaintCollector ( )
////////////////////////////////////////////////////////
{
repaintRegions = new Rectangle [ 0 ];
}
public int getCount ( ) { return count; }
public Rectangle [ ] getRepaintRegions ( )
///////////////////////////////////////////////////////
{
return repaintRegions;
}
SimpleRepaintCollector reacts to repaint requests by incrementing the request count and storing the request area. When its accessor methods are called, SimpleRepaintCollector simply returns the stored data as given.
public void repaint (
int x,
int y,
int width,
int height )
///////////////////////////////////////////////////////
{
if ( count == repaintRegions.length )
{
repaintRegions = ( Rectangle [ ] ) ArrayLib.append (
repaintRegions, new Rectangle ( x, y, width, height ) );
}
else
{
repaintRegions [ count ].setBounds ( x, y, width, height );
}
count++;
}
A request to repaint an area is simply appended to the Rectangle array repaintRegions and the count is incremented. If the array is not long enough, it is replaced by a new array using the ArrayLib.append() method from package com.croftsoft.core.util. If the array is already long enough, an old Rectangle instance in the array is reused to hold the new data. Assuming the length of the array eventually stabilizes to some maximum value, probably equal to the number of sprites in the game, this technique ensures that new Rectangle instances do not need to be created with every animation loop.
This method is unsynchronized, as it is assumed that the repaint requests generated during the update phase will be serialized through the event dispatch thread. If this is not the case and this method is called simultaneously by more than one thread, the data could become garbled.
public void repaint
)
//////////////////////////////////////////////////////
{
repaint ( 0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE );
}
The ArrayLib.append() method handles requests to repaint the entire component. The implementation simply delegates to the previous repaint() method using the maximum dimensions.
public void reset ( )
///////////////////////////////////////////////////////
{
count = 0;
}
The reset method simply resets the count to zero. The Rectangle array repaintRegions is not cleared, as the old data will simply be overwritten during the next loop.
BooleanRepaintCollector BooleanRepaintCollector is another simple RepaintCollector implementation in that it simply repaints the entire component in response to one or more repaint requests, regardless of the sizes of the requested repaint areas. If there is no repaint request during the animation loop, no repaint will occur. Another way to think of this RepaintCollector implementation is as an all-or-nothing strategy that coalesces multiple requests into one.
The BooleanRepaintCollector is often adequate for many animation tasks. Since you know that this implementation is going to repaint the entire component with each frame if there is at least one repaint request, the Component-Animator implementations do not need to calculate the repaint areas when they perform the sprite position updates. This makes a lot of sense when the scene background is always moving around and you know that the entire component would have to be repainted anyway.
private static final Rectangle [ ] REPAINT_REGIONS
= new Rectangle [ ] {
new Rectangle ( Integer.MAX_VALUE, Integer.MAX_VALUE ) };
//
private boolean doRepaint;
Constant Rectangle array REPAINT_REGIONS contains a single rectangle of maximum size. Boolean doRepaint is a flag that indicates whether there has been a repaint request during the current animation-loop iteration.
public int getCount ( )
/////////////////////////////////////////////////
{
return doRepaint ? 1 : 0;
}
public Rectangle [ ] getRepaintRegions ( )
/////////////////////////////////////////////////
{
return REPAINT_REGIONS; }
The getCount() method simply returns a value of one if there have been any number of repaint requests whatsoever during the current animation-loop iteration. If the getCount() method returns zero instead, the array returned by method getRepaintRegions() will not be used, as only its first zero elements are assumed to contain valid data.
public void repaint (
int x,
int y,
int width,
int height )
/////////////////////////////////////////////////////
{
doRepaint = true;
}
public void repaint ( )
///////////////////////////////////////////////////
{
doRepaint = true;
}
These two methods simply set the doRepaint flag. Note that the area arguments in the first method are not used. If the sprites are not moving, neither of these methods will be called. In this case, the doRepaint flag will remain false.
public void reset ( )
///////////////////////////////////////////////////
{
doRepaint = false;
}
At the end of each animation loop iteration, the doRepaint flag is reset to false.
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. |
Next: CoalescingRepaintCollector >>
More Java Articles
More By Apress Publishing