All Downloads are FREE. Search and download functionalities are using the official Maven repository.

javax.microedition.lcdui.game.TiledLayer Maven / Gradle / Ivy

/*
 *  MicroEmulator
 *  Copyright (C) 2005 Andres Navarro
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License as published by the Free Software Foundation; either
 *  version 2.1 of the License, or (at your option) any later version.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

package javax.microedition.lcdui.game;

import javax.microedition.lcdui.Graphics;
import javax.microedition.lcdui.Image;

/**
 *
 * @author Andres Navarro
 */


// Synchronization is important because of two things:
// first setStaticTileSet can change the whole Object
// so any function could be running at the same time as a setStaticTileSet
// and have inconsistent behaviour
// second is the animated tiles, their indexes should be consecutive and 
// two simultaneus createAnimatedTile methods could blow that up.
// One would expect only one thread accessing this class at the same time
// but it becomes a little tricky when you consider that repaints access this
// class and you have no control or knowledge of the repaint thread on most
// systems

public class TiledLayer extends Layer {
    private final int rows, cols;
    // package access for collision detection
    Image img;

    private int tileHeight, tileWidth, numStaticTiles;
    
    
    // the matrix for storing the tiles
    private int [][]tiles;
    
    // the list of anmated tiles
    // NOTE the first animatedTile (index -1) goes
    // into the first position in the array (index 0)
    // so to access the correct tile use animatedTiles[-n-1]
    int []animatedTiles;
    // the ammount of animated tiles
    int numAnimatedTiles;
    
    public TiledLayer(int cols, int rows, Image img, int tileWidth, int tileHeight) {
        // the specification doesn't states if the TiledLayer is visible on creation
        // we assume it is
        super(0, 0, cols * tileWidth, rows * tileHeight, true);
        
        if (img == null)
            throw new NullPointerException();
        if (cols <= 0 || rows <= 0 || tileHeight <= 0 || tileWidth <= 0)
            throw new IllegalArgumentException();
        if (img.getWidth() % tileWidth != 0 || img.getHeight() % tileHeight != 0)
            throw new IllegalArgumentException();
        
        this.img = img;
        this.cols = cols;
        this.rows = rows;
        this.tileWidth = tileWidth;
        this.tileHeight = tileHeight;
        this.numStaticTiles = (img.getWidth() / tileWidth) * (img.getHeight() / tileHeight);
        this.tiles = new int[rows][cols];
        this.animatedTiles = new int[5];
        this.numAnimatedTiles = 0;
    }
    
    // it is synchronized to avoid problems with the animatedTiles array and count
    public int createAnimatedTile(int staticTileIndex) {
    	synchronized (this) {
	        if (staticTileIndex < 0 || staticTileIndex > numStaticTiles)
	            throw new IndexOutOfBoundsException();
	        
	        if (numAnimatedTiles == animatedTiles.length) {
	            int [] temp = new int [numAnimatedTiles + 6];
	            System.arraycopy(animatedTiles, 0, temp, 0, numAnimatedTiles);
	            animatedTiles = temp;
	        }
	        
	        animatedTiles[numAnimatedTiles] = staticTileIndex; 
	        numAnimatedTiles++;
	        return -numAnimatedTiles;
    	}
    }
    
    public int getAnimatedTile(int index) {
    	synchronized (this) {
	        index = -index-1;
	        if (index < 0 || index >= numAnimatedTiles)
	            throw new IndexOutOfBoundsException();
	        return animatedTiles[index];
    	}
    }
    
    public void setAnimatedTile(int index, int staticTileIndex) {
    	synchronized (this) {
	        index = -index-1;
	        if (index < 0 || index >= numAnimatedTiles)
	            throw new IndexOutOfBoundsException();
	        if (staticTileIndex < 0 || staticTileIndex > numStaticTiles)
	            throw new IndexOutOfBoundsException();
	        
	        animatedTiles[index] = staticTileIndex;
    	}
    }
    
    public int getCell(int col, int row) {
        return this.tiles[row][col];
    }

    public void setCell(int col, int row, int index) {
    	synchronized (this) {
	        if (-index-1 >= numAnimatedTiles || index > numStaticTiles)
	            throw new IndexOutOfBoundsException();
	        tiles[row][col] = index;
    	}
    }
    
