I can't quite figure out how to render my entities and map...

Hey,

I’ve been having a bit of trouble figuring out how to use a camera to move around my map and render the player and other entities onto the map with working zooming.

If someone has some tips, suggestions, or sees a way to do this properly with my current code that would be appreciated.

Rendering the map:

package valkryst.area.map;

import java.awt.Graphics;
import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

import valkryst.area.Area;
import valkryst.area.map.tile.GrassTile;
import valkryst.area.map.tile.VoidTile;
import valkryst.core.Camera;

/**
 * This class adds the map to the pixel array that will be rendered onto the screen.
 * 
 * @author Valkryst
 * --- Last Edit 24-Oct-2013
 */
public class RenderMap {
	public static String[] map;
	private static int currentMapID = -1;
	
	private static VoidTile voidTile = new VoidTile();
	private static GrassTile grassTile = new GrassTile();
	
	/**
	 * Renders the map to the canvas.
	 * @param g The graphics object to use to render things to the canvas with.
	 * @param area The area that the player is currently in.
	 * @param p The player.
	 * @param width The width of the canvas.
	 * @param height The height of the canvas.
	 */
	public void render(final Graphics g, final Area area, final Camera c, final int width, final int height, final int scaleMultiplier) {
		int areaID = area.getMapID();
		if(areaID != currentMapID || currentMapID == -1) {
			loadMapFromFile(areaID);
			currentMapID = areaID;
		}
		
		int xOffset = c.getOriginX() >> 5; // The x-axis tile coordinate of where the cameras origin is currently.
		int yOffset = c.getOriginY() >> 5; // The y-axis tile coordinate of where the cameras origin is currently.
		int numberOfXTiles = (width >> 5); // Takes whatever the width of the canvas is, divides it by 32 and then that's then number of XTiles to draw.
		int numberOfYTiles = (height >> 5); // Takes whatever the height of the canvas is, divides it by 32 and then that's then number of YTiles to draw.
		
		if(width > 0 && height > 0) { // If there is no room on the screen to render the map then don't bother rendering it.
			for(int y = 0 + yOffset; y < yOffset + numberOfYTiles + 2; y++) {
				for(int x = 0 + xOffset; x < xOffset + numberOfXTiles + 2; x++) {
					try {
						switch(map[y].charAt(x)) {
							case 'A': {
								g.drawImage(grassTile.getTileImage(), (x - xOffset) * scaleMultiplier, (y - yOffset) * scaleMultiplier, scaleMultiplier, scaleMultiplier, null);
								break;
							}
							default: {
								g.drawImage(voidTile.getTileImage(), (x - xOffset) * scaleMultiplier, (y - yOffset) * scaleMultiplier, scaleMultiplier, scaleMultiplier, null);
							} 
						}
					} catch(Exception e) {
						continue;
					}
				}
			}
		}
	}
	
	public void loadMapFromFile(final int mapID) {
		List<String> loadedMap = new ArrayList<String>();
		
		InputStream is = this.getClass().getClassLoader().getResourceAsStream("Areas/Area" + mapID + ".txt");
		try {
			BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(is));
	        String line = null;
	        while ((line = bufferedReader.readLine()) != null) {
	            loadedMap.add(line);
	        }
	        bufferedReader.close();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		map = loadedMap.toArray(new String[loadedMap.size()]);
		System.out.println("Sucessfully finished loading Areas/Area" + mapID + ".txt");
	}
}

The Camera:

package valkryst.core;

import valkryst.area.Area;
import valkryst.core.graphics.Frame;

public class Camera {
	private int mapSizeInPixels;
	/** The origin for the are that the camera is currently viewing. */
	private int originX = 0, originY = 0;
	/** The start and end bounds of the map. */
	private int start = 0, end;
	
	public Camera(final Area currentAreaIn) {
		mapSizeInPixels = currentAreaIn.getMapSize() * (32 * Frame.scale);
		end = mapSizeInPixels;
	}
	
	/**
	 * Moves the camera's origin.
	 * @param x The value to add to the originX variable.
	 * @param y The value to add to the originY variable.
	 */
	public void moveOrigin(int x, int y) {
		originX += x;
		originY += y;
		
		checkBounds();
	}
	
