How to render multiple map layers and make the map rendering more efficient

So, i want to know how to render multiple map layers. I have tried to do it already but it seems to not work… I also want to know how to make the map render more efficiently because if i have a map that is 300 tiles long and 300 tiles tall it drops to like 20 fps.

World Class:

public class World {

	private Handler handler;
	private int width, height;
	@SuppressWarnings("unused")
	private int spawnX, spawnY;
	private int[][] backgroundTile;
	private int[][] collideTile;
	private int[][] foregroundTile;

	public World(Handler handler, String path) {
		this.handler = handler;
		loadWorld(path);
	}

	public void update() {

	}

	public void renderBackground(Graphics g) {
		int xStart = (int) Math.max(0, handler.getCamera().getxOffset()
				/ Tile.TILEWIDTH);
		int xEnd = (int) Math.min(width,
				(handler.getCamera().getxOffset() + Main.WIDTH)
						/ Tile.TILEWIDTH + 1);
		int yStart = (int) Math.max(0, handler.getCamera().getyOffset()
				/ Tile.TILEHEIGHT);
		int yEnd = (int) Math.min(height,
				(handler.getCamera().getyOffset() + Main.HEIGHT)
						/ Tile.TILEHEIGHT + 1);

		for (int y = yStart; y < yEnd; y++) {
			for (int x = xStart; x < xEnd; x++) {
				getTile(x, y).render(
						g,
						(int) (x * Tile.TILEWIDTH - handler.getCamera()
								.getxOffset()),
						(int) (y * Tile.TILEHEIGHT - handler.getCamera()
								.getyOffset()));
			}
		}
	}

	public void renderCollision(Graphics g) {
		int xStart = (int) Math.max(0, handler.getCamera().getxOffset()
				/ Tile.TILEWIDTH);
		int xEnd = (int) Math.min(width,
				(handler.getCamera().getxOffset() + Main.WIDTH)
						/ Tile.TILEWIDTH + 1);
		int yStart = (int) Math.max(0, handler.getCamera().getyOffset()
				/ Tile.TILEHEIGHT);
		int yEnd = (int) Math.min(height,
				(handler.getCamera().getyOffset() + Main.HEIGHT)
						/ Tile.TILEHEIGHT + 1);

		for (int y = yStart; y < yEnd; y++) {
			for (int x = xStart; x < xEnd; x++) {
				getCollideTile(x, y).render(
						g,
						(int) (x * Tile.TILEWIDTH - handler.getCamera()
								.getxOffset()),
						(int) (y * Tile.TILEHEIGHT - handler.getCamera()
								.getyOffset()));
			}
		}
	}

	public void renderForeground(Graphics g) {
		int xStart = (int) Math.max(0, handler.getCamera().getxOffset()
				/ Tile.TILEWIDTH);
		int xEnd = (int) Math.min(width,
				(handler.getCamera().getxOffset() + Main.WIDTH)
						/ Tile.TILEWIDTH + 1);
		int yStart = (int) Math.max(0, handler.getCamera().getyOffset()
				/ Tile.TILEHEIGHT);
		int yEnd = (int) Math.min(height,
				(handler.getCamera().getyOffset() + Main.HEIGHT)
						/ Tile.TILEHEIGHT + 1);

		for (int y = yStart; y < yEnd; y++) {
			for (int x = xStart; x < xEnd; x++) {
				getForegroundTile(x, y).render(
						g,
						(int) (x * Tile.TILEWIDTH - handler.getCamera()
								.getxOffset()),
						(int) (y * Tile.TILEHEIGHT - handler.getCamera()
								.getyOffset()));
			}
		}
	}

	public Tile getTile(int x, int y) {
		if (x < 0 || y < 0 || x >= width || y >= height) {
			return Tile.airTile;
		}

		Tile t = Tile.tiles[backgroundTile[x][y]];
		if (t == null) {
			return Tile.airTile;
		}
		return t;
	}

	public Tile getCollideTile(int x, int y) {
		if (x < 0 || y < 0 || x >= width || y >= height) {
			return Tile.airTile;
		}

		Tile t = Tile.tiles[collideTile[x][y]];
		if (t == null) {
			return Tile.airTile;
		}
		return t;
	}

	public Tile getForegroundTile(int x, int y) {
		if (x < 0 || y < 0 || x >= width || y >= height) {
			return Tile.airTile;
		}

		Tile t = Tile.tiles[foregroundTile[x][y]];
		if (t == null) {
			return Tile.airTile;
		}
		return t;
	}

	private void loadWorld(String path) {
		String file = Utils.loadFileAsString(path);
		String[] tokens = file.split("\\s+");
		width = Utils.parseInt(tokens[0]);
		height = Utils.parseInt(tokens[1]);

		backgroundTile = new int[width][height];
		collideTile = new int[width][height];
		foregroundTile = new int[width][height];
		for (int y = 0; y < height; y++) {
			for (int x = 0; x < width; x++) {
				backgroundTile[x][y] = Utils.parseInt(tokens[(x + y * width) + 2]);
				collideTile[x][y] = Utils.parseInt(tokens[(x + y) * 2]);
				foregroundTile[x][y] = Utils.parseInt(tokens[4]);
			}
		}
	}
	
	public int getWidth() {
		return width;
	}
	
	public int getHeight() {
		return height;
	}

}

Are you drawing just the tiles that can be seen on the screen, or the whole map?

Looks like it’s just what’s visible, going by the x/yStart and End variables.

@The OP: What are you using for graphics? Java2D? Also, if Tile.render() is something of your own, maybe you could post the code for that.

Tile.render():

public void render(Graphics g, int x, int y){
		g.drawImage(texture, x, y, TILEWIDTH, TILEHEIGHT, null);
	}

Using Swing…

IMO need to change to using a good gfx lib such as LibGDX for your tile rendering.

Swing is perfectly valid, just not generally the library of choice.

Rendering as much as you can to a single bufferedimage beforehand might give you a slight performance boost.