Camera/Movement Starting Point

I hate being that guy starting a thread that’s been started a million times, but none of the threads seem to have very good answers.

Anyway, I’m looking for some sort of learning materials, so I can understand and implement the camera/movement systems needed for a side scrolling game. I’m using slick2D, though, for general purpose learning, I guess it doesn’t have to be slick2D material (Not that I could find any, regardless).

The biggest thing is that I’m not using tiles. That seems to be where the search attempts fail. If I ever do find examples or tutorials, it’s for tile based games.

Any references would be greatly appreciated. Thanks!

Welp. Turns out it wasn’t as hard as I thought. I found a simple Camera class for use with TileMaps, and modified it to work with a background image instead. Here it is for anyone that wants to use it:

import org.newdawn.slick.GameContainer;
import org.newdawn.slick.Image;

public class Camera 
{
	// Image to draw
	protected Image bg;

	// Position of the camera
	protected float camX, camY;

	// Width and height of image
	protected float bgWidth, bgHeight;

	// Game container to get screen width/height
	protected GameContainer gc;

	/**
	 * Create new Camera
	 * 
	 * @param gc the game container
	 * @param bg the background image
	 */
	public Camera(GameContainer gc, Image bg)
	{
		this.bg = bg;

		bgWidth =  bg.getWidth();
		bgHeight = bg.getHeight();

		camX = camY = 0;

		this.gc = gc;
	}

	/**
	 * Centers on the x, y coordinate given. If the camera comes to
	 * an edge of the image, the camera stops
	 * 
	 * @param x x position to center on
	 * @param y y position to center on
	 */
	public void centerOn(float x, float y)
	{
		camX = x - gc.getWidth()  / 2;
		camY = y - gc.getHeight() / 2;

		if(camX < 0) 
			camX = 0;
		if(camX + gc.getWidth() > bgWidth) 
			camX = bgWidth - gc.getWidth();

		if(camY < 0) 
			camY = 0;
		if(camY + gc.getHeight() > bgHeight) 
			camY = bgHeight - gc.getHeight();
	}
	
	/**
	 * Centers on the x coordinate given. Use so the camera
	 * only accounts for horizontal movement
	 * 
	 * @param x x position to center on
	 */
	public void centerOnX(float x)
	{
		camX = x - gc.getWidth()  / 2;

		if(camX < 0) 
			camX = 0;
		if(camX + gc.getWidth() > bgWidth) 
			camX = bgWidth - gc.getWidth();

	}
	
	/**
	 * Centers on the y coordinate given. Use so the camera
	 * only accounts for vertical movement
	 * 
	 * @param y y position to center on
	 */
	public void centerOnY(float y)
	{
		camY = y - gc.getHeight() / 2;

		if(camY < 0) 
			camY = 0;
		if(camY + gc.getHeight() > bgHeight) 
			camY = bgHeight - gc.getHeight();
	}
	
	/**
	 * Draw the background
	 */
	public void draw()
	{
		this.draw(camX, camY);
	}
	
	/**
	 * Draw the background using an offset separate of the camera
	 * 
	 * @param offsetX x offset to use
	 * @param offsetY y offset to use
	 */
	public void draw(float offsetX, float offsetY)
	{
		gc.getGraphics().drawImage(bg, 0, 0, offsetX, offsetY, 
				offsetX + gc.getWidth(), offsetY + gc.getHeight());
	}
	
	/**
	 * Translates all graphics relative to the camera
	 */
	public void translateGraphics()
	{
		gc.getGraphics().translate(-camX, -camY);
	}
	
	/**
	 * Undoes translateGraphics(). Use before drawing anything
	 * that is independent of camera position, like HUD's.
	 */
	public void untranslateGraphics()
	{
		gc.getGraphics().translate(camX, camY);
	}
}

An example of using it in the render() method:

Camera cam;
Image bg;
Image player;
float px, py;   // Player coordinates

public void init(GameContainer gc)
{
    bg = new Image("Image path");
    player = new Image("Image path");
    cam = new Camera(gc, bg);

    px = py = 0;
}

public void render(GameContainer gc, Graphics g)
{
    cam.centerOn(x, py);
    cam.draw();
    cam.translateGraphics();

    g.drawImage(player, x, y);
}

public void update(GameContainer gc, int delta)
{
    // Move player and stuff
}