	public void checkBounds() {
		// Checks if the originX is below 0, if it is then set it to 0.
		if(originX < start) {
			originX = start;
		}
		
		// Checks if the originY is below 0, if it is then set it to 0.
		if(originY < start) {
			originY = start;
		}
	}
	
	/**
	 * Sets the bounds of the map.
	 * @param currentArea The area to create bounds for.
	 */
	public void changeBounds(final Area currentAreaIn) {
		mapSizeInPixels = currentAreaIn.getMapSize() * (32 * Frame.scale);
		end = mapSizeInPixels;
	}
	
	///////////////////////////////////////// Get methods here: ////////////////////////////////////////////////////
	
	 /**
     * Returns the originX variable of the camera.
     * @return Returns the originX variable of the camera.
     */
	public int getOriginX() {
		return originX;
	}
	
	/**
     * Returns the originY variable of the camera.
     * @return Returns the originY variable of the camera.
     */
	public int getOriginY() {
		return originY;
	}
}

The Player:

package valkryst.entity;

import java.awt.Graphics;
import java.awt.event.KeyEvent;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import valkryst.area.Area;
import valkryst.core.Camera;
import valkryst.core.graphics.Frame;
import valkryst.enums.BattleDecision;
import valkryst.enums.CombatType;

/**
 * This class defines a player object.
 * 
 * @author Valkryst
 * --- Last Edit 24-Oct-2013
 */
public class Player extends Entity {
    private BattleDecision battleDecision = null;
    
    /**
     * The constructor for the player object.
     * @param nameIn The name of the player being constructed.
     * @param playerLevelIn The level of the player being constructed.
     * @param playerMaxLevelIn The maximum level of the player being constructed.
     * @param combatTypeIn The combat type of the player being constructed.
     */
    public Player(final String nameIn, final int playerLevelIn, final int playerMaxLevelIn, final CombatType combatTypeIn) {
		setName(nameIn);
		setUsesArmor(true);
		setUsesWeapon(true);
		setLevel(playerLevelIn);
		setMaxLevel(playerMaxLevelIn);
		setExperience(0);
		double health = (playerLevelIn * 25.0);
		setHealth(health);
		setMaxHealth(health);
	
		
		switch (combatTypeIn) {
        	case MELEE:
        	    setEnergy(100.0);
        	    setMaxEnergy(100.0);
        	    setUsesEnergy(true);
        	    break;
        	case RANGED:
        	    setEnergy(100.0);
        	    setMaxEnergy(100.0);
        	    setUsesEnergy(true);
        	    break;
        	case CASTER:
        	    setMana(100.0);
        	    setMaxMana(100.0);
        	    setUsesMana(true);
        	    break;
        	default: {
        		final Logger LOGGER = LoggerFactory.getLogger(Player.class);
        		LOGGER.info("Unsupported type of CombatType: " + combatTypeIn);
        	}
		}
		
		setBaseDamage(3.5 * getLevel());
		setArmorPoints(0.0);
		setup(true);
    }

    /**
     * Updates the player in preparation to be rendered.
     */
    public void updateLogic(final Area currentArea, final Camera camera) {
    	// Checks whether the player entity is visible on the screen or not.
    	if(xCoord + sprite.getSpriteImage(0).getWidth(null) < camera.getOriginX() && yCoord + sprite.getSpriteImage(0).getHeight(null) < camera.getOriginY()) {
    		isVisible = false;
    	} else if (!isVisible){
    		isVisible = true;
    	}
    	
    	// Moves + or - one pixel and + or - 1/32 of a tile for every pixel moved.
    	if(Frame.KEYBOARD_INPUT.isKeyPressed(KeyEvent.VK_UP)) {
			move(0, -1, 0, -0.03125);
			camera.moveOrigin(0, -1);
		}
		if(Frame.KEYBOARD_INPUT.isKeyPressed(KeyEvent.VK_DOWN)) {
			move(0, 1, 0, 0.03125);
			camera.moveOrigin(0, 1);
		}
		if(Frame.KEYBOARD_INPUT.isKeyPressed(KeyEvent.VK_LEFT)) {
			move(-1, 0, -0.03125, 0);
			camera.moveOrigin(-1, 0);
		}
		if(Frame.KEYBOARD_INPUT.isKeyPressed(KeyEvent.VK_RIGHT)) {
			move(1, 0, 0.03125, 0);
			camera.moveOrigin(1, 0);
		}
		
		// Checks if the player entity is off of bounds and if it is then move it back onto the map.
		if(xCoord < 0 || tileX < 0) {
			xCoord = 0;
			tileX = 0;
		}
		
		if(yCoord < 0 || tileY < 0) {
			yCoord = 0;
			tileY = 0;
		}
		
		int mapSize = currentArea.getMapSize();
		int scale = (32 * Frame.scale);
		int mapSizeInPixels = (mapSize * scale);
		
		if(xCoord > mapSizeInPixels || tileX > mapSize) {
			System.out.println("Test1");
			xCoord = mapSizeInPixels;
			tileX = mapSize-1;
		}
		
		if(yCoord > mapSizeInPixels || tileY > mapSize) {
			System.out.println("Test2");
			yCoord = mapSizeInPixels;
			tileY = mapSize - 1;
		}
    }
    
