FileDocCategorySizeDatePackage
Sprite.javaAPI DocJ2ME MIDP 2.073812Thu Nov 07 12:02:28 GMT 2002javax.microedition.lcdui.game

Sprite

public class Sprite extends Layer
A Sprite is a basic visual element that can be rendered with one of several frames stored in an Image; different frames can be shown to animate the Sprite. Several transforms such as flipping and rotation can also be applied to a Sprite to further vary its appearance. As with all Layer subclasses, a Sprite's location can be changed and it can also be made visible or invisible.

Sprite Frames

The raw frames used to render a Sprite are provided in a single Image object, which may be mutable or immutable. If more than one frame is used, the Image is broken up into a series of equally-sized frames of a specified width and height. As shown in the figure below, the same set of frames may be stored in several different arrangements depending on what is the most convenient for the game developer.
Sprite Frames

Each frame is assigned a unique index number. The frame located in the upper-left corner of the Image is assigned an index of 0. The remaining frames are then numbered consecutively in row-major order (indices are assigned across the first row, then the second row, and so on). The method {@link #getRawFrameCount()} returns the total number of raw frames.

Frame Sequence

A Sprite's frame sequence defines an ordered list of frames to be displayed. The default frame sequence mirrors the list of available frames, so there is a direct mapping between the sequence index and the corresponding frame index. This also means that the length of the default frame sequence is equal to the number of raw frames. For example, if a Sprite has 4 frames, its default frame sequence is {0, 1, 2, 3}.
Default Frame Sequence

The developer must manually switch the current frame in the frame sequence. This may be accomplished by calling {@link #setFrame}, {@link #prevFrame()}, or {@link #nextFrame()}. Note that these methods always operate on the sequence index, they do not operate on frame indices; however, if the default frame sequence is used, then the sequence indices and the frame indices are interchangeable.

If desired, an arbitrary frame sequence may be defined for a Sprite. The frame sequence must contain at least one element, and each element must reference a valid frame index. By defining a new frame sequence, the developer can conveniently display the Sprite's frames in any order desired; frames may be repeated, omitted, shown in reverse order, etc.

For example, the diagram below shows how a special frame sequence might be used to animate a mosquito. The frame sequence is designed so that the mosquito flaps its wings three times and then pauses for a moment before the cycle is repeated.

Special Frame Sequence
By calling {@link #nextFrame} each time the display is updated, the resulting animation would like this:

Reference Pixel

Being a subclass of Layer, Sprite inherits various methods for setting and retrieving its location such as {@link #setPosition setPosition(x,y)}, {@link #getX getX()}, and {@link #getY getY()}. These methods all define position in terms of the upper-left corner of the Sprite's visual bounds; however, in some cases, it is more convenient to define the Sprite's position in terms of an arbitrary pixel within its frame, especially if transforms are applied to the Sprite.

Therefore, Sprite includes the concept of a reference pixel. The reference pixel is defined by specifying its location in the Sprite's untransformed frame using {@link #defineReferencePixel defineReferencePixel(x,y)}. By default, the reference pixel is defined to be the pixel at (0,0) in the frame. If desired, the reference pixel may be defined outside of the frame's bounds.

In this example, the reference pixel is defined to be the pixel that the monkey appears to be hanging from:

Defining The Reference Pixel

{@link #getRefPixelX getRefPixelX()} and {@link #getRefPixelY getRefPixelY()} can be used to query the location of the reference pixel in the painter's coordinate system. The developer can also use {@link #setRefPixelPosition setRefPixelPosition(x,y)} to position the Sprite so that reference pixel appears at a specific location in the painter's coordinate system. These methods automatically account for any transforms applied to the Sprite.

In this example, the reference pixel's position is set to a point at the end of a tree branch; the Sprite's location changes so that the reference pixel appears at this point and the monkey appears to be hanging from the branch:

Setting The Reference Pixel Position

Sprite Transforms

Various transforms can be applied to a Sprite. The available transforms include rotations in multiples of 90 degrees, and mirrored (about the vertical axis) versions of each of the rotations. A Sprite's transform is set by calling {@link #setTransform setTransform(transform)}.

Transforms

When a transform is applied, the Sprite is automatically repositioned such that the reference pixel appears stationary in the painter's coordinate system. Thus, the reference pixel effectively becomes the center of the transform operation. Since the reference pixel does not move, the values returned by {@link #getRefPixelX()} and {@link #getRefPixelY()} remain the same; however, the values returned by {@link #getX getX()} and {@link #getY getY()} may change to reflect the movement of the Sprite's upper-left corner.

Referring to the monkey example once again, the position of the reference pixel remains at (48, 22) when a 90 degree rotation is applied, thereby making it appear as if the monkey is swinging from the branch:

Transform Center

Sprite Drawing

Sprites can be drawn at any time using the {@link #paint(Graphics)} method. The Sprite will be drawn on the Graphics object according to the current state information maintained by the Sprite (i.e. position, frame, visibility). Erasing the Sprite is always the responsibility of code outside the Sprite class.

Sprites can be implemented using whatever techniques a manufacturers wishes to use (e.g hardware acceleration may be used for all Sprites, for certain sizes of Sprites, or not at all).

For some platforms, certain Sprite sizes may be more efficient than others; manufacturers may choose to provide developers with information about device-specific characteristics such as these.

since
MIDP 2.0

Fields Summary
public static final int
TRANS_NONE
No transform is applied to the Sprite. This constant has a value of 0.
public static final int
TRANS_ROT90
Causes the Sprite to appear rotated clockwise by 90 degrees. This constant has a value of 5.
public static final int
TRANS_ROT180
Causes the Sprite to appear rotated clockwise by 180 degrees. This constant has a value of 3.
public static final int
TRANS_ROT270
Causes the Sprite to appear rotated clockwise by 270 degrees. This constant has a value of 6.
public static final int
TRANS_MIRROR
Causes the Sprite to appear reflected about its vertical center. This constant has a value of 2.
public static final int
TRANS_MIRROR_ROT90
Causes the Sprite to appear reflected about its vertical center and then rotated clockwise by 90 degrees. This constant has a value of 7.
public static final int
TRANS_MIRROR_ROT180
Causes the Sprite to appear reflected about its vertical center and then rotated clockwise by 180 degrees. This constant has a value of 1.
public static final int
TRANS_MIRROR_ROT270
Causes the Sprite to appear reflected about its vertical center and then rotated clockwise by 270 degrees. This constant has a value of 4.
private static final int
INVERTED_AXES
If this bit is set, it denotes that the transform causes the axes to be interchanged
private static final int
X_FLIP
If this bit is set, it denotes that the transform causes the x axis to be flipped.
private static final int
Y_FLIP
If this bit is set, it denotes that the transform causes the y axis to be flipped.
private static final int
ALPHA_BITMASK
Bit mask for channel value in ARGB pixel.
javax.microedition.lcdui.Image
sourceImage
Source image
int
numberFrames
The number of frames
int[]
frameCoordsX
list of X coordinates of individual frames
int[]
frameCoordsY
list of Y coordinates of individual frames
int
srcFrameWidth
Width of each frame in the source image
int
srcFrameHeight
Height of each frame in the source image
int[]
frameSequence
The sequence in which to display the Sprite frames
private int
sequenceIndex
The sequence index
private boolean
customSequenceDefined
Set to true if custom sequence is used.
int
dRefX
Horizontal offset of the reference point from the top left of the sprite.
int
dRefY
Vertical offset of the reference point from the top left of the sprite.
int
collisionRectX
Horizontal offset of the top left of the collision rectangle from the top left of the sprite.
int
collisionRectY
Vertical offset of the top left of the collision rectangle from the top left of the sprite.
int
collisionRectWidth
Width of the bounding rectangle for collision detection.
int
collisionRectHeight
Height of the bounding rectangle for collision detection.
int
t_currentTransformation
The current transformation in effect.
int
t_collisionRectX
Horizontal offset of the top left of the collision rectangle from the top left of the sprite.
int
t_collisionRectY
Vertical offset of the top left of the collision rectangle from the top left of the sprite.
int
t_collisionRectWidth
Width of the bounding rectangle for collision detection, with the current transformation in effect.
int
t_collisionRectHeight
Height of the bounding rectangle for collision detection, with the current transformation in effect.
Constructors Summary
public Sprite(javax.microedition.lcdui.Image image)
Creates a new non-animated Sprite using the provided Image. This constructor is functionally equivalent to calling new Sprite(image, image.getWidth(), image.getHeight())

By default, the Sprite is visible and its upper-left corner is positioned at (0,0) in the painter's coordinate system.

param
image the Image to use as the single frame for the Sprite
throws
NullPointerException if img is null


    // ----- Constructors -----

                                                                        
       
        super(image.getWidth(), image.getHeight());

	initializeFrames(image, image.getWidth(), image.getHeight(), false);

	// initialize collision rectangle
	initCollisionRectBounds();

	// current transformation is TRANS_NONE
	this.setTransformImpl(TRANS_NONE);

    
public Sprite(javax.microedition.lcdui.Image image, int frameWidth, int frameHeight)
Creates a new animated Sprite using frames contained in the provided Image. The frames must be equally sized, with the dimensions specified by frameWidth and frameHeight. They may be laid out in the image horizontally, vertically, or as a grid. The width of the source image must be an integer multiple of the frame width, and the height of the source image must be an integer multiple of the frame height. The values returned by {@link Layer#getWidth} and {@link Layer#getHeight} will reflect the frame width and frame height subject to the Sprite's current transform.

Sprites have a default frame sequence corresponding to the raw frame numbers, starting with frame 0. The frame sequence may be modified with {@link #setFrameSequence(int[])}.

By default, the Sprite is visible and its upper-left corner is positioned at (0,0) in the painter's coordinate system.

param
image the Image to use for Sprite
param
frameWidth the width, in pixels, of the individual raw frames
param
frameHeight the height, in pixels, of the individual raw frames
throws
NullPointerException if img is null
throws
IllegalArgumentException if frameHeight or frameWidth is less than 1
throws
IllegalArgumentException if the image width is not an integer multiple of the frameWidth
throws
IllegalArgumentException if the image height is not an integer multiple of the frameHeight


        super(frameWidth, frameHeight);
        // if img is null img.getWidth() will throw NullPointerException
        if ((frameWidth < 1 || frameHeight < 1) ||
	    ((image.getWidth() % frameWidth) != 0) ||
            ((image.getHeight() % frameHeight) != 0)) {
             throw new IllegalArgumentException();
	}

	// construct the array of images that 
	// we use as "frames" for the sprite.
        // use default frame , sequence index = 0  
        initializeFrames(image, frameWidth, frameHeight, false);

	// initialize collision rectangle
	initCollisionRectBounds();

	// current transformation is TRANS_NONE
	this.setTransformImpl(TRANS_NONE);

    
public Sprite(Sprite s)
Creates a new Sprite from another Sprite.

All instance attributes (raw frames, position, frame sequence, current frame, reference point, collision rectangle, transform, and visibility) of the source Sprite are duplicated in the new Sprite.

param
s the Sprite to create a copy of
throws
NullPointerException if s is null


	super(s != null ? s.getWidth() : 0,
                     s != null ? s.getHeight() : 0);

        if (s == null) {
	    throw new NullPointerException();
        }

        this.sourceImage = Image.createImage(s.sourceImage);

	this.numberFrames = s.numberFrames;

	this.frameCoordsX = new int[this.numberFrames];
	this.frameCoordsY = new int[this.numberFrames];

        System.arraycopy(s.frameCoordsX, 0, 
			 this.frameCoordsX, 0,
			 s.getRawFrameCount());

        System.arraycopy(s.frameCoordsY, 0, 
			 this.frameCoordsY, 0,
			 s.getRawFrameCount());

        this.x = s.getX();
        this.y = s.getY();

	// these fields are set by defining a reference point
	this.dRefX = s.dRefX;
	this.dRefY = s.dRefY;

	// these fields are set when defining a collision rectangle
	this.collisionRectX = s.collisionRectX;
	this.collisionRectY = s.collisionRectY;
	this.collisionRectWidth = s.collisionRectWidth;
	this.collisionRectHeight = s.collisionRectHeight;

	// these fields are set when creating a Sprite from an Image
	this.srcFrameWidth = s.srcFrameWidth;
	this.srcFrameHeight = s.srcFrameHeight;

	// the above fields are used in setTransform()
	// which is why we set them first, then  call setTransformImpl() 
	// to set up internally used data structures.
	setTransformImpl(s.t_currentTransformation);

        this.setVisible(s.isVisible()); 

	this.frameSequence = new int[s.getFrameSequenceLength()];
        this.setFrameSequence(s.frameSequence);
        this.setFrame(s.getFrame());

        this.setRefPixelPosition(s.getRefPixelX(), s.getRefPixelY());
	
    
Methods Summary
public final booleancollidesWith(javax.microedition.lcdui.game.Sprite s, boolean pixelLevel)
Checks for a collision between this Sprite and the specified Sprite.

If pixel-level detection is used, a collision is detected only if opaque pixels collide. That is, an opaque pixel in the first Sprite would have to collide with an opaque pixel in the second Sprite for a collision to be detected. Only those pixels within the Sprites' respective collision rectangles are checked.

If pixel-level detection is not used, this method simply checks if the Sprites' collision rectangles intersect.

Any transforms applied to the Sprites are automatically accounted for.

Both Sprites must be visible in order for a collision to be detected.

param
s the Sprite to test for collision with
param
pixelLevel true to test for collision on a pixel-by-pixel basis, false to test using simple bounds checking.
return
true if the two Sprites have collided, otherwise false
throws
NullPointerException if Sprite s is null

        
        // check if either of the Sprite's are not visible
        if (!(s.visible && this.visible)) {
            return false;
        }

	// these are package private 
	// and can be accessed directly
        int otherLeft    = s.x + s.t_collisionRectX;
        int otherTop     = s.y + s.t_collisionRectY;
        int otherRight   = otherLeft + s.t_collisionRectWidth;
        int otherBottom  = otherTop  + s.t_collisionRectHeight;

	int left   = this.x + this.t_collisionRectX;
	int top    = this.y + this.t_collisionRectY;
	int right  = left + this.t_collisionRectWidth;
	int bottom = top  + this.t_collisionRectHeight;

	// check if the collision rectangles of the two sprites intersect
	if (intersectRect(otherLeft, otherTop, otherRight, otherBottom,
			  left, top, right, bottom)) {

	    // collision rectangles intersect
	    if (pixelLevel) {

		// we need to check pixel level collision detection.
		// use only the coordinates within the Sprite frame if 
		// the collision rectangle is larger than the Sprite 
		// frame 
		if (this.t_collisionRectX < 0) {
		    left = this.x;
		}
		if (this.t_collisionRectY < 0) {
		    top = this.y;
		}
		if ((this.t_collisionRectX + this.t_collisionRectWidth)
		    > this.width) {
		    right = this.x + this.width;
		}
		if ((this.t_collisionRectY + this.t_collisionRectHeight)
		    > this.height) {
		    bottom = this.y + this.height;
		}

		// similarly for the other Sprite
		if (s.t_collisionRectX < 0) {
		    otherLeft = s.x;
		}
		if (s.t_collisionRectY < 0) {
		    otherTop = s.y;
		}
		if ((s.t_collisionRectX + s.t_collisionRectWidth)
		    > s.width) {
		    otherRight = s.x + s.width;
		}
		if ((s.t_collisionRectY + s.t_collisionRectHeight)
		    > s.height) {
		    otherBottom = s.y + s.height;
		}

		// recheck if the updated collision area rectangles intersect
		if (!intersectRect(otherLeft, otherTop, otherRight, otherBottom,
				  left, top, right, bottom)) {

		    // if they don't intersect, return false;
		    return false;
		}

		// the updated collision rectangles intersect,
		// go ahead with collision detection


		// find intersecting region, 
		// within the collision rectangles
		int intersectLeft = (left < otherLeft) ? otherLeft : left;
		int intersectTop  = (top < otherTop) ? otherTop : top;

		// used once, optimize.
		int intersectRight  = (right < otherRight) 
		                      ? right : otherRight;
		int intersectBottom = (bottom < otherBottom) 
		                      ? bottom : otherBottom;

		int intersectWidth  = Math.abs(intersectRight - intersectLeft);
		int intersectHeight = Math.abs(intersectBottom - intersectTop);

		// have the coordinates in painter space,
		// need coordinates of top left and width, height
		// in source image of Sprite.
		
		int thisImageXOffset = getImageTopLeftX(intersectLeft, 
							intersectTop,
							intersectRight,
							intersectBottom);
		
		int thisImageYOffset = getImageTopLeftY(intersectLeft, 
							intersectTop,
							intersectRight,
							intersectBottom);

		int otherImageXOffset = s.getImageTopLeftX(intersectLeft, 
							   intersectTop,
							   intersectRight,
							   intersectBottom);
		
		int otherImageYOffset = s.getImageTopLeftY(intersectLeft, 
							   intersectTop,
							   intersectRight,
							   intersectBottom);

		// check if opaque pixels intersect.

		return doPixelCollision(thisImageXOffset, thisImageYOffset,
					otherImageXOffset, otherImageYOffset,
					this.sourceImage,
					this.t_currentTransformation,
					s.sourceImage, 
					s.t_currentTransformation,
					intersectWidth, intersectHeight);

	    } else {
		// collides!
		return true;
	    }
	}
        return false;

    
public final booleancollidesWith(TiledLayer t, boolean pixelLevel)
Checks for a collision between this Sprite and the specified TiledLayer. If pixel-level detection is used, a collision is detected only if opaque pixels collide. That is, an opaque pixel in the Sprite would have to collide with an opaque pixel in TiledLayer for a collision to be detected. Only those pixels within the Sprite's collision rectangle are checked.

If pixel-level detection is not used, this method simply checks if the Sprite's collision rectangle intersects with a non-empty cell in the TiledLayer.

Any transform applied to the Sprite is automatically accounted for.

The Sprite and the TiledLayer must both be visible in order for a collision to be detected.

param
t the TiledLayer to test for collision with
param
pixelLevel true to test for collision on a pixel-by-pixel basis, false to test using simple bounds checking against non-empty cells.
return
true if this Sprite has collided with the TiledLayer, otherwise false
throws
NullPointerException if t is null


	// check if either this Sprite or the TiledLayer is not visible
	if (!(t.visible && this.visible)) {
	    return false;
	}

        // dimensions of tiledLayer, cell, and
        // this Sprite's collision rectangle

        // these are package private 
        // and can be accessed directly
        int tLx1 = t.x;
        int tLy1 = t.y;
        int tLx2 = tLx1 + t.width;
        int tLy2 = tLy1 + t.height;

        int tW = t.getCellWidth();
        int tH = t.getCellHeight();

        int sx1 = this.x + this.t_collisionRectX;
        int sy1 = this.y + this.t_collisionRectY;
        int sx2 = sx1 + this.t_collisionRectWidth;
        int sy2 = sy1 + this.t_collisionRectHeight;

        // number of cells
        int tNumCols = t.getColumns();
        int tNumRows = t.getRows();

        // temporary loop variables.
        int startCol; // = 0;
        int endCol;   // = 0;
        int startRow; // = 0;
        int endRow;   // = 0;

        if (!intersectRect(tLx1, tLy1, tLx2, tLy2, sx1, sy1, sx2, sy2)) {
            // if the collision rectangle of the sprite
            // does not intersect with the dimensions of the entire 
            // tiled layer
            return false;
        }

        // so there is an intersection

            // note sx1 < sx2, tLx1 < tLx2, sx2 > tLx1  from intersectRect()
            // use <= for comparison as this saves us some
            // computation - the result will be 0
            startCol = (sx1 <= tLx1) ? 0 : (sx1 - tLx1)/tW;
            startRow = (sy1 <= tLy1) ? 0 : (sy1 - tLy1)/tH;
            // since tLx1 < sx2 < tLx2, the computation will yield
            // a result between 0 and tNumCols - 1
            // subtract by 1 because sx2,sy2 represent
            // the enclosing bounds of the sprite, not the 
            // locations in the coordinate system.
            endCol = (sx2 < tLx2) ? ((sx2 - 1 - tLx1)/tW) : tNumCols - 1;
            endRow = (sy2 < tLy2) ? ((sy2 - 1 - tLy1)/tH) : tNumRows - 1;

        if (!pixelLevel) {
            // check for intersection with a non-empty cell,
            for (int row = startRow; row <= endRow; row++) {
                for (int col = startCol; col <= endCol; col++) {
                    if (t.getCell(col, row) != 0) {
                        return true;
                    }
                }
            }
            // worst case! we scanned through entire 
            // overlapping region and
            // all the cells are empty!
            return false;
        } else {
            // do pixel level

            // we need to check pixel level collision detection.
            // use only the coordinates within the Sprite frame if 
            // the collision rectangle is larger than the Sprite 
            // frame 
            if (this.t_collisionRectX < 0) {
                sx1 = this.x;
            }
            if (this.t_collisionRectY < 0) {
                sy1 = this.y;
            }
            if ((this.t_collisionRectX + this.t_collisionRectWidth)
                > this.width) {
                sx2 = this.x + this.width;
            }
            if ((this.t_collisionRectY + this.t_collisionRectHeight)
                > this.height) {
                sy2 = this.y + this.height;
            }
                
            if (!intersectRect(tLx1, tLy1, tLx2, tLy2, sx1, sy1, sx2, sy2)) {
                return (false);
            }
                
            // we have an intersection between the Sprite and 
            // one or more cells of the tiledlayer

            // note sx1 < sx2, tLx1 < tLx2, sx2 > tLx1  from intersectRect()
            // use <= for comparison as this saves us some
            // computation - the result will be 0
            startCol = (sx1 <= tLx1) ? 0 : (sx1 - tLx1)/tW;
            startRow = (sy1 <= tLy1) ? 0 : (sy1 - tLy1)/tH;
            // since tLx1 < sx2 < tLx2, the computation will yield
            // a result between 0 and tNumCols - 1
            // subtract by 1 because sx2,sy2 represent
            // the enclosing bounds of the sprite, not the 
            // locations in the coordinate system.
            endCol = (sx2 < tLx2) ? ((sx2 - 1 - tLx1)/tW) : tNumCols - 1;
            endRow = (sy2 < tLy2) ? ((sy2 - 1 - tLy1)/tH) : tNumRows - 1;

            // current cell coordinates
            int cellTop    = startRow * tH + tLy1;
            int cellBottom = cellTop  + tH;

            // the index of the current tile.
            int tileIndex; // = 0;

            for (int row = startRow; row <= endRow; 
                 row++, cellTop += tH, cellBottom += tH) {

		// current cell coordinates
		int cellLeft   = startCol * tW + tLx1;
		int cellRight  = cellLeft + tW;

                for (int col = startCol; col <= endCol; 
                     col++, cellLeft += tW, cellRight += tW) {

                    tileIndex = t.getCell(col, row);

                    if (tileIndex != 0) {
                        
                        // current cell/sprite intersection coordinates
                        // in painter coordinate system.
                        // find intersecting region, 
                        int intersectLeft = (sx1 < cellLeft) ? cellLeft : sx1;
                        int intersectTop  = (sy1 < cellTop) ? cellTop  : sy1;
                        
                        // used once, optimize.
                        int intersectRight  = (sx2 < cellRight) ? 
                                               sx2 : cellRight;
                        int intersectBottom = (sy2 < cellBottom) ? 
                                               sy2 : cellBottom;

                        if (intersectLeft > intersectRight) {
                            int temp = intersectRight;
                            intersectRight = intersectLeft;
                            intersectLeft = temp;
                        }

                        if (intersectTop > intersectBottom) {
                            int temp = intersectBottom;
                            intersectBottom = intersectTop;
                            intersectTop = temp;
                        }

                        int intersectWidth  = intersectRight  - intersectLeft;
                        int intersectHeight = intersectBottom - intersectTop;

                        int image1XOffset = getImageTopLeftX(intersectLeft, 
                                                             intersectTop,
                                                             intersectRight,
                                                             intersectBottom);

                        int image1YOffset = getImageTopLeftY(intersectLeft, 
                                                             intersectTop,
                                                             intersectRight,
                                                             intersectBottom);

                        int image2XOffset = t.tileSetX[tileIndex] +
                                            (intersectLeft - cellLeft);
                        int image2YOffset = t.tileSetY[tileIndex] +
                                            (intersectTop - cellTop);

                        if (doPixelCollision(image1XOffset,
                                             image1YOffset,
                                             image2XOffset,
                                             image2YOffset,
                                             this.sourceImage, 
                                             this.t_currentTransformation,
                                             t.sourceImage,
                                             TRANS_NONE,
                                             intersectWidth, intersectHeight)) {
                            // intersection found with this tile
                            return true;
                        }
                    }
                } // end of for col
            }// end of for row

            // worst case! we scanned through entire 
            // overlapping region and
            // no pixels collide!
            return false;
        }

    
public final booleancollidesWith(javax.microedition.lcdui.Image image, int x, int y, boolean pixelLevel)
Checks for a collision between this Sprite and the specified Image with its upper left corner at the specified location. If pixel-level detection is used, a collision is detected only if opaque pixels collide. That is, an opaque pixel in the Sprite would have to collide with an opaque pixel in Image for a collision to be detected. Only those pixels within the Sprite's collision rectangle are checked.

If pixel-level detection is not used, this method simply checks if the Sprite's collision rectangle intersects with the Image's bounds.

Any transform applied to the Sprite is automatically accounted for.

The Sprite must be visible in order for a collision to be detected.

param
image the Image to test for collision
param
x the horizontal location of the Image's upper left corner
param
y the vertical location of the Image's upper left corner
param
pixelLevel true to test for collision on a pixel-by-pixel basis, false to test using simple bounds checking
return
true if this Sprite has collided with the Image, otherwise false
throws
NullPointerException if image is null


	// check if this Sprite is not visible
	if (!(this.visible)) {
	    return false;
	}

	// if image is null 
	// image.getWidth() will throw NullPointerException
        int otherLeft    = x;
        int otherTop     = y;
        int otherRight   = x + image.getWidth();
        int otherBottom  = y + image.getHeight();

	int left   = this.x + this.t_collisionRectX;
	int top    = this.y + this.t_collisionRectY;
	int right  = left + this.t_collisionRectWidth;
	int bottom = top  + this.t_collisionRectHeight;

	// first check if the collision rectangles of the two sprites intersect
	if (intersectRect(otherLeft, otherTop, otherRight, otherBottom,
			  left, top, right, bottom)) {

	    // collision rectangles intersect
	    if (pixelLevel) {

		// find intersecting region, 

		// we need to check pixel level collision detection.
		// use only the coordinates within the Sprite frame if 
		// the collision rectangle is larger than the Sprite 
		// frame 
		if (this.t_collisionRectX < 0) {
		    left = this.x;
		}
		if (this.t_collisionRectY < 0) {
		    top = this.y;
		}
		if ((this.t_collisionRectX + this.t_collisionRectWidth)
		    > this.width) {
		    right = this.x + this.width;
		}
		if ((this.t_collisionRectY + this.t_collisionRectHeight)
		    > this.height) {
		    bottom = this.y + this.height;
		}

		// recheck if the updated collision area rectangles intersect
		if (!intersectRect(otherLeft, otherTop, 
				   otherRight, otherBottom,
				   left, top, right, bottom)) {

		    // if they don't intersect, return false;
		    return false;
		}

		// within the collision rectangles
		int intersectLeft = (left < otherLeft) ? otherLeft : left;
		int intersectTop  = (top < otherTop) ? otherTop : top;

		// used once, optimize.
		int intersectRight  = (right < otherRight) 
		                      ? right : otherRight;
		int intersectBottom = (bottom < otherBottom) 
		                      ? bottom : otherBottom;

		int intersectWidth  = Math.abs(intersectRight - intersectLeft);
		int intersectHeight = Math.abs(intersectBottom - intersectTop);

		// have the coordinates in painter space,
		// need coordinates of top left and width, height
		// in source image of Sprite.
		
		int thisImageXOffset = getImageTopLeftX(intersectLeft, 
							intersectTop,
							intersectRight,
							intersectBottom);
		
		int thisImageYOffset = getImageTopLeftY(intersectLeft, 
							intersectTop,
							intersectRight,
							intersectBottom);

		int otherImageXOffset = intersectLeft - x;
		int otherImageYOffset = intersectTop  - y;

		// check if opaque pixels intersect.
		return doPixelCollision(thisImageXOffset, thisImageYOffset,
					otherImageXOffset, otherImageYOffset,
					this.sourceImage,
					this.t_currentTransformation,
					image, 
					Sprite.TRANS_NONE,
					intersectWidth, intersectHeight);

	    } else {
		// collides!
		return true;
	    }
	}
        return false;

    
private voidcomputeTransformedBounds(int transform)
Calculate transformed sprites collision rectangle and transformed width and height

param
transform the desired transform for this Sprite

	switch (transform) {

	case TRANS_NONE:

	    t_collisionRectX = collisionRectX;
	    t_collisionRectY = collisionRectY;
	    t_collisionRectWidth = collisionRectWidth;
	    t_collisionRectHeight = collisionRectHeight;
  	    this.width = srcFrameWidth;
  	    this.height = srcFrameHeight;

	    break;

	case TRANS_MIRROR:

	    // flip across vertical

	    // NOTE: top left x and y coordinate must reflect the transformation
	    // performed around the reference point

	    // the X-offset of the reference point from the top left corner
	    // changes.
	    t_collisionRectX = srcFrameWidth - 
		               (collisionRectX + collisionRectWidth);

	    t_collisionRectY = collisionRectY;
	    t_collisionRectWidth = collisionRectWidth;
	    t_collisionRectHeight = collisionRectHeight;

	    // the Y-offset of the reference point from the top left corner
	    // remains the same,
	    // top left X-co-ordinate changes

  	    this.width = srcFrameWidth;
  	    this.height = srcFrameHeight;

	    break;

	case TRANS_MIRROR_ROT180:

	    // flip across horizontal

	    // NOTE: top left x and y coordinate must reflect the transformation
	    // performed around the reference point

	    // the Y-offset of the reference point from the top left corner
	    // changes
	    t_collisionRectY = srcFrameHeight - 
                               (collisionRectY + collisionRectHeight);

	    t_collisionRectX = collisionRectX;
	    t_collisionRectWidth = collisionRectWidth;
	    t_collisionRectHeight = collisionRectHeight;

	    // width and height are as before
  	    this.width = srcFrameWidth;
  	    this.height = srcFrameHeight;
    
	    // the X-offset of the reference point from the top left corner
	    // remains the same.
	    // top left Y-co-ordinate changes
	    
	    break;

	case TRANS_ROT90:

	    // NOTE: top left x and y coordinate must reflect the transformation
	    // performed around the reference point

	    // the bottom-left corner of the rectangle becomes the 
	    // top-left when rotated 90.

	    // both X- and Y-offset to the top left corner may change

	    // update the position information for the collision rectangle

	    t_collisionRectX = srcFrameHeight - 
                               (collisionRectHeight + collisionRectY);
	    t_collisionRectY = collisionRectX;

	    t_collisionRectHeight = collisionRectWidth;
	    t_collisionRectWidth = collisionRectHeight;

	    // set width and height
  	    this.width = srcFrameHeight;
  	    this.height = srcFrameWidth;

	    break;

	case TRANS_ROT180:

	    // NOTE: top left x and y coordinate must reflect the transformation
	    // performed around the reference point

	    // width and height are as before

	    // both X- and Y- offsets from the top left corner may change

	    t_collisionRectX = srcFrameWidth - (collisionRectWidth + 
						collisionRectX);
	    t_collisionRectY = srcFrameHeight - (collisionRectHeight + 
						 collisionRectY);

	    t_collisionRectWidth = collisionRectWidth;
	    t_collisionRectHeight = collisionRectHeight;

  	    // set width and height
  	    this.width = srcFrameWidth;
  	    this.height = srcFrameHeight;

	    break;

	case TRANS_ROT270:

	    // the top-right corner of the rectangle becomes the 
	    // top-left when rotated 270.

	    // both X- and Y-offset to the top left corner may change

	    // update the position information for the collision rectangle

	    t_collisionRectX = collisionRectY;
	    t_collisionRectY = srcFrameWidth - (collisionRectWidth + 
						collisionRectX);

	    t_collisionRectHeight = collisionRectWidth;
	    t_collisionRectWidth = collisionRectHeight;

	    // set width and height
  	    this.width = srcFrameHeight;
  	    this.height = srcFrameWidth;

	    break;

	case TRANS_MIRROR_ROT90:

	    // both X- and Y- offset from the top left corner may change

	    // update the position information for the collision rectangle

	    t_collisionRectX = srcFrameHeight - (collisionRectHeight + 
						 collisionRectY);
	    t_collisionRectY = srcFrameWidth - (collisionRectWidth + 
						collisionRectX);

	    t_collisionRectHeight = collisionRectWidth;
	    t_collisionRectWidth = collisionRectHeight;

	    // set width and height
  	    this.width = srcFrameHeight;
  	    this.height = srcFrameWidth;

	    break;

	case TRANS_MIRROR_ROT270:

	    // both X- and Y- offset from the top left corner may change

	    // update the position information for the collision rectangle

	    t_collisionRectY = collisionRectX;
	    t_collisionRectX = collisionRectY;

	    t_collisionRectHeight = collisionRectWidth;
	    t_collisionRectWidth = collisionRectHeight;

	    // set width and height
  	    this.width = srcFrameHeight;
  	    this.height = srcFrameWidth;

	    break;

	default:
            // INVALID TRANSFORMATION!
	    throw new IllegalArgumentException();

	}
    
public voiddefineCollisionRectangle(int x, int y, int width, int height)
Defines the Sprite's bounding rectangle that is used for collision detection purposes. This rectangle is specified relative to the un-transformed Sprite's upper-left corner and defines the area that is checked for collision detection. For pixel-level detection, only those pixels within the collision rectangle are checked. By default, a Sprite's collision rectangle is located at 0,0 as has the same dimensions as the Sprite. The collision rectangle may be specified to be larger or smaller than the default rectangle; if made larger, the pixels outside the bounds of the Sprite are considered to be transparent for pixel-level collision detection.

param
x the horizontal location of the collision rectangle relative to the untransformed Sprite's left edge
param
y the vertical location of the collision rectangle relative to the untransformed Sprite's top edge
param
width the width of the collision rectangle
param
height the height of the collision rectangle
throws
IllegalArgumentException if the specified width or height is less than 0


	if (width < 0 || height < 0) {
             throw new IllegalArgumentException();
	}

	collisionRectX = x;
	collisionRectY = y;
	collisionRectWidth = width;
	collisionRectHeight = height;

	// call set transform with current transformation to 
	// update transformed sprites collision rectangle
	setTransformImpl(t_currentTransformation);
    
public voiddefineReferencePixel(int x, int y)
Defines the reference pixel for this Sprite. The pixel is defined by its location relative to the upper-left corner of the Sprite's un-transformed frame, and it may lay outside of the frame's bounds.

When a transformation is applied, the reference pixel is defined relative to the Sprite's initial upper-left corner before transformation. This corner may no longer appear as the upper-left corner in the painter's coordinate system under current transformation.

By default, a Sprite's reference pixel is located at (0,0); that is, the pixel in the upper-left corner of the raw frame.

Changing the reference pixel does not change the Sprite's physical position in the painter's coordinate system; that is, the values returned by {@link #getX getX()} and {@link #getY getY()} will not change as a result of defining the reference pixel. However, subsequent calls to methods that involve the reference pixel will be impacted by its new definition.

param
x the horizontal location of the reference pixel, relative to the left edge of the un-transformed frame
param
y the vertical location of the reference pixel, relative to the top edge of the un-transformed frame
see
#setRefPixelPosition
see
#getRefPixelX
see
#getRefPixelY

	dRefX = x;
	dRefY = y;
    
private static booleandoPixelCollision(int image1XOffset, int image1YOffset, int image2XOffset, int image2YOffset, javax.microedition.lcdui.Image image1, int transform1, javax.microedition.lcdui.Image image2, int transform2, int width, int height)
Detect opaque pixel intersection between regions of two images

param
image1XOffset left coordinate in the first image
param
image1YOffset top coordinate in the first image
param
image2XOffset left coordinate in the second image
param
image2YOffset top coordinate in the second image
param
image1 first source image
param
transform1 The transform for the first image
param
image2 second source image
param
transform2 transform set on the second image
param
width width of overlapping region, when transformed
param
height height of overlapping region, when transformed Clarification required on parameters: XOffset and YOffset are the offsets from the top left hand corner of the image. width, height is the dimensions of the intersecting regions in the two transformed images. there fore appropriate conversions have to be made on these dimensions when using the values, according to the transformation that has been set.
return
True if there is a pixel level collision


	// starting point of comparison
	int startY1;
	// x and y increments
	int xIncr1, yIncr1;

	// .. for image 2
	int startY2;
	int xIncr2, yIncr2;

	int numPixels = height * width;

	int[] argbData1 = new int[numPixels];
	int[] argbData2 = new int[numPixels];

	if (0x0 != (transform1 & INVERTED_AXES)) {
	    // inverted axes

	    // scanlength = height

	    if (0x0 != (transform1 & Y_FLIP)) {
		xIncr1 = -(height); // - scanlength

		startY1 = numPixels - height; // numPixels - scanlength
	    } else {
		xIncr1 = height; // + scanlength
		
		startY1 = 0;
	    }

	    if (0x0 != (transform1 &  X_FLIP)) {
		yIncr1 = -1;

		startY1 += (height - 1);
	    } else {
		yIncr1 = +1;
	    }

	    image1.getRGB(argbData1, 0, height, // scanlength = height
			  image1XOffset, image1YOffset, height, width);

	} else {

	    // scanlength = width

	    if (0x0 != (transform1 & Y_FLIP)) {

		startY1 = numPixels - width; // numPixels - scanlength

		yIncr1  = -(width); // - scanlength
	    } else {
		startY1 = 0;

		yIncr1  = width; // + scanlength
	    }

	    if (0x0 != (transform1 &  X_FLIP)) {
		xIncr1  = -1;

		startY1 += (width - 1);
	    } else {
		xIncr1  = +1;
	    }

	    image1.getRGB(argbData1, 0, width, // scanlength = width
			  image1XOffset, image1YOffset, width, height);

	}


	if (0x0 != (transform2 & INVERTED_AXES)) {
	    // inverted axes

	    if (0x0 != (transform2 & Y_FLIP)) {
		xIncr2 = -(height);

		startY2 = numPixels - height;
	    } else {
		xIncr2 = height;

		startY2 = 0;
	    }

	    if (0x0 != (transform2 &  X_FLIP)) {
		yIncr2 = -1;
		
		startY2 += height - 1;
	    } else {
		yIncr2 = +1;
	    }

	    image2.getRGB(argbData2, 0, height,
			  image2XOffset, image2YOffset, height, width);

	} else {

	    if (0x0 != (transform2 & Y_FLIP)) {
		startY2 = numPixels - width;

		yIncr2  = -(width);
	    } else {
		startY2 = 0;

		yIncr2  = +width;
	    }

	    if (0x0 != (transform2 &  X_FLIP)) {
		xIncr2  = -1;

		startY2 += (width - 1);
	    } else {
		xIncr2  = +1;
	    }

	    image2.getRGB(argbData2, 0, width,
			  image2XOffset, image2YOffset, width, height);

	}


	int x1, x2;
	int xLocalBegin1, xLocalBegin2;

	// the loop counters
	int numIterRows;
	int numIterColumns;

	for (numIterRows = 0, xLocalBegin1 = startY1, xLocalBegin2 = startY2;
	    numIterRows < height;
	    xLocalBegin1 += yIncr1, xLocalBegin2 += yIncr2, numIterRows++) {

	    for (numIterColumns = 0, x1 = xLocalBegin1, x2 = xLocalBegin2;
		 numIterColumns < width;
		 x1 += xIncr1, x2 += xIncr2, numIterColumns++) {

		if (((argbData1[x1] & ALPHA_BITMASK) != 0) && 
		    ((argbData2[x2] & ALPHA_BITMASK) != 0)) {

		    return true;
		}
		
	    } // end for x	
	    
	} // end for y
	
	// worst case!  couldn't find a single colliding pixel!
	return false;
    
public final intgetFrame()
Gets the current index in the frame sequence.

The index returned refers to the current entry in the frame sequence, not the index of the actual frame that is displayed.

return
the current index in the frame sequence
see
#setFrameSequence(int[])
see
#setFrame

        return sequenceIndex;
    
public intgetFrameSequenceLength()
Gets the number of elements in the frame sequence. The value returned reflects the length of the Sprite's frame sequence; it does not reflect the number of raw frames. However, these two values will be the same if the default frame sequence is used.

return
the number of elements in this Sprite's frame sequence
see
#getRawFrameCount

        return frameSequence.length;
    
private intgetImageTopLeftX(int x1, int y1, int x2, int y2)
Given a rectangle that lies within the sprite in the painter's coordinates, find the X coordinate of the top left corner in the source image of the sprite

param
x1 the x coordinate of the top left of the rectangle
param
y1 the y coordinate of the top left of the rectangle
param
x2 the x coordinate of the bottom right of the rectangle
param
y2 the y coordinate of the bottom right of the rectangle
return
the X coordinate in the source image

	int retX = 0;

	// left = this.x
	// right = this.x + this.width
	// top = this.y
	// bottom = this.y + this.height

	switch (this.t_currentTransformation) {

	case TRANS_NONE:
	case TRANS_MIRROR_ROT180:
	    retX = x1 - this.x;
	    break;

	case TRANS_MIRROR:
	case TRANS_ROT180:
	    retX = (this.x + this.width) - x2;
	    break;

	case TRANS_ROT90:
	case TRANS_MIRROR_ROT270:
	    retX = y1 - this.y;
	    break;

	case TRANS_ROT270:
	case TRANS_MIRROR_ROT90:
	    retX = (this.y + this.height) - y2;
	    break;
	}

	retX += frameCoordsX[frameSequence[sequenceIndex]];

	return retX;
    
private intgetImageTopLeftY(int x1, int y1, int x2, int y2)
Given a rectangle that lies within the sprite in the painter's coordinates, find the Y coordinate of the top left corner in the source image of the sprite

param
x1 the x coordinate of the top left of the rectangle
param
y1 the y coordinate of the top left of the rectangle
param
x2 the x coordinate of the bottom right of the rectangle
param
y2 the y coordinate of the bottom right of the rectangle
return
the Y coordinate in the source image

	int retY = 0;

	// left = this.x
	// right = this.x + this.width
	// top = this.y
	// bottom = this.y + this.height

	switch (this.t_currentTransformation) {

	case TRANS_NONE:
	case TRANS_MIRROR:
	    retY = y1 - this.y;
	    break;

	case TRANS_ROT180:
	case TRANS_MIRROR_ROT180:
	    retY = (this.y + this.height) - y2;
	    break;

	case TRANS_ROT270:
	case TRANS_MIRROR_ROT270:
	    retY = x1 - this.x;
	    break;

	case TRANS_ROT90:
	case TRANS_MIRROR_ROT90:
	    retY = (this.x + this.width) - x2;
	    break;
	}

	retY += frameCoordsY[frameSequence[sequenceIndex]];

	return retY;
    
public intgetRawFrameCount()
Gets the number of raw frames for this Sprite. The value returned reflects the number of frames; it does not reflect the length of the Sprite's frame sequence. However, these two values will be the same if the default frame sequence is used.

return
the number of raw frames for this Sprite
see
#getFrameSequenceLength

        return numberFrames;
    
public intgetRefPixelX()
Gets the horizontal position of this Sprite's reference pixel in the painter's coordinate system.

return
the horizontal location of the reference pixel
see
#defineReferencePixel
see
#setRefPixelPosition
see
#getRefPixelY

	return (this.x +
		getTransformedPtX(dRefX, dRefY, this.t_currentTransformation));
    
public intgetRefPixelY()
Gets the vertical position of this Sprite's reference pixel in the painter's coordinate system.

return
the vertical location of the reference pixel
see
#defineReferencePixel
see
#setRefPixelPosition
see
#getRefPixelX

	return (this.y + 
		getTransformedPtY(dRefX, dRefY, this.t_currentTransformation));
    
intgetTransformedPtX(int x, int y, int transform)
Given the x and y offsets off a pixel from the top left corner, in an untransformed sprite, calculates the x coordinate of the pixel when the same sprite is transformed, with the coordinates of the top-left pixel of the transformed sprite as (0,0).

param
x Horizontal offset within the untransformed sprite
param
y Vertical offset within the untransformed sprite
param
transform transform for the sprite
return
The x-offset, of the coordinates of the pixel, with the top-left corner as 0 when transformed.


	int t_x = 0;

  	switch (transform) {

  	case TRANS_NONE:
 	    t_x = x;
  	    break;
  	case TRANS_MIRROR:
 	    t_x = srcFrameWidth - x - 1;
  	    break;
  	case TRANS_MIRROR_ROT180:
 	    t_x = x;
  	    break;
  	case TRANS_ROT90:
 	    t_x = srcFrameHeight - y - 1;
  	    break;
  	case TRANS_ROT180:
 	    t_x = srcFrameWidth - x - 1;
  	    break;
  	case TRANS_ROT270:
 	    t_x = y;
  	    break;
  	case TRANS_MIRROR_ROT90:
 	    t_x = srcFrameHeight - y - 1;
  	    break;
  	case TRANS_MIRROR_ROT270:
 	    t_x = y;
  	    break;
  	default:
	    // INVALID TRANSFORMATION!
  	    throw new IllegalArgumentException();

  	}

	return t_x;

    
intgetTransformedPtY(int x, int y, int transform)
Given the x and y offsets off a pixel from the top left corner, in an untransformed sprite, calculates the y coordinate of the pixel when the same sprite is transformed, with the coordinates of the top-left pixel of the transformed sprite as (0,0).

param
x Horizontal offset within the untransformed sprite
param
y Vertical offset within the untransformed sprite
param
transform transform for the sprite
return
The y-offset, of the coordinates of the pixel, with the top-left corner as 0 when transformed.


	int t_y = 0;

  	switch (transform) {
  
  	case TRANS_NONE:
 	    t_y = y;
  	    break;
  	case TRANS_MIRROR:
 	    t_y = y;
  	    break;
  	case TRANS_MIRROR_ROT180:
 	    t_y = srcFrameHeight - y - 1;
  	    break;
  	case TRANS_ROT90:
 	    t_y = x;
  	    break;
  	case TRANS_ROT180:
 	    t_y = srcFrameHeight - y - 1;
  	    break;
  	case TRANS_ROT270:
 	    t_y = srcFrameWidth - x - 1;
  	    break;
  	case TRANS_MIRROR_ROT90:
 	    t_y = srcFrameWidth - x - 1;
  	    break;
  	case TRANS_MIRROR_ROT270:
 	    t_y = x;
  	    break;
  	default:
              // INVALID TRANSFORMATION!
  	    throw new IllegalArgumentException();
  	}

	return t_y;

    
private voidinitCollisionRectBounds()
initialize the collision rectangle


	// reset x and y of collision rectangle
	collisionRectX = 0;
	collisionRectY = 0;

	// intialize the collision rectangle bounds to that of the sprite
	collisionRectWidth = this.width;
	collisionRectHeight = this.height;

    
private voidinitializeFrames(javax.microedition.lcdui.Image image, int fWidth, int fHeight, boolean maintainCurFrame)
create the Image Array.

param
image Image to use for Sprite
param
fWidth width, in pixels, of the individual raw frames
param
fHeight height, in pixels, of the individual raw frames
param
maintainCurFrame true if Current Frame is maintained


	int imageW = image.getWidth();
	int imageH = image.getHeight();
	    
        int numHorizontalFrames = imageW / fWidth;
        int numVerticalFrames   = imageH / fHeight;

	sourceImage = image;

	srcFrameWidth = fWidth;
  	srcFrameHeight = fHeight;

	numberFrames = numHorizontalFrames*numVerticalFrames;

	frameCoordsX = new int[numberFrames];
	frameCoordsY = new int[numberFrames];

        if (!maintainCurFrame) {
	    sequenceIndex = 0;
	}

        if (!customSequenceDefined) {
            frameSequence = new int[numberFrames];
        }

        int currentFrame = 0;

	for (int yy = 0; yy < imageH; yy += fHeight) {
	    for (int xx = 0; xx < imageW; xx += fWidth) {

		frameCoordsX[currentFrame] = xx;
		frameCoordsY[currentFrame] = yy;
	
	        if (!customSequenceDefined) {
                    frameSequence[currentFrame] = currentFrame;
		}
                currentFrame++;

	    }
	}
    
private booleanintersectRect(int r1x1, int r1y1, int r1x2, int r1y2, int r2x1, int r2y1, int r2x2, int r2y2)
Detect rectangle intersection

param
r1x1 left co-ordinate of first rectangle
param
r1y1 top co-ordinate of first rectangle
param
r1x2 right co-ordinate of first rectangle
param
r1y2 bottom co-ordinate of first rectangle
param
r2x1 left co-ordinate of second rectangle
param
r2y1 top co-ordinate of second rectangle
param
r2x2 right co-ordinate of second rectangle
param
r2y2 bottom co-ordinate of second rectangle
return
True if there is rectangle intersection

	if (r2x1 >= r1x2 || r2y1 >= r1y2 || r2x2 <= r1x1 || r2y2 <= r1y1) {
	    return false;
	} else {
	    return true;
	}
    
public voidnextFrame()
Selects the next frame in the frame sequence.

The frame sequence is considered to be circular, i.e. if {@link #nextFrame} is called when at the end of the sequence, this method will advance to the first entry in the sequence.

see
#setFrameSequence(int[])
see
#prevFrame

        sequenceIndex = (sequenceIndex + 1) % frameSequence.length;
    
public final voidpaint(javax.microedition.lcdui.Graphics g)
Draws the Sprite.

Draws current frame of Sprite using the provided Graphics object. The Sprite's upper left corner is rendered at the Sprite's current position relative to the origin of the Graphics object. The current position of the Sprite's upper-left corner can be retrieved by calling {@link #getX()} and {@link #getY()}.

Rendering is subject to the clip region of the Graphics object. The Sprite will be drawn only if it is visible.

If the Sprite's Image is mutable, the Sprite is rendered using the current contents of the Image.

param
g the graphics object to draw Sprite on
throws
NullPointerException if g is null

	// managing the painting order is the responsibility of
	// the layermanager, so depth is ignored
        if (g == null) {
            throw new NullPointerException();
        }

        if (visible) {

                // width and height of the source
                // image is the width and height
                // of the original frame
		g.drawRegion(sourceImage, 
			     frameCoordsX[frameSequence[sequenceIndex]],
			     frameCoordsY[frameSequence[sequenceIndex]],
			     srcFrameWidth, 
			     srcFrameHeight,
			     t_currentTransformation,
			     this.x, 
			     this.y, 
			     Graphics.TOP | Graphics.LEFT);
        }

    
public voidprevFrame()
Selects the previous frame in the frame sequence.

The frame sequence is considered to be circular, i.e. if {@link #prevFrame} is called when at the start of the sequence, this method will advance to the last entry in the sequence.

see
#setFrameSequence(int[])
see
#nextFrame

	if (sequenceIndex == 0) {
            sequenceIndex = frameSequence.length - 1;
	} else {
            sequenceIndex--;
	}
    
public voidsetFrame(int sequenceIndex)
Selects the current frame in the frame sequence.

The current frame is rendered when {@link #paint(Graphics)} is called.

The index provided refers to the desired entry in the frame sequence, not the index of the actual frame itself.

param
sequenceIndex the index of of the desired entry in the frame sequence
throws
IndexOutOfBoundsException if frameIndex is less than0
throws
IndexOutOfBoundsException if frameIndex is equal to or greater than the length of the current frame sequence (or the number of raw frames for the default sequence)
see
#setFrameSequence(int[])
see
#getFrame

        if (sequenceIndex < 0 || sequenceIndex >= frameSequence.length) {
            throw new IndexOutOfBoundsException();
	}
	this.sequenceIndex = sequenceIndex;
    
public voidsetFrameSequence(int[] sequence)
Set the frame sequence for this Sprite.

All Sprites have a default sequence that displays the Sprites frames in order. This method allows for the creation of an arbitrary sequence using the available frames. The current index in the frame sequence is reset to zero as a result of calling this method.

The contents of the sequence array are copied when this method is called; thus, any changes made to the array after this method returns have no effect on the Sprite's frame sequence.

Passing in null causes the Sprite to revert to the default frame sequence.

param
sequence an array of integers, where each integer represents a frame index
throws
ArrayIndexOutOfBoundsException if seq is non-null and any member of the array has a value less than 0 or greater than or equal to the number of frames as reported by {@link #getRawFrameCount()}
throws
IllegalArgumentException if the array has less than 1 element
see
#nextFrame
see
#prevFrame
see
#setFrame
see
#getFrame


        if (sequence == null) {
	    // revert to the default sequence
	    sequenceIndex = 0;
	    customSequenceDefined = false;
	    frameSequence = new int[numberFrames];
	    // copy frames indices into frameSequence
            for (int i = 0; i < numberFrames; i++)
	    {
                frameSequence[i] = i;
            }
            return;
        }

	if (sequence.length < 1) {
             throw new IllegalArgumentException();
	}

        for (int i = 0; i < sequence.length; i++)
	{
            if (sequence[i] < 0 || sequence[i] >= numberFrames) {
		throw new ArrayIndexOutOfBoundsException();
	    }
	}
	customSequenceDefined = true;
	frameSequence = new int[sequence.length];
        System.arraycopy(sequence, 0, frameSequence, 0, sequence.length);
	sequenceIndex = 0;
    
public voidsetImage(javax.microedition.lcdui.Image img, int frameWidth, int frameHeight)
Changes the Image containing the Sprite's frames.

Replaces the current raw frames of the Sprite with a new set of raw frames. See the constructor {@link #Sprite(Image, int, int)} for information on how the frames are created from the image. The values returned by {@link Layer#getWidth} and {@link Layer#getHeight} will reflect the new frame width and frame height subject to the Sprite's current transform.

Changing the image for the Sprite could change the number of raw frames. If the new frame set has as many or more raw frames than the previous frame set, then:

  • The current frame will be unchanged
  • If a custom frame sequence has been defined (using {@link #setFrameSequence(int[])}), it will remain unchanged. If no custom frame sequence is defined (i.e. the default frame sequence is in use), the default frame sequence will be updated to be the default frame sequence for the new frame set. In other words, the new default frame sequence will include all of the frames from the new raw frame set, as if this new image had been used in the constructor.

If the new frame set has fewer frames than the previous frame set, then:

  • The current frame will be reset to entry 0
  • Any custom frame sequence will be discarded and the frame sequence will revert to the default frame sequence for the new frame set.

The reference point location is unchanged as a result of calling this method, both in terms of its defined location within the Sprite and its position in the painter's coordinate system. However, if the frame size is changed and the Sprite has been transformed, the position of the Sprite's upper-left corner may change such that the reference point remains stationary.

If the Sprite's frame size is changed by this method, the collision rectangle is reset to its default value (i.e. it is set to the new bounds of the untransformed Sprite).

param
img the Image to use for Sprite
param
frameWidth the width in pixels of the individual raw frames
param
frameHeight the height in pixels of the individual raw frames
throws
NullPointerException if img is null
throws
IllegalArgumentException if frameHeight or frameWidth is less than 1
throws
IllegalArgumentException if the image width is not an integer multiple of the frameWidth
throws
IllegalArgumentException if the image height is not an integer multiple of the frameHeight


        // if image is null image.getWidth() will throw NullPointerException
        if ((frameWidth < 1 || frameHeight < 1) ||
	    ((img.getWidth() % frameWidth) != 0) ||
	    ((img.getHeight() % frameHeight) != 0)) {
             throw new IllegalArgumentException();
	}

	int noOfFrames = 
          (img.getWidth() / frameWidth)*(img.getHeight() / frameHeight);

	boolean maintainCurFrame = true;
	if (noOfFrames < numberFrames) {
            // use default frame , sequence index = 0
	    maintainCurFrame = false; 
	    customSequenceDefined = false;
	}

	if (! ((srcFrameWidth == frameWidth) &&
               (srcFrameHeight == frameHeight))) {

	    // computing is the location
            // of the reference pixel in the painter's coordinate system.
	    // and then use this to find x and y position of the Sprite
	    int oldX = this.x + 
		getTransformedPtX(dRefX, dRefY, this.t_currentTransformation);

	    int oldY = this.y +
		getTransformedPtY(dRefX, dRefY, this.t_currentTransformation);


	    setWidthImpl(frameWidth);
	    setHeightImpl(frameHeight);

	    initializeFrames(img, frameWidth, frameHeight, maintainCurFrame);

	    // initialize collision rectangle
	    initCollisionRectBounds();

	    // set the new x and y position of the Sprite
	    this.x = oldX - 
		getTransformedPtX(dRefX, dRefY, this.t_currentTransformation);

	    this.y = oldY -
		getTransformedPtY(dRefX, dRefY, this.t_currentTransformation);


	    // Calculate transformed sprites collision rectangle
	    // and transformed width and height

	    computeTransformedBounds(this.t_currentTransformation);

	} else {
	    // just reinitialize the animation frames.
	    initializeFrames(img, frameWidth, frameHeight, maintainCurFrame);
	}

    
public voidsetRefPixelPosition(int x, int y)
Sets this Sprite's position such that its reference pixel is located at (x,y) in the painter's coordinate system.

param
x the horizontal location at which to place the reference pixel
param
y the vertical location at which to place the reference pixel
see
#defineReferencePixel
see
#getRefPixelX
see
#getRefPixelY


	// update this.x and this.y
	this.x = x - getTransformedPtX(dRefX, dRefY, 
				       this.t_currentTransformation);
	this.y = y - getTransformedPtY(dRefX, dRefY, 
				       this.t_currentTransformation);

    
public voidsetTransform(int transform)
Sets the transform for this Sprite. Transforms can be applied to a Sprite to change its rendered appearance. Transforms are applied to the original Sprite image; they are not cumulative, nor can they be combined. By default, a Sprite's transform is {@link #TRANS_NONE}.

Since some transforms involve rotations of 90 or 270 degrees, their use may result in the overall width and height of the Sprite being swapped. As a result, the values returned by {@link Layer#getWidth} and {@link Layer#getHeight} may change.

The collision rectangle is also modified by the transform so that it remains static relative to the pixel data of the Sprite. Similarly, the defined reference pixel is unchanged by this method, but its visual location within the Sprite may change as a result.

This method repositions the Sprite so that the location of the reference pixel in the painter's coordinate system does not change as a result of changing the transform. Thus, the reference pixel effectively becomes the centerpoint for the transform. Consequently, the values returned by {@link #getRefPixelX} and {@link #getRefPixelY} will be the same both before and after the transform is applied, but the values returned by {@link #getX getX()} and {@link #getY getY()} may change.

param
transform the desired transform for this Sprite
throws
IllegalArgumentException if the requested transform is invalid
see
#TRANS_NONE
see
#TRANS_ROT90
see
#TRANS_ROT180
see
#TRANS_ROT270
see
#TRANS_MIRROR
see
#TRANS_MIRROR_ROT90
see
#TRANS_MIRROR_ROT180
see
#TRANS_MIRROR_ROT270

	setTransformImpl(transform);
    
private voidsetTransformImpl(int transform)
Sets the transform for this Sprite

param
transform the desired transform for this Sprite


	// ---

	// setTransform sets up all transformation related data structures
	// except transforming the current frame's bitmap.
	
	// x, y, width, height, dRefX, dRefY, 
	// collisionRectX, collisionRectY, collisionRectWidth,
	// collisionRectHeight, t_currentTransformation,
	// t_bufferImage

	// The actual tranformed frame is drawn at paint time.

	// ---

	// update top-left corner position
	this.x = this.x + 
	    getTransformedPtX(dRefX, dRefY, this.t_currentTransformation) -
	    getTransformedPtX(dRefX, dRefY, transform);

	this.y = this.y +
	    getTransformedPtY(dRefX, dRefY, this.t_currentTransformation) -
	    getTransformedPtY(dRefX, dRefY, transform);

	// Calculate transformed sprites collision rectangle
	// and transformed width and height
	computeTransformedBounds(transform);

	// set the current transform to be the one requested
	t_currentTransformation = transform;