2D Tile Map + Camera

Hey guys, first post here. I felt like learning something new today and landed on game development which lead me here. So far I have been able to create a canvas on which to draw on, except key input and move a character around the screen. Pretty awesome so far. Anyway, I am now at the point where I need to create a map. I plan on loading a small image of the map, looking at the color of each pixel on that, and then determining which texture to place in that location/array based on that color.

I am trying to make an RTS style game, so the way my map needs to work is the map will be drawn out in the space, and I’m thinking I will need a Camera class that I can click and drag around so I don’t have to move all the objects manually. Upon searching I didn’t manage to come up with anything that seemed to be what I need, however I could have missed something.

If I could get a little nudge in the right direction that would be great :slight_smile:

Create an object that extends the rectangle class to make life easier, when the player moves move the rectangle as well(int the opposite direction). I personally have a small area the player can move in without moving the map, but if he goes to the edge of it the map will start to move. Then when it comes to drawing stuff to the screen just add the x cord of what your trying to draw and that of the map together. I know it sounds bad to move the entire world around the player and not the other way round but its not actually as bad as you would think. :slight_smile:
e.g.


     public void paint(Graphics g){
       player.drawEntity(g2d);
     }

	public void drawEntity(Graphics2D g2d){
		g2d.drawImage(image, getScreenX(), getScreenY(), null);
	}

	public int getScreenX(){
		return new Integer(getX() + Map.getX()); // map being my object that inherits from the rectangle class
	}
	
	public int getScreenY(){
		return new Integer(getY() + Map.getY());
	}

This is good as when you playing around with stuff like player, power ups, baddies all their x,y cords are relative to the map, so a cords of (300,300) could draw a player on the screen at (50, 50). So you could just set player spawn in code using local cords
e.g. player.setSpawn(10, 10); // spawn player top left of map

Thanks for the reply, that should be very helpful!

Here is sorta my structure so far, I am trying to create my map first and then I will worry about getting its positioning with a camera developed. So far, my main Game class(where my loop is) has an update method which controls logic for the game, and a render class which then renders all graphics, using the render methods in each class that I deem worthy of needing to control rendering. So my Game executes the render method in the Level class, and the level is made up of a 2d array of Tile objects. So far a tile just has an ID which the Level’s render method will determine which texture to draw for that tile’s location.

I’m usually a backend guy so I’m not really well versed in graphics drawing. Is this how I should set up drawing the map? Do I draw it on my Camera object that extends rectangle? Should my level class take care of drawing tiles, or should each tile render itself? I’m thinking it would be more efficient for the Level to render a tile, only needing to load the texture file 1 time, cutting it up, and then deciding which to draw based on the tile id.

EDIT: I have the map class done the way I described above and it seems to work, however its constantly using 25% of my 3rd CPU core as well as 150MB of memory, even though I’m not moving anything at all. I assume this will be an issue once things actually start to animate. My Texture image as well as the minimap that the map is draw from(which should be discarded after the array is made) is about 7KB. Turning off the rendering uses 0 CPU and 35MB memory. So maybe I have a leak somewhere?

Heres my map class:

package com.warmongerstudios.RTS;

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.IOException;

public class Level {
	public Tile[][] tiles;
	private BufferedImage[] mapTextures;
	public final int tileSize;
	
	
	public Level(String map, String textures){
		this.tileSize = 64;
		loadMap(map, textures);
	}
	
	public void buildLevelArray(BufferedImage mini){
		int w = mini.getWidth();
		int h = mini.getHeight();
		tiles = new Tile[w][h];
		
		
		for(int i=0; i<w;i++){
			for(int j=0; j<h;j++){
				int rgb = mini.getRGB(i, j);
				
				switch(rgb){
					case 0xFF000000:
						tiles[i][j] = new Tile(0);
						break;
					case 0xFFFFFFFF:
						tiles[i][j] = new Tile(1);
						break;
				}
			}
		}
	}
	
	public void cutTextureSheet(BufferedImage textures){
		int y = textures.getHeight() / this.tileSize;
		mapTextures = new BufferedImage[y];
		
		for(int i=0; i<y;i++){
			this.mapTextures[i] = textures.getSubimage(0, i*this.tileSize, this.tileSize, this.tileSize);
		}
	}
	
	@SuppressWarnings("all")
	private void loadMap(String minimap, String textures){
		BufferedImageLoader loader = new BufferedImageLoader();
		BufferedImage bi1 = null;
		BufferedImage bi2 = null;
		try {
			bi1 = loader.loadImage(minimap);
			bi2 = loader.loadImage(textures);
		} catch (IOException e) {
			//Do Nothing
		}
		
		buildLevelArray(bi1);
		cutTextureSheet(bi2);
	}
	
	public void render(Graphics g){
		int w = tiles.length;
		int h = tiles[0].length;
		
		for(int i=0; i<w;i++){
			for(int j=0; j<h;j++){
				g.drawImage(mapTextures[tiles[i][j].getType()], j*this.tileSize, i*this.tileSize, null);
			}
		}
	}
}

Drawing the map pixel by pixel is probably not the most efficient way to render your map. I would either draw the image once if you are using it as a background, or create tiles of larger size (eg 16x16) which you render individually.