    /**
     * Renders the player to the screen.
     */
    public void render(final Graphics g, final int scaleMultiplier) {
    	if(isVisible) {
    		g.drawImage(getSprite().getSpriteImage(0), xCoord, yCoord, scaleMultiplier, scaleMultiplier , null);
    	}
    }
    
    ///////////////////////////////////////// Get methods here: ////////////////////////////////////////////////////
    public BattleDecision getBattleDecision() {
    	return battleDecision;
    }

    ///////////////////////////////////////// Set methods here: ////////////////////////////////////////////////////
    public void setMyBattleDecision(final BattleDecision b) {
    	battleDecision = b;
    }
}

The Creature:

package valkryst.entity;

import java.util.Random;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import valkryst.enums.CombatType;
import valkryst.systems.Drops;
import valkryst.systems.battle.AITactics;

/**
 * This class defines a creature object.
 * 
 * @author Valkryst
 * --- Last Edit 24-Oct-2013
 */
public class Creature extends Entity {
	public final AITactics TACTICS = new AITactics();
	/** The id of the creature. */
	final int CREATURE_ID;
	/** The drop table of the creature. */
	private Drops drops;
	/** Whether the creature has been looted or not. If the creature has been looted then it can be removed from the area it's on. */
	private boolean hasBeenLooted = false;

	/**
	 * The constructor method for the Creature object.
	 * @param creatureIdIn The ID of the creature being created.
	 * @param nameIn The name of the creature being created.
	 * @param creatureLevelIn The level of the creature being created.
	 * @param creatureMaxLevelIn The maximum level of the creature being created.
	 * @param combatTypeIn The combat type of the creature being created.
	 */
    public Creature(final int creatureIdIn, final String nameIn, final int creatureLevelIn, final int creatureMaxLevelIn, final CombatType combatTypeIn) {
    	CREATURE_ID = creatureIdIn; // Set the creature's ID.
        setName(nameIn);// Set the creature's name.

        int level = -1;
        while(level <= 0) { // Prevents the creature's level from being 0 or below.
        	// Generates a random integer that is within playerLevel-3 and playerLevel+3.
        	level = (creatureLevelIn - 3) + (int) (Math.random() * (((creatureLevelIn + 3) - (creatureLevelIn - 3)) + 1));
        }
        setLevel(level);
        setMaxLevel(creatureMaxLevelIn);
        setExperience(0);

        // Figure out the creature's health.
        final Random RANDOM = new Random();
        double health = 0;
        while(health <= 0 || health == -1) { 
        	health = (level * 25.0) + RANDOM.nextInt((level * 10) + 1);
        }
        setHealth(health);
        setMaxHealth(health);
        
        // Figure out the creature's aggressiveness. REWORK LATER ON
        if(level >= creatureLevelIn) { 
        	setAggressiveness(Math.random() + (level - creatureLevelIn)/100); // Tested multiple times and has never gone to 1.0 or above. Do extensive testing if it ever does tho.
        } else if(getAggressiveness() == -1) { 
        	setAggressiveness(Math.random()); 
        }
        
        // Set the creature's energy/mana depending on it's combatType.
        switch (combatTypeIn) {
            case MELEE: {
                setEnergy(100.0);
                setMaxEnergy(100.0);
                setUsesEnergy(true);
                break;
            }
            case RANGED: {
                setEnergy(100.0);
                setMaxEnergy(100.0);
                setUsesEnergy(true);
                break;
            }
            case CASTER: {
                setMana(100.0);
                setMaxMana(100.0);
                setUsesMana(true);
                break;
            }
            default: {
        		final Logger LOGGER = LoggerFactory.getLogger(Creature.class);
        		LOGGER.info("Unsupported type of CombatType: " + combatTypeIn);
        	}
        }

        setBaseDamage(2.5 * level); // Set the creature's base damage.
        setArmorPoints(0.0); // Set the armor points of the creature.
        setup(false);
    }
    
    public void createDropTable(final int[] dropTable, final double[] dropChance) {
    	drops.createDropTable(dropTable, dropChance);
    }

    /**
     * Updates the creature in preparation to be rendered.
     */
    public void updateLogic() {
    }
    
    /**
     * Renders the player to the screen.
     */
    public void render() {
    	
    }
    
    ///////////////////////////////////////// Set methods here: ////////////////////////////////////////////////////
    
    /**
     * Sets whether the creature has been looted or not.
     * @param b The variable to set the hasBeenLooted variable to.
     */
    public void setHasBeenLooted(boolean b) {
    	hasBeenLooted = b;
    }
    
    ///////////////////////////////////////// Get methods here: ////////////////////////////////////////////////////
    
    /**
     * Returns the drop variable of the creature.
     * @return Returns the drop variable of the creature.
     */
    public Drops getDrops() {
    	return drops;
    }
    
    /**
     * Returns whether the creature has been looted or not.
     * @return Returns whether the creature has been looted or not.
     */
    public boolean getHasBeenLooted() {
    	return hasBeenLooted;
    }
}

The Game Loop:

package valkryst.core.graphics;

import java.awt.Canvas;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.image.BufferStrategy;

import javax.swing.SwingUtilities;

import valkryst.area.Area;
import valkryst.area.map.RenderMap;
import valkryst.core.Camera;
import valkryst.entity.Player;
import valkryst.enums.CombatType;
import valkryst.spell.Cast;


/**
 * @author Valkryst
 * --- Last Edit 24-Oct-2013
 */
public class Screen extends Canvas implements Runnable{
	private static final long serialVersionUID = 4532836895892068039L;
	
	private Thread gameThread;
	private boolean isGameRunning = false;
	
	private int WIDTH = Frame.WIDTH, HEIGHT = Frame.HEIGHT, SCALE = Frame.scale;
	
	private BufferStrategy BS = getBufferStrategy();
	private Area currentArea = new Area(0, 10, "TestArea"); // area shouldn't be created here.
	int lastFrameScale = 0, scaleMultiplier = (32 * Frame.scale);
	
	
	private RenderMap renderMap = new RenderMap();
	private Camera camera;
	
	public Screen() {   
		setPreferredSize(new Dimension(WIDTH * SCALE, HEIGHT * SCALE));
		setFocusable(true);
		setVisible(true);
	}

	public void run() {
		long lastLoopTime = System.nanoTime();
	    final int TARGET_FPS = 60;
		final long OPTIMAL_TIME = 1000000000 / TARGET_FPS;   
		double delta = 0;
		
		// Keep looping until the game ends.
		while (isGameRunning) {
			long now = System.nanoTime();
			long updateLength = now - lastLoopTime;
			lastLoopTime = now;
		    delta += updateLength / ((double)OPTIMAL_TIME); // Work out how long its been since the last update. This will be used to calculate how far the entities should move this loop.
		    
		    //Update the game's logic and then render the screen.
		    while(delta >= 1) {
		    	updateLogic(delta);
		    	delta--;
		    }
		    
		    render();
		      
		    // we want each frame to take 10 milliseconds, to do this
		    // we've recorded when we started the frame. We add 10 milliseconds
		    // to this and then factor in the current time to give 
		    // us our final value to wait for
		    // remember this is in ms, whereas our lastLoopTime etc. vars are in ns.
		    try {
		    	long tempLong = (lastLoopTime-System.nanoTime() + OPTIMAL_TIME)/1000000;
		    	if(tempLong <= 0) { continue; } // Skips the sleep()
				Thread.sleep(tempLong);
			} catch (InterruptedException e) {
				continue;
			}
		}
		stop();
	}
	
	public synchronized void start() {
		// TEMPORARY
		currentArea.addPlayerToArea(new Player("Test", 1, (short)60, CombatType.CASTER));
		// END OF TEMPORARY
		
		camera = new Camera(currentArea);
		
		setBackground(Color.black);
		isGameRunning = true;
		gameThread = new Thread(this, "Display");
		gameThread.start();
	}

	public synchronized void stop() {
		try {
			gameThread.join();
		} catch(InterruptedException e) {
			e.printStackTrace();
		}
	}

	// When called this updates all of the game's logic.
	public void updateLogic(double delta) {
		Cast.setCurrentTime();
		currentArea.pruneCreatures(); // Removes all creatures that have been looted from the area.
		currentArea.updateLogic(camera);
	}

	// When called this updates the screen.
	public void render() {
		// If Frame.scale has changed then re-size all tile images.
		if(Frame.scale != lastFrameScale) {
			scaleMultiplier = (32 * Frame.scale);
		}
		lastFrameScale = Frame.scale;
				
		// Forces the canvas to use triple buffering.
		BS = getBufferStrategy();
        if (BS == null) {
        	SwingUtilities.invokeLater(new Runnable() {
        	    public void run() {
        	        createBufferStrategy(3);
        	    }
        	});
        	return;
        }
		
        // Creates the graphics object and then clears the screen.
        Graphics g = BS.getDrawGraphics();
        g.clearRect(0, 0, getWidth(), getHeight());
        renderMap.render(g, currentArea, camera, getWidth(), getHeight(), scaleMultiplier);
		currentArea.render(g, scaleMultiplier);
        g.dispose();
		BS.show();
	}
}

Thanks for any replies!

Well, in Java2D I would recommend creating a rectangle that is the same size of the viewport, and every time the camera position changes, check through all the tiles and see if they are intersecting rectangle, if they are, render them.

Wouldn’t that require me to create rectangles for every single tile and test for intersection every time?


Google, please.

I’ve already googled it. If you look at my code it works.

What I can’t do is render the map using the camera and then have the outside of the map and then somehow render onto the map when they’re in view.

You need to calculate the left-top corner of the screen and add width and height:

Camera = [left_top_x, left_top_y, left_top_x + width, left_top_y + height];

Draw only tiles on screen:
i dont know how you have your map, but if it is something like this:
0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0
0,0,0,0,0,0,0,0,0,0

you can loop each tile and calculate x and y position. if position is on screen you can draw.

int y = 0;
for (int line : map) {
    int x = 0;
    for (int tile : line) {
        if (x >= camera[0] && y >= camera[1] && x <= camera[2] && y <= camera[3] {
            g.draw(tiles[tile], x, y, zoom_x, zoom_y, null);
            x += tiles_size_width;
        }
    }
    y += tiles_size_height;

Use the same method with player, enemies, objects etc.
Calculate first your “camera” position (i calculate mine with left-top corner and add width and height) and check if everything is on screen to draw.
To use zoom, g.draw(image, x , y, ZOOM x, ZOOM y, null).
I don’t see much difference with performance scaling this before draw. Just do it for everything you need to draw.

This is pseudo-code. Sorry for my english.
If you need more help show me your map file.

This is what my map file looks like:

AAAAAAAAAA
AAAAAAAAAA
AAAAAAAAAA
AAAAAAAAAA
AAAAAAAAAA
AAAAAAAAAA
AAAAAAAAAA
AAAAAAAAAA
AAAAAAAAAA
AAAAAAAAAA

It must always have the same width and height, I’ll probably change that limitation eventually.

I’ve managed to figure out your example, mostly. I’m not sure how the for loops you wrote so I changed them to what I thought would work but the rest was fairly easy to integrate with my camera. The code I currently have is:

int mapSize = area.getMapSize(); // Size of map, in tiles.

		int y = 0;
		for (int i = 0; i < mapSize;i++) {
		    int x = 0;
		    for (int j = 0; j < mapSize;j++) {
		        if (x >= c.getOriginX() && y >= c.getOriginY() && x <= c.getEndX() && y <= c.getEndY()) {
		        	switch(map[y].charAt(x)) {
						case 'A': {
							g.drawImage(grassTile.getTileImage(), x, y, scale, scale, null);
							break;
						}
						default: {
							g.drawImage(voidTile.getTileImage(), x, y, scale, scale, null);
						} 
						
		            	x += (scale * 32);
		        	}
		        }
		        y += (scale * 32);
		    }
		}

This doesn’t currently display anything to the screen. It’s just black.

For the camera I’m doing:

/** The origin for the are that the camera is currently viewing. */
	private int originX = 0, originY = 0;
	/** The start and end bounds of the map. */
	private int endX = 0, endY = 0;
	
	public Camera(final int widthIn, final int heightIn) { // Width and Height of the canvas.
		endX = originX + widthIn;
		endY = originY + heightIn;
	}
String[] list = new String[] {A,A,A,A,A};

for (String s : list) System.out.println(s);

for (int i = 0; i < list.size(); i++) System.out.println(list.get(i));

/*
console output:
     A
     A
     A
     A
     A
*/

They have the same output. The first loop is just more readable (for me) and use less lines of code.
s parse your list and temporary store each value (in this case, A).

“This doesn’t currently display anything to the screen. It’s just black.”
Make sure your x and y are in camera range. I will check your code (first post) soon and give some feedback.

Ah, the for loop makes more sense now, but I don’t see how it’ll work with a one dimensional array. My map is in a String[] array.

I’ve managed to get the map to display properly, but when I move the camera it disappears.

int y = 0;
		for (int i = 0; i < mapSize;i++) {
		    int x = 0;
		    for (int j = 0; j < mapSize;j++) {
		        if (x >= c.getOriginX() && y >= c.getOriginY() && x <= c.getEndX() && y <= c.getEndY()) {
		        	try {
						switch(map[i].charAt(j)) {
							case 'A': {
								g.drawImage(grassTile.getTileImage(), x, y, scale, scale, null);
								break;
							}
							default: {
								g.drawImage(voidTile.getTileImage(), x, y, scale, scale, null);
							} 
						}
					} catch(Exception e) {
						continue;
					}
		            x += 32;
		        }
		    }
		    y += 32;
		}

Edit:
There may be a bug in one of my other classes causing this issue, I’m looking into it now.

Edit 2:
The bug is mostly fixed. The map works if you only move along the Y-axis, but if you move along the X-axis the map will disappear after you move one tile to the right.

The current camera code is:

package valkryst.core;

/**
 * This class defines a Camera object.
 * 
 * @author Valkryst
 * --- Last Edit 30-Oct-2013
 */
public class Camera {
	/** The map size in pixels. */
	private int mapSizeInPixels = -1;
	private int widthOfScreen = -1, heightOfScreen = -1;
	/** The origin for the are that the camera is currently viewing. */
	private int originX = 0, originY = 0;
	/** The start and end bounds of the map. */
	private int endX = 0, endY = 0;
	
	public Camera(final int widthIn, final int heightIn, final int mapSizeInPixelsIn, final int widthOfScreenIn, final int heightOfScreenIn) { // Width and height of canvas
		mapSizeInPixels = mapSizeInPixelsIn;
		endX = originX + widthIn;
		endY = originY + heightIn;
		widthOfScreen = widthOfScreenIn;
		heightOfScreen = heightOfScreenIn;
	}
	
	/**
	 * Moves the camera's origin.
	 * @param x The value to add to the originX variable.
	 * @param y The value to add to the originY variable.
	 */
	public void moveOrigin(int x, int y) {
		originX += x;
		originY += y;
		
		checkBounds();
		System.out.println(originX + " " + originY);
	}
	
	public void checkBounds() {
		// Checks if the originX is below 0, if it is then set it to 0.
		if(originX < 0) {
			originX = 0;
		}
		
		// Checks if the originY is below 0, if it is then set it to 0.
		if(originY < mapSizeInPixels) {
			originY = 0;
		}
				
		// Checks if the originX is nearing the end of the screen on the x-axis, if it is then set it to the map size in pixels minus the screen width.
		if(originX > ((originX + widthOfScreen) - mapSizeInPixels)) {
			originX = mapSizeInPixels - widthOfScreen;
		}
		
		// Checks if the originY is nearing the end of the screen on the y-axis, if it is then set it to the map size in pixels minus the screen height.
		if(originY > ((originY + heightOfScreen) - mapSizeInPixels)) {
			originY = mapSizeInPixels - heightOfScreen;
		}
	}
	
	public void updateCamera(final int widthIn, final int heightIn, final int mapSizeInPixelsIn, final int widthOfScreenIn, final int heightOfScreenIn) {
		mapSizeInPixels = mapSizeInPixelsIn;
		endX = originX + widthIn;
		endY = originY + heightIn;
		widthOfScreen = widthOfScreenIn;
		heightOfScreen = heightOfScreenIn;
	}
	
	///////////////////////////////////////// Get methods here: ////////////////////////////////////////////////////
	
	 /**
     * Returns the originX variable of the camera.
     * @return Returns the originX variable of the camera.
     */
	public int getOriginX() {
		return originX;
	}
	
	/**
     * Returns the originY variable of the camera.
     * @return Returns the originY variable of the camera.
     */
	public int getOriginY() {
		return originY;
	}
	
	/**
     * Returns the endX variable of the camera.
     * @return Returns the endX variable of the camera.
     */
	public int getEndX() {
		return endX;
	}
	
	/**
     * Returns the endY variable of the camera.
     * @return Returns the endY variable of the camera.
     */
	public int getEndY() {
		return endY;
	}
}

The current rendering code is:


int mapSize = area.getMapSize(); // Size of map, in tiles.

		int y = 0;
		for (int i = 0; i < mapSize;i++) {
		    int x = 0;
		    for (int j = 0; j < mapSize;j++) {
		        if (x >= c.getOriginX() && y >= c.getOriginY() && x <= c.getEndX() && y <= c.getEndY()) {
		        	try {
						switch(map[i].charAt(j)) {
							case 'A': {
								g.drawImage(grassTile.getTileImage(), x, y, scale, scale, null);
								break;
							}
							default: {
								g.drawImage(voidTile.getTileImage(), x, y, scale, scale, null);
							} 
						}
					} catch(Exception e) {
						continue;
					}
		            x += 32;
		        }
		    }
		    y += 32;
		}

I think the map disappears because this conditions is false:

if (x >= c.getOriginX() && y >= c.getOriginY() && x <= c.getEndX() && y <= c.getEndY()) {
                 try {
                  switch(map[i].charAt(j)) {
                     case 'A': {
                        g.drawImage(grassTile.getTileImage(), x, y, scale, scale, null);
                        break;
                     }
                     default: {
                        g.drawImage(voidTile.getTileImage(), x, y, scale, scale, null);
                     } 
                  }
               } catch(Exception e) {
                  continue;
               }
                  x += 32;
              }

Add this in the second line and give me feedback:

if (x >= c.getOriginX() && y >= c.getOriginY() && x <= c.getEndX() && y <= c.getEndY()) {
System.out.println("CONDITION IS TRUE");

(...)

After you move right, it should not print CONDITION IS TRUE.

Also, in the last lines, try to switch down x += 32:

               } catch(Exception e) {
                  continue;
               }
                 // NOT HERE
              }

               // HERE
               x += 32;

          }
          y += 32;
      

It always returns true.

int mapSize = area.getMapSize(); // Size of map, in tiles.

		int y = 0;
		for (int i = 0; i < mapSize;i++) {
		    int x = 0;
		    for (int j = 0; j < mapSize;j++) {
		        if (x >= c.getOriginX() && y >= c.getOriginY() && x <= c.getEndX() && y <= c.getEndY()) {
		        	System.out.println("true");
		        	try {
						switch(map[i].charAt(j)) {
							case 'A': {
								g.drawImage(grassTile.getTileImage(), x, y, scale, scale, null);
								break;
							}
							default: {
								g.drawImage(voidTile.getTileImage(), x, y, scale, scale, null);
							} 
						}
					} catch(Exception e) {
						continue;
					}
		        }
		        x += 32;
		    }
		    y += 32;
		}

The map now works, but whenever the player moves onto a new tile, the row or column (depends if the player moves up, down, left, or right) behind the player disappears.

Are you changing your origin by too much so that it is clear off to the right or something?

The origin changes by -1 or +1. From the printouts it’s working as intended, so I don’t see that causing anything.