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

TiledLayer

public class TiledLayer extends Layer
A TiledLayer is a visual element composed of a grid of cells that can be filled with a set of tile images. This class allows large virtual layers to be created without the need for an extremely large Image. This technique is commonly used in 2D gaming platforms to create very large scrolling backgrounds,

Tiles

The tiles used to fill the TiledLayer's cells are provided in a single Image object which may be mutable or immutable. The Image is broken up into a series of equally-sized tiles; the tile size is specified along with the Image. As shown in the figure below, the same tile set can be stored in several different arrangements depending on what is the most convenient for the game developer.
Tiles

Each tile is assigned a unique index number. The tile located in the upper-left corner of the Image is assigned an index of 1. The remaining tiles are then numbered consecutively in row-major order (indices are assigned across the first row, then the second row, and so on). These tiles are regarded as static tiles because there is a fixed link between the tile and the image data associated with it.

A static tile set is created when the TiledLayer is instantiated; it can also be updated at any time using the {@link #setStaticTileSet} method.

In addition to the static tile set, the developer can also define several animated tiles. An animated tile is a virtual tile that is dynamically associated with a static tile; the appearance of an animated tile will be that of the static tile that it is currently associated with.

Animated tiles allow the developer to change the appearance of a group of cells very easily. With the group of cells all filled with the animated tile, the appearance of the entire group can be changed by simply changing the static tile associated with the animated tile. This technique is very useful for animating large repeating areas without having to explicitly change the contents of numerous cells.

Animated tiles are created using the {@link #createAnimatedTile} method, which returns the index to be used for the new animated tile. The animated tile indices are always negative and consecutive, beginning with -1. Once created, the static tile associated with an animated tile can be changed using the {@link #setAnimatedTile} method.

Cells

The TiledLayer's grid is made up of equally sized cells; the number of rows and columns in the grid are specified in the constructor, and the physical size of the cells is defined by the size of the tiles.

The contents of each cell is specified by means of a tile index; a positive tile index refers to a static tile, and a negative tile index refers to an animated tile. A tile index of 0 indicates that the cell is empty; an empty cell is fully transparent and nothing is drawn in that area by the TiledLayer. By default, all cells contain tile index 0.

The contents of cells may be changed using {@link #setCell} and {@link #fillCells}. Several cells may contain the same tile; however, a single cell cannot contain more than one tile. The following example illustrates how a simple background can be created using a TiledLayer.

TiledLayer Grid

In this example, the area of water is filled with an animated tile having an index of -1, which is initially associated with static tile 5. The entire area of water may be animated by simply changing the associated static tile using setAnimatedTile(-1, 7).
TiledLayer Grid 2

Rendering a TiledLayer

A TiledLayer can be rendered by manually calling its paint method; it can also be rendered automatically using a LayerManager object.

The paint method will attempt to render the entire TiledLayer subject to the clip region of the Graphics object; the upper left corner of the TiledLayer is rendered at its current (x,y) position relative to the Graphics object's origin. The rendered region may be controlled by setting the clip region of the Graphics object accordingly.

since
MIDP 2.0

Fields Summary
private int
cellHeight
the overall height of the TiledLayer grid
private int
cellWidth
the overall cell width of the TiledLayer grid
private int
rows
The num of rows of the TiledLayer grid.
private int
columns
the num of columns in the TiledLayer grid
private int[]
cellMatrix
int array for storing row and column of cell it contains the tile Index for both static and animated tiles
javax.microedition.lcdui.Image
sourceImage
Source image for tiles
private int
numberOfTiles
no. of tiles
int[]
tileSetX
X co-ordinate definitions for individual frames into the source image
int[]
tileSetY
Y co-ordinate definitions for individual frames into the source image
private int[]
anim_to_static
Table to map from animated Index to static Index 0th location is unused. anim --> static Index -1 --> 21 -2 --> 34 -3 --> 45 for now keep 0 the location of the table empty instead of computing -index make index +ve and access this Table.
private int
numOfAnimTiles
total number of animated tiles. This variable is also used as index in the above table to add new entries to the anim_to_static table. initialized to 1 when table is created.
Constructors Summary
public TiledLayer(int columns, int rows, javax.microedition.lcdui.Image image, int tileWidth, int tileHeight)
Creates a new TiledLayer.

The TiledLayer's grid will be rows cells high and columns cells wide. All cells in the grid are initially empty (i.e. they contain tile index 0). The contents of the grid may be modified through the use of {@link #setCell} and {@link #fillCells}.

The static tile set for the TiledLayer is created from the specified Image with each tile having the dimensions of tileWidth x tileHeight. The width of the source image must be an integer multiple of the tile width, and the height of the source image must be an integer multiple of the tile height; otherwise, an IllegalArgumentException is thrown;

The entire static tile set can be changed using {@link #setStaticTileSet(Image, int, int)}. These methods should be used sparingly since they are both memory and time consuming. Where possible, animated tiles should be used instead to animate tile appearance.

param
columns the width of the TiledLayer, expressed as a number of cells
param
rows the height of the TiledLayer, expressed as a number of cells
param
image the Image to use for creating the static tile set
param
tileWidth the width in pixels of a single tile
param
tileHeight the height in pixels of a single tile
throws
NullPointerException if image is null
throws
IllegalArgumentException if the number of rows or columns is less than 1
throws
IllegalArgumentException if tileHeight or tileWidth is less than 1
throws
IllegalArgumentException if the image width is not an integer multiple of the tileWidth
throws
IllegalArgumentException if the image height is not an integer multiple of the tileHeight

	// IllegalArgumentException will be thrown 
	// in the Layer super-class constructor
        super(columns < 1 || tileWidth < 1 ? -1 : columns * tileWidth, 
	         rows < 1 || tileHeight < 1 ? -1 : rows * tileHeight);

        // if img is null img.getWidth() will throw NullPointerException
        if (((image.getWidth() % tileWidth) != 0) || 
            ((image.getHeight() % tileHeight) != 0)) {
             throw new IllegalArgumentException();
	}
        this.columns = columns;
	this.rows = rows;

        cellMatrix = new int[rows][columns];

        int noOfFrames = 
            (image.getWidth() / tileWidth) * (image.getHeight() / tileHeight);
        // the zero th index is left empty for transparent tile
        // so it is passed in  createStaticSet as noOfFrames + 1
        // Also maintain static indices is true
	// all elements of cellMatrix[][] 
	// are set to zero by new, so maintainIndices = true
        createStaticSet(image,  noOfFrames + 1, tileWidth, tileHeight, true);
    
Methods Summary
public intcreateAnimatedTile(int staticTileIndex)
Creates a new animated tile and returns the index that refers to the new animated tile. It is initially associated with the specified tile index (either a static tile or 0).

The indices for animated tiles are always negative. The first animated tile shall have the index -1, the second, -2, etc.

param
staticTileIndex the index of the associated tile (must be 0 or a valid static tile index)
return
the index of newly created animated tile
throws
IndexOutOfBoundsException if the staticTileIndex is invalid

        // checks static tile 
        if (staticTileIndex < 0 || staticTileIndex >= numberOfTiles) { 
	    throw new IndexOutOfBoundsException();
	}

        if (anim_to_static == null) {
	    anim_to_static = new int[4];
	    numOfAnimTiles = 1;
        } else if (numOfAnimTiles == anim_to_static.length) {
	    // grow anim_to_static table if needed 
	    int new_anim_tbl[] = new int[anim_to_static.length * 2];
	    System.arraycopy(anim_to_static, 0, 
                         new_anim_tbl, 0, anim_to_static.length);
	    anim_to_static = new_anim_tbl;
	}
	anim_to_static[numOfAnimTiles] = staticTileIndex;
	numOfAnimTiles++;
        return (-(numOfAnimTiles - 1));
    
private voidcreateStaticSet(javax.microedition.lcdui.Image image, int noOfFrames, int tileWidth, int tileHeight, boolean maintainIndices)
create the Image Array.

param
image Image to use for creating the static tile set
param
noOfFrames total number of frames
param
tileWidth The width, in pixels, of a single tile
param
tileHeight The height, in pixels, of a single tile
param
maintainIndices


        cellWidth = tileWidth;
        cellHeight = tileHeight;

	int imageW = image.getWidth();
	int imageH = image.getHeight();

	sourceImage = image;

	numberOfTiles = noOfFrames;
	tileSetX = new int[numberOfTiles];
	tileSetY = new int[numberOfTiles];
	
	if (!maintainIndices) {
            // populate cell matrix, all the indices are 0 to begin with
            for (rows = 0; rows < cellMatrix.length; rows++) {
                int totalCols = cellMatrix[rows].length;
                for (columns = 0; columns < totalCols; columns++) {
                    cellMatrix[rows][columns] = 0;
                }
            }
	    // delete animated tiles
	    anim_to_static = null;
	} 

        int currentTile = 1;

        for (int y = 0; y < imageH; y += tileHeight) {
            for (int x = 0; x < imageW; x += tileWidth) {

		tileSetX[currentTile] = x;
		tileSetY[currentTile] = y;

                currentTile++;
            }
        }
    
public voidfillCells(int col, int row, int numCols, int numRows, int tileIndex)
Fills a region cells with the specific tile. The cells may be filled with a static tile index, an animated tile index, or they may be left empty (index 0).

param
col the column of top-left cell in the region
param
row the row of top-left cell in the region
param
numCols the number of columns in the region
param
numRows the number of rows in the region
param
tileIndex the Index of the tile to place in all cells in the specified region
throws
IndexOutOfBoundsException if the rectangular region defined by the parameters extends beyond the bounds of the TiledLayer grid
throws
IllegalArgumentException if numCols is less than zero
throws
IllegalArgumentException if numRows is less than zero
throws
IndexOutOfBoundsException if there is no tile with index tileIndex
see
#setCell
see
#getCell


        if (col < 0 || col >= this.columns || row < 0 || row >= this.rows ||
                   numCols < 0 || col + numCols > this.columns ||
                   numRows < 0 || row + numRows > this.rows) {
            throw new IndexOutOfBoundsException();
        }

	if (tileIndex > 0) {
            // do checks for static tile 
            if (tileIndex >= numberOfTiles) { 
	        throw new IndexOutOfBoundsException();
	    }
	} else if (tileIndex < 0) {
            // do animated tile index check
	    if (anim_to_static == null || 
                (-tileIndex) >= numOfAnimTiles) { 
	            throw new IndexOutOfBoundsException();
            }
	}

        for (int rowCount = row; rowCount < row + numRows; rowCount++) {
            for (int columnCount = col; 
                     columnCount < col + numCols; columnCount++) {
                cellMatrix[rowCount][columnCount] = tileIndex;
            }
        }
    
public intgetAnimatedTile(int animatedTileIndex)
Gets the tile referenced by an animated tile.

Returns the tile index currently associated with the animated tile.

param
animatedTileIndex the index of the animated tile
return
the index of the tile reference by the animated tile
throws
IndexOutOfBoundsException if the animated tile index is invalid
see
#setAnimatedTile

        animatedTileIndex = - animatedTileIndex;
        if (anim_to_static == null || animatedTileIndex <= 0 
                   || animatedTileIndex >= numOfAnimTiles) { 
	    throw new IndexOutOfBoundsException();
        }
	
        return anim_to_static[animatedTileIndex];
    
public intgetCell(int col, int row)
Gets the contents of a cell.

Gets the index of the static or animated tile currently displayed in a cell. The returned index will be 0 if the cell is empty.

param
col the column of cell to check
param
row the row of cell to check
return
the index of tile in cell
throws
IndexOutOfBoundsException if row or col is outside the bounds of the TiledLayer grid
see
#setCell
see
#fillCells

        if (col < 0 || col >= this.columns || row < 0 || row >= this.rows) {
            throw new IndexOutOfBoundsException();
        }
        return cellMatrix[row][col];
    
public final intgetCellHeight()
Gets the height of a single cell, in pixels.

return
the height in pixels of a single cell in the TiledLayer grid

        return cellHeight;
    
public final intgetCellWidth()
Gets the width of a single cell, in pixels.

return
the width in pixels of a single cell in the TiledLayer grid

        return cellWidth;
    
public final intgetColumns()
Gets the number of columns in the TiledLayer grid. The overall width of the TiledLayer, in pixels, may be obtained by calling {@link #getWidth}.

return
the width in columns of the TiledLayer grid

        return columns;
    
public final intgetRows()
Gets the number of rows in the TiledLayer grid. The overall height of the TiledLayer, in pixels, may be obtained by calling {@link #getHeight}.

return
the height in rows of the TiledLayer grid

        return rows;
    
public final voidpaint(javax.microedition.lcdui.Graphics g)
Draws the TiledLayer. The entire TiledLayer is rendered subject to the clip region of the Graphics object. The TiledLayer's upper left corner is rendered at the TiledLayer's current position relative to the origin of the Graphics object. The current position of the TiledLayer's upper-left corner can be retrieved by calling {@link #getX()} and {@link #getY()}. The appropriate use of a clip region and/or translation allows an arbitrary region of the TiledLayer to be rendered.

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

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


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

        if (visible) {
	    int tileIndex = 0;

	    // y-coordinate
	    int ty        = this.y;
            for (int row = 0; 
                   row < cellMatrix.length; row++, ty += cellHeight) {

	        // reset the x-coordinate at the beginning of every row
                // x-coordinate to draw tile into
	        int tx = this.x;
		int totalCols = cellMatrix[row].length;

                for (int column = 0; column < totalCols; 
		    column++, tx += cellWidth) {
		
                    tileIndex = cellMatrix[row][column];
	            // check the indices 
		    // if animated get the corresponding 
		    // static index from anim_to_static table
		    if (tileIndex == 0) { // transparent tile
			continue;
                    } else if (tileIndex < 0) {
                        tileIndex = getAnimatedTile(tileIndex);
		    }

		    g.drawRegion(sourceImage, 
				 tileSetX[tileIndex], 
				 tileSetY[tileIndex], 
				 cellWidth, cellHeight,
				 Sprite.TRANS_NONE,
				 tx, ty,
				 Graphics.TOP | Graphics.LEFT);

                }
            }
	}
    
public voidsetAnimatedTile(int animatedTileIndex, int staticTileIndex)
Associates an animated tile with the specified static tile.

param
animatedTileIndex the index of the animated tile
param
staticTileIndex the index of the associated tile (must be 0 or a valid static tile index)
throws
IndexOutOfBoundsException if the staticTileIndex is invalid
throws
IndexOutOfBoundsException if the animated tile index is invalid
see
#getAnimatedTile

        // checks static tile
        if (staticTileIndex < 0 || staticTileIndex >= numberOfTiles) {  
	    throw new IndexOutOfBoundsException();
	}
        // do animated tile index check
	animatedTileIndex = - animatedTileIndex;
	if (anim_to_static == null || animatedTileIndex <= 0 
            || animatedTileIndex >= numOfAnimTiles) { 
	    throw new IndexOutOfBoundsException();
        }

        anim_to_static[animatedTileIndex] = staticTileIndex;

    
public voidsetCell(int col, int row, int tileIndex)
Sets the contents of a cell.

The contents may be set to a static tile index, an animated tile index, or it may be left empty (index 0)

param
col the column of cell to set
param
row the row of cell to set
param
tileIndex the index of tile to place in cell
throws
IndexOutOfBoundsException if there is no tile with index tileIndex
throws
IndexOutOfBoundsException if row or col is outside the bounds of the TiledLayer grid
see
#getCell
see
#fillCells


        if (col < 0 || col >= this.columns || row < 0 || row >= this.rows) {
            throw new IndexOutOfBoundsException();
        }

	if (tileIndex > 0) {
            // do checks for static tile 
            if (tileIndex >= numberOfTiles) { 
	        throw new IndexOutOfBoundsException();
	    }
	} else if (tileIndex < 0) {
            // do animated tile index check
	    if (anim_to_static == null ||
                (-tileIndex) >= numOfAnimTiles) { 
	        throw new IndexOutOfBoundsException();
            }
	}

        cellMatrix[row][col] = tileIndex;
 
    
public voidsetStaticTileSet(javax.microedition.lcdui.Image image, int tileWidth, int tileHeight)
Change the static tile set.

Replaces the current static tile set with a new static tile set. See the constructor {@link #TiledLayer(int, int, Image, int, int)} for information on how the tiles are created from the image.

If the new static tile set has as many or more tiles than the previous static tile set, the the animated tiles and cell contents will be preserve. If not, the contents of the grid will be cleared (all cells will contain index 0) and all animated tiles will be deleted.

param
image the Image to use for creating the static tile set
param
tileWidth the width in pixels of a single tile
param
tileHeight the height in pixels of a single tile
throws
NullPointerException if image is null
throws
IllegalArgumentException if tileHeight or tileWidth is less than 1
throws
IllegalArgumentException if the image width is not an integer multiple of the tileWidth
throws
IllegalArgumentException if the image height is not an integer multiple of the tileHeight

        // if img is null img.getWidth() will throw NullPointerException
        if (tileWidth < 1 || tileHeight < 1 ||
	    ((image.getWidth() % tileWidth) != 0) || 
            ((image.getHeight() % tileHeight) != 0)) {
             throw new IllegalArgumentException();
	}
        setWidthImpl(columns * tileWidth);
	setHeightImpl(rows * tileHeight);

        int noOfFrames = 
          (image.getWidth() / tileWidth) * (image.getHeight() / tileHeight);

        // the zero th index is left empty for transparent tile
        // so it is passed in  createStaticSet as noOfFrames + 1

	if (noOfFrames >= (numberOfTiles - 1)) {
	    // maintain static indices
	    createStaticSet(image, noOfFrames + 1, tileWidth, tileHeight, true);
	} else {
            createStaticSet(image, noOfFrames + 1, tileWidth, 
                                tileHeight, false);
	}