    public void setStaticTileSet(Image image, int tileWidth, int tileHeight) {
    	synchronized (this) {
	        if (img == null)
	            throw new NullPointerException();
	        if (tileHeight <= 0 || tileWidth <= 0)
	            throw new IllegalArgumentException();
	        if (img.getWidth() % tileWidth != 0 || img.getHeight() % tileHeight != 0)
	            throw new IllegalArgumentException();
	
	        int newNumStaticTiles = (img.getWidth() / getCellWidth()) * 
	                                    (img.getHeight() / getCellHeight());
	        
	        
	        // recalculate size
	        int w = cols * tileWidth;
	        int h = rows * tileHeight;
	        
	        setSize(w, h);
	        
	        this.img = img;
	        this.tileWidth = tileWidth;
	        this.tileHeight = tileHeight;
	        
	        if (newNumStaticTiles >= numStaticTiles) {
	            this.numStaticTiles = newNumStaticTiles;
	            return;
	        }
	        // if there are less static tiles
	        // all animated tiles are discarded and
	        // the tiledLayer is filled with tiles with index 0
	
	        this.numStaticTiles = newNumStaticTiles;
	        this.animatedTiles = new int[5];
	        this.numAnimatedTiles = 0;
	        this.fillCells(0, 0, getColumns(), getRows(), 0);
    	}
    }

    public void fillCells(int col, int row, int numCols, int numRows, int index) {
    	synchronized (this) {
	        if (numCols < 0 || numRows < 0)
	            throw new IllegalArgumentException();
	        if (row < 0 || col < 0 || col + numCols > this.cols || row + numRows > this.rows)    
	            throw new IndexOutOfBoundsException();
	        if (-index-1 >= numAnimatedTiles || index > numStaticTiles)
	            throw new IndexOutOfBoundsException();
	        
	        int rMax = row + numRows;
	        int cMax = col + numCols;
	        for (int r = row; r < rMax; r++) {
	            for (int c = col; c < cMax; c++) {
	                tiles[r][c] = index; 
	            }
	        }
    	}
    }
    
    // dont need for synch here as columns are a constant
    // after creation
    public final int getColumns() {
        return cols;
    }
    
    // dont need for synch here as rows are a constant
    // after creation
    public final int getRows() {
        return rows;
    }
    
    public final int getCellWidth() {
        return tileWidth;
    }
    
    public final int getCellHeight() {
        return tileHeight;
    }
    
    public final void paint(Graphics g) {
    	synchronized (this) {
	        if (!this.isVisible())
	            return;
	        
	        int x = getX();
	        int y = getY();
	
	        int c0 = 0;
	        int r0 = 0;
	        int cMax = getColumns();
	        int rMax = getRows();
	        
	        int tW = getCellWidth();
	        int tH = getCellHeight();
	        
	        int cX = g.getClipX();
	        int cY = g.getClipY();
	        int cW = g.getClipWidth();
	        int cH = g.getClipHeight();
	        
	        // take out the columns and rows that are outside of
	        // the clip area, this should speed things up a bit
/*	        
	        int diff = cX - x;
	        if (diff > 0)
	            c0 += diff / tW;
	        
	        diff = cX + cW - (x + cMax*tW);
	        if (diff > 0)
	            cMax -= diff / tW;
	
	        diff = cY - y;
	        if (diff > 0)
	            r0 += diff / tH;
	        
	        diff = cY + cH - (x + rMax*tH);
	        if (diff > 0)
	            rMax -= diff / tH;
*/	        
	        int x0 = x;
	        int anchor = Graphics.LEFT | Graphics.TOP;
	        
	        int imgCols = img.getWidth() / tW;
	        int imgRows = img.getHeight() / tH;
	                
	        for (int r = r0; r < rMax; r++, y += tH) {
	            x = x0;
	            for (int c = c0; c < cMax; c++, x += tW) {
	                int tile = getCell(c, r);
	                if (tile < 0)
	                    tile = getAnimatedTile(tile);
	                if (tile == 0)
	                    continue;
	                
	                tile--;
	                
	                int xSrc = tW * (tile % imgCols);
	                int ySrc = (tile / imgCols) * tH;
	                
	                g.drawRegion(img, xSrc, ySrc, tW, tH, Sprite.TRANS_NONE, x, y, anchor);
	            }
	        }
    	}
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy