Search code examples
javagraphics2d-games

Slow map in java


I'm making a game in java, is a rpg, however, only with the map the game is slow. The map is made ​​in TiledMap Editor, therefore, an XML that is read and loaded into an ArrayList. My PC is a dual-core 3.0, 4GB RAM, 1GB Video. The do the rendering is done as follows:

//method of tileset class
public void loadTileset(){
    positions = new int[1 + tilesX * tilesY][2];
    int yy = 0;
    int xx = 0;
    int index = 0;
    // save the initial x and y point of each tile in an array named positions 
    // positions[tileNumber] [0] - X position 
    // positions[tileNumber] [1] - Y position
    for(int i = 1 ; i < positions.length; i++){ 
        if(index == tilesX ){
            yy += tileHeight;
            xx = 0;
            index = 0;
        }
        positions[i][0] = xx;
        positions[i][1] = yy;
        xx += tileWidth;    
        index++;
    }
}


//method of map class
public void draw(Graphics2D screen){
    //x and y position of each tile on the screen
    int x = 0; int y = 0;

    for(int j = 0; j < 20 ; j++){
        for(int i = initialTile ; i < initialTile + quantTiles  ; i++){
            int tile = map[j][i];
            if(tile != 0){
                screen.drawImage(tileSet.getTileImage().getSubimage(tileSet.getTileX(tile), tileSet.getTileY(tile),tileSet.getTileWidth(), tileSet.getTileHeight()),x,y,null);
            }
            x += tileSet.getTileWidth();
        }
        x = 0;
        y += tileSet.getTileHeight();
    }

}

Am I doing something wrong? Note: I'm new to the forum and to make matters worse I do not understand very much English, so excuse any mistake.


Solution

  • First of all, you should not create the subimages for the tiles during each call. Strictly speaking, you should not call getSubimage at all for images that you want to paint: It will make the image "unmanaged", and this can degrade rendering performance by an order of magnitude. You should only call getSubimage for images that you do not want to render - for example, when you are initially creating individual images for the tiles.

    You obviously already have a TileSet class. You could add a bit of functionality to this class so that you can directly access images for the tiles.

    Your current code looks like this:

    screen.drawImage(
        tileSet.getTileImage().getSubimage(
            tileSet.getTileX(tile), 
            tileSet.getTileY(tile),
            tileSet.getTileWidth(), 
            tileSet.getTileHeight()),
        x,y,null);
    

    You could change it to look like this:

    screen.drawImage(tileSet.getTileImage(tile), x,y,null);
    

    The getTileImage(int tile) method suggested here could then obtain tiles that have been stored internally.

    I'll sketch a few lines of code from the tip of my head, you'll probably be able to transfer this into your TileSet class:

    class TileSet
    {
        private Map<Integer, BufferedImage> tileImages;
    
        TileSet()
        {
            ....
            prepareTileImages();
        }
    
        private void prepareTileImages()
        {
            tileImages = new HashMap<Integer, BufferedImage>();
    
            for (int tile : allPossibleTileValuesThatMayBeInTheMap)
            {
                // These are the tiles that you originally rendered
                // in your "draw"-Method
                BufferedImage image = 
                    getTileImage().getSubimage(
                        getTileX(tile), 
                        getTileY(tile),
                        getTileWidth(), 
                        getTileHeight());
    
                // Create a new, managed copy of the image,
                // and store it in the map
                BufferedImage managedImage = convertToARGB(image);
                tileImages.put(tile, managedImage);
            }
        }
    
        private static BufferedImage convertToARGB(BufferedImage image)
        {
            BufferedImage newImage = new BufferedImage(
                image.getWidth(), image.getHeight(),
                BufferedImage.TYPE_INT_ARGB);
            Graphics2D g = newImage.createGraphics();
            g.drawImage(image, 0, 0, null);
            g.dispose();
            return newImage;
        }    
    
        // This is the new method: For a given "tile" value
        // that you found at map[x][y], this returns the
        // appropriate tile:
        public BufferedImage getTileImage(int tile) 
        {
            return tileImages.get(tile);
        }
    }